diff --git a/src/HPWH.hh b/src/HPWH.hh index 6d7e0437..ccdae473 100644 --- a/src/HPWH.hh +++ b/src/HPWH.hh @@ -10,1320 +10,1494 @@ #include #include -#include //for exit +#include //for exit #include -namespace Btwxt { class RegularGridInterpolator; }; +namespace Btwxt +{ +class RegularGridInterpolator; +}; -//#define HPWH_ABRIDGED +// #define HPWH_ABRIDGED /**< If HPWH_ABRIDGED is defined, then some function definitions will be * excluded from compiling. This is done in order to reduce the size of the * final compiled code. */ #include "HPWHversion.hh" -class HPWH { -public: - static const int version_major = HPWHVRSN_MAJOR; - static const int version_minor = HPWHVRSN_MINOR; - static const int version_patch = HPWHVRSN_PATCH; - static const std::string version_maint; // Initialized in source file (HPWH.cc) - - static const float DENSITYWATER_kgperL; - static const float KWATER_WpermC; - static const float CPWATER_kJperkgC; - static const int CONDENSITY_SIZE = 12; /** SANCO2 5-23 - MODELS_SANCO2_43 = 120, /**< SANCO2 43 gallon CO2 external heat pump */ - MODELS_SANCO2_83 = 121, /**< SANCO2 83 gallon CO2 external heat pump */ - MODELS_SANCO2_GS3_45HPA_US_SP = 122, /**< SANCO2 80 gallon CO2 external heat pump used for MF */ - MODELS_SANCO2_119 = 123, /**< SANCO2 120 gallon CO2 external heat pump */ - - // Sanden synomyms for backward compatability - // allow unmodified code using HPWHsim to build - MODELS_Sanden40 = MODELS_SANCO2_43, - MODELS_Sanden80 = MODELS_SANCO2_83, - MODELS_Sanden_GS3_45HPA_US_SP = MODELS_SANCO2_GS3_45HPA_US_SP, - MODELS_Sanden120 = MODELS_SANCO2_119, - - // The new-ish Rheem - MODELS_RheemHB50 = 140, /**< Rheem 2014 (?) Model */ - MODELS_RheemHBDR2250 = 141, /**< 50 gallon, 2250 W resistance Rheem HB Duct Ready */ - MODELS_RheemHBDR4550 = 142, /**< 50 gallon, 4500 W resistance Rheem HB Duct Ready */ - MODELS_RheemHBDR2265 = 143, /**< 65 gallon, 2250 W resistance Rheem HB Duct Ready */ - MODELS_RheemHBDR4565 = 144, /**< 65 gallon, 4500 W resistance Rheem HB Duct Ready */ - MODELS_RheemHBDR2280 = 145, /**< 80 gallon, 2250 W resistance Rheem HB Duct Ready */ - MODELS_RheemHBDR4580 = 146, /**< 80 gallon, 4500 W resistance Rheem HB Duct Ready */ - - // The new new Rheem - MODELS_Rheem2020Prem40 = 151, /**< 40 gallon, Rheem 2020 Premium */ - MODELS_Rheem2020Prem50 = 152, /**< 50 gallon, Rheem 2020 Premium */ - MODELS_Rheem2020Prem65 = 153, /**< 65 gallon, Rheem 2020 Premium */ - MODELS_Rheem2020Prem80 = 154, /**< 80 gallon, Rheem 2020 Premium */ - MODELS_Rheem2020Build40 = 155, /**< 40 gallon, Rheem 2020 Builder */ - MODELS_Rheem2020Build50 = 156, /**< 50 gallon, Rheem 2020 Builder */ - MODELS_Rheem2020Build65 = 157, /**< 65 gallon, Rheem 2020 Builder */ - MODELS_Rheem2020Build80 = 158, /**< 80 gallon, Rheem 2020 Builder */ - - // Rheem 120V dedicated-circuit product, no resistance elements - MODELS_RheemPlugInDedicated40 = 1160, /**< 40 gallon, Rheem 120V dedicated-circuit */ - MODELS_RheemPlugInDedicated50 = 1161, /**< 50 gallon, Rheem 120V dedicated-circuit */ - - // Rheem 120V shared-circuit products, no resistance elements. - MODELS_RheemPlugInShared40 = 1150, /**< 40 gallon, Rheem 120V shared-circuit */ - MODELS_RheemPlugInShared50 = 1151, /**< 50 gallon, Rheem 120V shared-circuit */ - MODELS_RheemPlugInShared65 = 1152, /**< 65 gallon, Rheem 120V shared-circuit */ - MODELS_RheemPlugInShared80 = 1153, /**< 80 gallon, Rheem 120V shared-circuit */ - - // The new-ish Stiebel - MODELS_Stiebel220E = 160, /**< Stiebel Eltron (2014 model?) */ - - // Generic water heaters, corresponding to the tiers 1, 2, and 3 - MODELS_Generic1 = 170, /**< Generic Tier 1 */ - MODELS_Generic2 = 171, /**< Generic Tier 2 */ - MODELS_Generic3 = 172, /**< Generic Tier 3 */ - MODELS_UEF2generic = 173, /**< UEF 2.0, modified GE2014STDMode case */ - MODELS_genericCustomUEF = 174, /**< used for creating "generic" model with custom uef*/ - - MODELS_AWHSTier3Generic40 = 175, /**< Generic AWHS Tier 3 50 gallons*/ - MODELS_AWHSTier3Generic50 = 176, /**< Generic AWHS Tier 3 50 gallons*/ - MODELS_AWHSTier3Generic65 = 177, /**< Generic AWHS Tier 3 65 gallons*/ - MODELS_AWHSTier3Generic80 = 178, /**< Generic AWHS Tier 3 80 gallons*/ - - MODELS_StorageTank = 180, /**< Generic Tank without heaters */ - MODELS_TamScalable_SP = 190, /** < HPWH input passed off a poor preforming SP model that has scalable input capacity and COP */ - MODELS_Scalable_MP = 191, /** < Lower performance MP model that has scalable input capacity and COP */ - - // Non-preset models - MODELS_CustomFile = 200, /**< HPWH parameters were input via file */ - MODELS_CustomResTank = 201, /**< HPWH parameters were input via HPWHinit_resTank */ - MODELS_CustomResTankGeneric = 202, /**< HPWH parameters were input via HPWHinit_commercialResTank */ - - // Larger Colmac models in single pass configuration - MODELS_ColmacCxV_5_SP = 210, /**< Colmac CxA_5 external heat pump in Single Pass Mode */ - MODELS_ColmacCxA_10_SP = 211, /**< Colmac CxA_10 external heat pump in Single Pass Mode */ - MODELS_ColmacCxA_15_SP = 212, /**< Colmac CxA_15 external heat pump in Single Pass Mode */ - MODELS_ColmacCxA_20_SP = 213, /**< Colmac CxA_20 external heat pump in Single Pass Mode */ - MODELS_ColmacCxA_25_SP = 214, /**< Colmac CxA_25 external heat pump in Single Pass Mode */ - MODELS_ColmacCxA_30_SP = 215, /**< Colmac CxA_30 external heat pump in Single Pass Mode */ - - // Larger Colmac models in multi pass configuration - MODELS_ColmacCxV_5_MP = 310, /**< Colmac CxA_5 external heat pump in Multi Pass Mode */ - MODELS_ColmacCxA_10_MP = 311, /**< Colmac CxA_10 external heat pump in Multi Pass Mode */ - MODELS_ColmacCxA_15_MP = 312, /**< Colmac CxA_15 external heat pump in Multi Pass Mode */ - MODELS_ColmacCxA_20_MP = 313, /**< Colmac CxA_20 external heat pump in Multi Pass Mode */ - MODELS_ColmacCxA_25_MP = 314, /**< Colmac CxA_25 external heat pump in Multi Pass Mode */ - MODELS_ColmacCxA_30_MP = 315, /**< Colmac CxA_30 external heat pump in Multi Pass Mode */ - - // Larger Nyle models in single pass configuration - MODELS_NyleC25A_SP = 230, /*< Nyle C25A external heat pump in Single Pass Mode */ - MODELS_NyleC60A_SP = 231, /*< Nyle C60A external heat pump in Single Pass Mode */ - MODELS_NyleC90A_SP = 232, /*< Nyle C90A external heat pump in Single Pass Mode */ - MODELS_NyleC125A_SP = 233, /*< Nyle C125A external heat pump in Single Pass Mode */ - MODELS_NyleC185A_SP = 234, /*< Nyle C185A external heat pump in Single Pass Mode */ - MODELS_NyleC250A_SP = 235, /*< Nyle C250A external heat pump in Single Pass Mode */ - // Larger Nyle models with the cold weather package! - MODELS_NyleC60A_C_SP = 241, /*< Nyle C60A external heat pump in Single Pass Mode */ - MODELS_NyleC90A_C_SP = 242, /*< Nyle C90A external heat pump in Single Pass Mode */ - MODELS_NyleC125A_C_SP = 243, /*< Nyle C125A external heat pump in Single Pass Mode */ - MODELS_NyleC185A_C_SP = 244, /*< Nyle C185A external heat pump in Single Pass Mode */ - MODELS_NyleC250A_C_SP = 245, /*< Nyle C250A external heat pump in Single Pass Mode */ - - // Mitsubishi Electric Trane - MODELS_MITSUBISHI_QAHV_N136TAU_HPB_SP = 250, /*< Mitsubishi Electric Trane QAHV external CO2 heat pump */ - - // Larger Nyle models in multi pass configuration - //MODELS_NyleC25A_MP = 330, /*< Nyle C25A external heat pump in Multi Pass Mode */ - MODELS_NyleC60A_MP = 331, /*< Nyle C60A external heat pump in Multi Pass Mode */ - MODELS_NyleC90A_MP = 332, /*< Nyle C90A external heat pump in Multi Pass Mode */ - MODELS_NyleC125A_MP = 333, /*< Nyle C125A external heat pump in Multi Pass Mode */ - MODELS_NyleC185A_MP = 334, /*< Nyle C185A external heat pump in Multi Pass Mode */ - MODELS_NyleC250A_MP = 335, /*< Nyle C250A external heat pump in Multi Pass Mode */ - - MODELS_NyleC60A_C_MP = 341, /*< Nyle C60A external heat pump in Multi Pass Mode */ - MODELS_NyleC90A_C_MP = 342, /*< Nyle C90A external heat pump in Multi Pass Mode */ - MODELS_NyleC125A_C_MP = 343, /*< Nyle C125A external heat pump in Multi Pass Mode */ - MODELS_NyleC185A_C_MP = 344, /*< Nyle C185A external heat pump in Multi Pass Mode */ - MODELS_NyleC250A_C_MP = 345, /*< Nyle C250A external heat pump in Multi Pass Mode */ - - // Large Rheem multi pass models - MODELS_RHEEM_HPHD60HNU_201_MP = 350, - MODELS_RHEEM_HPHD60VNU_201_MP = 351, - MODELS_RHEEM_HPHD135HNU_483_MP = 352, // really bad fit to data due to inconsistency in data - MODELS_RHEEM_HPHD135VNU_483_MP = 353, // really bad fit to data due to inconsistency in data - - MODELS_AquaThermAire = 400 // heat exchanger model - }; - - ///specifies the modes for writing output - ///the specified values are used for >= comparisons, so the numerical order is relevant - enum VERBOSITY { - VRB_silent = 0, /**< print no outputs */ - VRB_reluctant = 10, /**< print only outputs for fatal errors */ - VRB_minuteOut = 15, /**< print minutely output */ - VRB_typical = 20, /**< print some basic debugging info */ - VRB_emetic = 30 /**< print all the things */ - }; - - - enum UNITS{ - UNITS_C, /**< celsius */ - UNITS_F, /**< fahrenheit */ - UNITS_KWH, /**< kilowatt hours */ - UNITS_BTU, /**< british thermal units */ - UNITS_KJ, /**< kilojoules */ - UNITS_KW, /**< kilowatt */ - UNITS_BTUperHr, /**< british thermal units per Hour */ - UNITS_GAL, /**< gallons */ - UNITS_L, /**< liters */ - UNITS_kJperHrC, /**< UA, metric units */ - UNITS_BTUperHrF, /**< UA, imperial units */ - UNITS_FT, /**< feet */ - UNITS_M, /**< meters */ - UNITS_FT2, /**< square feet */ - UNITS_M2, /**< square meters */ - UNITS_MIN, /**< minutes */ - UNITS_SEC, /**< seconds */ - UNITS_HR, /**< hours */ - UNITS_GPM, /**< gallons per minute */ - UNITS_LPS /**< liters per second */ - }; - - /** specifies the type of heat source */ - enum HEATSOURCE_TYPE { - TYPE_none, /**< a default to check to make sure it's been set */ - TYPE_resistance, /**< a resistance element */ - TYPE_compressor /**< a vapor cycle compressor */ - }; - - /** specifies the extrapolation method based on Tair, from the perfmap for a heat source */ - enum EXTRAP_METHOD { - EXTRAP_LINEAR, /**< the default extrapolates linearly */ - EXTRAP_NEAREST /**< extrapolates using nearest neighbor, will just continue from closest point */ - }; - - /** specifies the unit type for outputs in the CSV file-s */ - enum CSVOPTIONS { - CSVOPT_NONE = 0, - CSVOPT_IPUNITS = 1 << 0, - CSVOPT_IS_DRAWING = 1 << 1 - }; - - struct NodeWeight { - int nodeNum; - double weight; - NodeWeight(int n,double w): nodeNum(n),weight(w) {}; - - NodeWeight(int n): nodeNum(n),weight(1.0) {}; - }; - - struct HeatingLogic { - public: - std::string description; - std::function compare; - - HeatingLogic(std::string desc,double decisionPoint_in,HPWH *hpwh_in, - std::function c,bool isHTS): - description(desc),decisionPoint(decisionPoint_in),hpwh(hpwh_in),compare(c), - isEnteringWaterHighTempShutoff(isHTS) - {}; - - /**< checks that the input is all valid. */ - virtual const bool isValid() = 0; - /**< gets the value for comparing the tank value to, i.e. the target SoC */ - virtual const double getComparisonValue() = 0; - /**< gets the calculated value from the tank, i.e. SoC or tank average of node weights*/ - virtual const double getTankValue() = 0; - /**< function to calculate where the average node for a logic set is. */ - virtual const double nodeWeightAvgFract() = 0; - /**< gets the fraction of a node that has to be heated up to met the turnoff condition*/ - virtual const double getFractToMeetComparisonExternal() = 0; - - virtual int setDecisionPoint(double value) = 0; - double getDecisionPoint() { return decisionPoint; } - bool getIsEnteringWaterHighTempShutoff() { return isEnteringWaterHighTempShutoff; } - - protected: - double decisionPoint; - HPWH* hpwh; - bool isEnteringWaterHighTempShutoff; - }; - - struct SoCBasedHeatingLogic: HeatingLogic { - public: - SoCBasedHeatingLogic(std::string desc,double decisionPoint,HPWH *hpwh, - double hF = -0.05,double tM_C = 43.333,bool constMains = false,double mains_C = 18.333, - std::function c = std::less()): - HeatingLogic(desc,decisionPoint,hpwh,c,false), - hysteresisFraction(hF),tempMinUseful_C(tM_C), - useCostantMains(constMains),constantMains_C(mains_C) - {}; - const bool isValid(); - - const double getComparisonValue(); - const double getTankValue(); - const double nodeWeightAvgFract(); - const double getFractToMeetComparisonExternal(); - const double getMainsT_C(); - const double getTempMinUseful_C(); - int setDecisionPoint(double value); - int setConstantMainsTemperature(double mains_C); - - private: - double tempMinUseful_C; - double hysteresisFraction; - bool useCostantMains; - double constantMains_C; - }; - - struct TempBasedHeatingLogic: HeatingLogic { - public: - TempBasedHeatingLogic(std::string desc,std::vector n, - double decisionPoint,HPWH *hpwh,bool a = false, - std::function c = std::less(), - bool isHTS = false): - HeatingLogic(desc,decisionPoint,hpwh,c,isHTS), - nodeWeights(n),isAbsolute(a) - {}; - - const bool isValid(); - - const double getComparisonValue(); - const double getTankValue(); - const double nodeWeightAvgFract(); - const double getFractToMeetComparisonExternal(); - - int setDecisionPoint(double value); - int setDecisionPoint(double value,bool absolute); - - private: - const bool areNodeWeightsValid(); - - bool isAbsolute; - std::vector nodeWeights; - }; - - std::shared_ptr shutOffSoC(std::string desc,double targetSoC,double hystFract,double tempMinUseful_C, - bool constMains,double mains_C); - std::shared_ptr turnOnSoC(std::string desc,double targetSoC,double hystFract,double tempMinUseful_C, - bool constMains,double mains_C); - - std::shared_ptr wholeTank(double decisionPoint,const UNITS units = UNITS_C, const bool absolute = false); - std::shared_ptr topThird(double decisionPoint); - std::shared_ptr topThird_absolute(double decisionPoint); - std::shared_ptr secondThird(double decisionPoint,const UNITS units = UNITS_C, const bool absolute = false); - std::shared_ptr bottomThird(double decisionPoint); - std::shared_ptr bottomHalf(double decisionPoint) ; - std::shared_ptr bottomTwelfth(double decisionPoint); - std::shared_ptr bottomSixth(double decisionPoint); - std::shared_ptr bottomSixth_absolute(double decisionPoint); - std::shared_ptr secondSixth(double decisionPoint); - std::shared_ptr thirdSixth(double decisionPoint); - std::shared_ptr fourthSixth(double decisionPoint); - std::shared_ptr fifthSixth(double decisionPoint); - std::shared_ptr topSixth(double decisionPoint); - - std::shared_ptr standby(double decisionPoint); - std::shared_ptr topNodeMaxTemp(double decisionPoint); - std::shared_ptr bottomNodeMaxTemp(double decisionPoint,bool isEnteringWaterHighTempShutoff = false); - std::shared_ptr bottomTwelfthMaxTemp(double decisionPoint); - std::shared_ptr topThirdMaxTemp(double decisionPoint); - std::shared_ptr bottomSixthMaxTemp(double decisionPoint); - std::shared_ptr secondSixthMaxTemp(double decisionPoint); - std::shared_ptr fifthSixthMaxTemp(double decisionPoint); - std::shared_ptr topSixthMaxTemp(double decisionPoint); - - std::shared_ptr largeDraw(double decisionPoint); - std::shared_ptr largerDraw(double decisionPoint); - - ///this is the value that the public functions will return in case of a simulation - ///destroying error - static const int HPWH_ABORT = -274000; - - static std::string getVersion(); - /**< This function returns a string with the current version number */ - - int HPWHinit_presets(MODELS presetNum); - /**< This function will reset all member variables to defaults and then - * load in a set of parameters that are hardcoded in this function - - * which particular set of parameters is selected by presetNum. - * This is similar to the way the HPWHsim currently operates, as used in SEEM, - * but not quite as versatile. - * My impression is that this could be a useful input paradigm for CSE - * - * The return value is 0 for successful initialization, HPWH_ABORT otherwise - */ - - int HPWHinit_file(std::string configFile); - /**< This function will load in a set of parameters from a file - * The file name is the input - there should be at most one set of parameters per file - * This is useful for testing new variations, and for the sort of variability - * that we typically do when creating SEEM runs - * Appropriate use of this function can be found in the documentation - - * The return value is 0 for successful initialization, HPWH_ABORT otherwise - */ - - int HPWHinit_resTank(); /**< Default resistance tank, EF 0.95, volume 47.5 */ - int HPWHinit_resTank(double tankVol_L,double energyFactor,double upperPower_W,double lowerPower_W); - /**< This function will initialize a HPWH object to be a resistance tank. Since - * resistance tanks are so simple, they can be specified with only four variables: - * tank volume, energy factor, and the power of the upper and lower elements. Energy - * factor is converted into UA internally, although an external setter for UA is - * also provided in case the energy factor is unknown. - * - * Several assumptions regarding the tank configuration are assumed: the lower element - * is at the bottom, the upper element is at the top third. The logics are also set - * to standard setting, with upper as VIP activating when the top third is too cold. - */ - - int HPWHinit_resTankGeneric(double tankVol_L,double rValue_M2KperW,double upperPower_W,double lowerPower_W); - /**< This function will initialize a HPWH object to be a generic resistance storage water heater, - * with a specific R-Value defined at initalization. - * - * Several assumptions regarding the tank configuration are assumed: the lower element - * is at the bottom, the upper element is at the top third. The controls are the same standard controls for - * the HPWHinit_resTank() - */ - - int HPWHinit_genericHPWH(double tankVol_L,double energyFactor,double resUse_C); - /**< This function will initialize a HPWH object to be a non-specific HPWH model - * with an energy factor as specified. Since energy - * factor is not strongly correlated with energy use, most settings - * are taken from the GE2015_STDMode model. - */ - - int runOneStep(double drawVolume_L,double ambientT_C, - double externalT_C,DRMODES DRstatus,double inletVol2_L = 0.,double inletT2_C = 0., - std::vector* extraHeatDist_W = NULL); - /**< This function will progress the simulation forward in time by one step - * all calculated outputs are stored in private variables and accessed through functions - * - * The return value is 0 for successful simulation run, HPWH_ABORT otherwise - */ - - /** An overloaded function that uses takes inletT_C */ - int runOneStep(double inletT_C,double drawVolume_L,double ambientT_C, - double externalT_C,DRMODES DRstatus,double inletVol2_L = 0.,double inletT2_C = 0., - std::vector* extraHeatDist_W = NULL) { - setInletT(inletT_C); - return runOneStep(drawVolume_L,ambientT_C, - externalT_C,DRstatus,inletVol2_L,inletT2_C, - extraHeatDist_W); - }; - - - int runNSteps(int N,double *inletT_C,double *drawVolume_L, - double *tankAmbientT_C,double *heatSourceAmbientT_C, - DRMODES *DRstatus); - /**< This function will progress the simulation forward in time by N (equal) steps - * The calculated values will be summed or averaged, as appropriate, and - * then stored in the usual variables to be accessed through functions - * - * The return value is 0 for successful simulation run, HPWH_ABORT otherwise - */ - - /** Setters for the what are typically input variables */ - void setInletT(double newInletT_C) { member_inletT_C = newInletT_C; }; - void setMinutesPerStep(double newMinutesPerStep); - - void setVerbosity(VERBOSITY hpwhVrb); - /**< sets the verbosity to the specified level */ - void setMessageCallback(void (*callbackFunc)(const std::string message,void* pContext),void* pContext); - /**< sets the function to be used for message passing */ - void printHeatSourceInfo(); - /**< this prints out the heat source info, nicely formatted - specifically input/output energy/power, and runtime - will print to cout if messageCallback pointer is unspecified - does not use verbosity, as it is public and expected to be called only when needed */ - void printTankTemps(); - /**< this prints out all the node temps, kind of nicely formatted - does not use verbosity, as it is public and expected to be called only when needed */ - - int WriteCSVHeading(FILE* outFILE,const char* preamble = "",int nTCouples = 6,int options = CSVOPT_NONE) const; - int WriteCSVRow(FILE* outFILE,const char* preamble = "",int nTCouples = 6,int options = CSVOPT_NONE) const; - /**< a couple of function to write the outputs to a file - they both will return 0 for success - the preamble should be supplied with a trailing comma, as these functions do - not add one. Additionally, a newline is written with each call. */ - - /**< Sets the tank node temps based on the provided vector of temps, which are mapped onto the - existing nodes, regardless of numNodes. */ - int setTankLayerTemperatures(std::vector setTemps, const UNITS units = UNITS_C); - void getTankTemps(std::vector &tankTemps); - - bool isSetpointFixed() const; /**< is the setpoint allowed to be changed */ - int setSetpoint(double newSetpoint,UNITS units = UNITS_C);/** 0 minutes and < 1440 minutes. */ - double getTimerLimitTOT_minute() const; - /**< Returns the timer limit in minutes for the DR_TOT call. */ - - int getInletHeight(int whichInlet) const; - /**< returns the water inlet height node number */ - - /**< resizes the tankTemp_C and nextTankTemp_C node vectors */ - void setNumNodes(const std::size_t num_nodes); - - /**< returns the number of nodes */ - int getNumNodes() const; - - /**< returns the index of the top node */ - int getIndexTopNode() const; - - double getTankNodeTemp(int nodeNum,UNITS units = UNITS_C) const; - /**< returns the temperature of the water at the specified node - with specified units - or HPWH_ABORT for incorrect node number or unit failure */ - - double getNthSimTcouple(int iTCouple,int nTCouple,UNITS units = UNITS_C) const; - /**< returns the temperature from a set number of virtual "thermocouples" specified by nTCouple, - which are constructed from the node temperature array. Specify iTCouple from 1-nTCouple, - 1 at the bottom using specified units - returns HPWH_ABORT for iTCouple < 0, > nTCouple, or incorrect units */ - - int getNumHeatSources() const; - /**< returns the number of heat sources */ - - int getNumResistanceElements() const; - /**< returns the number of resistance elements */ - - int getCompressorIndex() const; - /**< returns the index of the compressor in the heat source array. - Note only supports HPWHs with one compressor, if multiple will return the last index - of a compressor */ - - double getCompressorCapacity(double airTemp = 19.722,double inletTemp = 14.444,double outTemp = 57.222, - UNITS pwrUnit = UNITS_KW,UNITS tempUnit = UNITS_C); - /**< Returns the heating output capacity of the compressor for the current HPWH model. - Note only supports HPWHs with one compressor, if multiple will return the last index - of a compressor. Outlet temperatures greater than the max allowable setpoints will return an error, but - for compressors with a fixed setpoint the */ - - int setCompressorOutputCapacity(double newCapacity,double airTemp = 19.722,double inletTemp = 14.444,double outTemp = 57.222, - UNITS pwrUnit = UNITS_KW,UNITS tempUnit = UNITS_C); - /**< Sets the heating output capacity of the compressor at the defined air, inlet water, and outlet temperatures. - For multi-pass models the capacity is set as the average between the inletTemp and outTemp since multi-pass models will increase - the water temperature only a few degrees at a time (i.e. maybe 10 degF) until the tank reaches the outTemp, the capacity at - inletTemp might not be accurate for the entire heating cycle. - Note only supports HPWHs with one compressor, if multiple will return the last index - of a compressor */ - - int setScaleHPWHCapacityCOP(double scaleCapacity = 1.,double scaleCOP = 1.); - /**< Scales the heatpump water heater input capacity and COP*/ - - int setResistanceCapacity(double power,int which = -1,UNITS pwrUNIT = UNITS_KW); - /**< Scale the resistance elements in the heat source list. Which heat source is chosen is changes is given by "which" - - If which (-1) sets all the resisistance elements in the tank. - - If which (0, 1, 2...) sets the resistance element in a low to high order. - So if there are 3 elements 0 is the bottom, 1 is the middle, and 2 is the top element, regardless of their order - in heatSources. If the elements exist on at the same node then all of the elements are set. - - The only valid values for which are between -1 and getNumResistanceElements()-1. Since which is defined as the - by the ordered height of the resistance elements it cannot refer to a compressor. - */ - - double getResistanceCapacity(int which = -1,UNITS pwrUNIT = UNITS_KW); - /**< Returns the resistance elements capacity. Which heat source is chosen is changes is given by "which" - - If which (-1) gets all the resisistance elements in the tank. - - If which (0, 1, 2...) sets the resistance element in a low to high order. - So if there are 3 elements 0 is the bottom, 1 is the middle, and 2 is the top element, regardless of their order - in heatSources. If the elements exist on at the same node then all of the elements are set. - - The only valid values for which are between -1 and getNumResistanceElements()-1. Since which is defined as the - by the ordered height of the resistance elements it cannot refer to a compressor. - */ - - int getResistancePosition(int elementIndex) const; - - double getNthHeatSourceEnergyInput(int N,UNITS units = UNITS_KWH) const; - /**< returns the energy input to the Nth heat source, with the specified units - energy used by the heat source is positive - should always be positive - returns HPWH_ABORT for N out of bounds or incorrect units */ - - double getNthHeatSourceEnergyOutput(int N,UNITS units = UNITS_KWH) const; - /**< returns the energy output from the Nth heat source, with the specified units - energy put into the water is positive - should always be positive - returns HPWH_ABORT for N out of bounds or incorrect units */ - - double getNthHeatSourceRunTime(int N) const; - /**< returns the run time for the Nth heat source, in minutes - note: they may sum to more than 1 time step for concurrently running heat sources - returns HPWH_ABORT for N out of bounds */ - int isNthHeatSourceRunning(int N) const; - /**< returns 1 if the Nth heat source is currently engaged, 0 if it is not, and - returns HPWH_ABORT for N out of bounds */ - HEATSOURCE_TYPE getNthHeatSourceType(int N) const; - /**< returns the enum value for what type of heat source the Nth heat source is */ - - - double getOutletTemp(UNITS units = UNITS_C) const; - /**< returns the outlet temperature in the specified units - returns 0 when no draw occurs, or HPWH_ABORT for incorrect unit specifier */ - double getCondenserWaterInletTemp(UNITS units = UNITS_C) const; - /**< returns the condenser inlet temperature in the specified units - returns 0 when no HP not running occurs, or HPWH_ABORT for incorrect unit specifier */ - - double getCondenserWaterOutletTemp(UNITS units = UNITS_C) const; - /**< returns the condenser outlet temperature in the specified units - returns 0 when no HP not running occurs, or HPWH_ABORT for incorrect unit specifier */ - - double getExternalVolumeHeated(UNITS units = UNITS_L) const; - /**< returns the volume of water heated in an external in the specified units - returns 0 when no external heat source is running */ - - double getEnergyRemovedFromEnvironment(UNITS units = UNITS_KWH) const; - /**< get the total energy removed from the environment by all heat sources in specified units - (not net energy - does not include standby) - moving heat from the space to the water is the positive direction - returns HPWH_ABORT for incorrect units */ - - double getStandbyLosses(UNITS units = UNITS_KWH) const; - /**< get the amount of heat lost through the tank in specified units - moving heat from the water to the space is the positive direction - negative should occur seldom - returns HPWH_ABORT for incorrect units */ - - double getTankHeatContent_kJ() const; - /**< get the heat content of the tank, relative to zero celsius - * returns using kilojoules */ - - int getHPWHModel() const; - /**< get the model number of the HPWHsim model number of the hpwh */ - - int getCompressorCoilConfig() const; - bool isCompressorMultipass() const; - bool isCompressoExternalMultipass() const; - - bool hasACompressor() const; - /**< Returns if the HPWH model has a compressor or not, could be a storage or resistance tank. */ - - bool hasExternalHeatSource() const; - /**< Returns if the HPWH model has any external heat sources or not, could be a compressor or resistance element. */ - double getExternalMPFlowRate(UNITS units = UNITS_GPM) const; - /**< Returns the constant flow rate for an external multipass heat sources. */ - - - double getCompressorMinRuntime(UNITS units = UNITS_MIN) const; - - int getSizingFractions(double &aquafract,double &percentUseable) const; - /**< returns the fraction of total tank volume from the bottom up where the aquastat is - or the turn on logic for the compressor, and the USEable fraction of storage or 1 minus - where the shut off logic is for the compressor. If the logic spans multiple nodes it - returns the weighted average of the nodes */ - - bool isHPWHScalable() const; - /**< returns if the HPWH is scalable or not*/ - - bool shouldDRLockOut(HEATSOURCE_TYPE hs,DRMODES DR_signal) const; - /**< Checks the demand response signal against the different heat source types */ - - void resetTopOffTimer(); - /**< resets variables for timer associated with the DR_TOT call */ - - double getLocationTemp_C() const; - int setMaxTempDepression(double maxDepression,UNITS units = UNITS_C); - - bool hasEnteringWaterHighTempShutOff(int heatSourceIndex); - int setEnteringWaterHighTempShutOff(double highTemp,bool tempIsAbsolute,int heatSourceIndex,UNITS units = UNITS_C); - /**< functions to check for and set specific high temperature shut off logics. - HPWHs can only have one of these, which is at least typical */ - - int setTargetSoCFraction(double target); - - bool canUseSoCControls(); - - int switchToSoCControls(double targetSoC,double hysteresisFraction = 0.05,double tempMinUseful = 43.333,bool constantMainsT = false, - double mainsT = 18.333,UNITS tempUnit = UNITS_C); - - bool isSoCControlled() const; - - /// Checks whether energy is balanced during a simulation step. - bool isEnergyBalanced(const double drawVol_L,const double prevHeatContent_kJ,const double fracEnergyTolerance = 0.001); - - /// Overloaded version of above that allows specification of inlet temperature. - bool isEnergyBalanced(const double drawVol_L,double inletT_C_in,const double prevHeatContent_kJ,const double fracEnergyTolerance) { - setInletT(inletT_C_in); - return isEnergyBalanced(drawVol_L,prevHeatContent_kJ,fracEnergyTolerance); - } - - /// Addition of heat from a normal heat sources; return excess heat, if needed, to prevent exceeding maximum or setpoint - double addHeatAboveNode(double qAdd_kJ,const int nodeNum,const double maxT_C); - - /// Addition of extra heat handled separately from normal heat sources - void addExtraHeatAboveNode(double qAdd_kJ,const int nodeNum); - -private: - class HeatSource; - - void setAllDefaults(); /**< sets all the defaults default */ - - void updateTankTemps(double draw,double inletT_C,double ambientT_C,double inletVol2_L,double inletT2_L); - void mixTankInversions(); - /**< Mixes the any temperature inversions in the tank after all the temperature calculations */ - void updateSoCIfNecessary(); - - bool areAllHeatSourcesOff() const; - /**< test if all the heat sources are off */ - void turnAllHeatSourcesOff(); - /**< disengage each heat source */ - - void addHeatParent(HeatSource *heatSourcePtr,double heatSourceAmbientT_C,double minutesToRun); - - /// adds extra heat to the set of nodes that are at the same temperature, above the - /// specified node number - void modifyHeatDistribution(std::vector &heatDistribution); - void addExtraHeat(std::vector &extraHeatDist_W); - - /// "extra" heat added during a simulation step - double extraEnergyInput_kWh; - - double tankAvg_C(const std::vector nodeWeights) const; - /**< functions to calculate what the temperature in a portion of the tank is */ - - void mixTankNodes(int mixedAboveNode,int mixedBelowNode,double mixFactor); - /**< function to average the nodes in a tank together bewtween the mixed abovenode and mixed below node. */ - - void calcDerivedValues(); - /**< a helper function for the inits, calculating condentropy and the lowest node */ - void calcSizeConstants(); - /**< a helper function to set constants for the UA and tank size*/ - void calcDerivedHeatingValues(); - /**< a helper for the helper, calculating condentropy and the lowest node*/ - void mapResRelativePosToHeatSources(); - /**< a helper function for the inits, creating a mapping function for the position of the resistance elements - to their indexes in heatSources. */ - - int checkInputs(); - /**< a helper function to run a few checks on the HPWH input parameters */ - - double getChargePerNode(double tCold,double tMix,double tHot) const; - - void calcAndSetSoCFraction(); - - void sayMessage(const std::string message) const; - /**< if the messagePriority is >= the hpwh verbosity, - either pass your message out to the callback function or print it to cout - otherwise do nothing */ - void msg(const char* fmt,...) const; - void msgV(const char* fmt,va_list ap=NULL) const; - - bool simHasFailed; - /**< did an internal error cause the simulation to fail? */ - - bool isHeating; - /**< is the hpwh currently heating or not? */ - - bool setpointFixed; - /**< does the HPWH allow the setpoint to vary */ - - bool tankSizeFixed; - /**< does the HPWH have a constant tank size or can it be changed */ - - bool canScale; - /**< can the HPWH scale capactiy and COP or not */ - - VERBOSITY hpwhVerbosity; - /**< an enum to let the sim know how much output to say */ - - void (*messageCallback)(const std::string message,void* contextPtr); - /**< function pointer to indicate an external message processing function */ - void* messageCallbackContextPtr; - /**< caller context pointer for external message processing */ - +class HPWH +{ + public: + static const int version_major = HPWHVRSN_MAJOR; + static const int version_minor = HPWHVRSN_MINOR; + static const int version_patch = HPWHVRSN_PATCH; + static const std::string version_maint; // Initialized in source file (HPWH.cc) + + static const float DENSITYWATER_kgperL; + static const float KWATER_WpermC; + static const float CPWATER_kJperkgC; + static const int CONDENSITY_SIZE = + 12; /** SANCO2 5-23 + MODELS_SANCO2_43 = 120, /**< SANCO2 43 gallon CO2 external heat pump */ + MODELS_SANCO2_83 = 121, /**< SANCO2 83 gallon CO2 external heat pump */ + MODELS_SANCO2_GS3_45HPA_US_SP = + 122, /**< SANCO2 80 gallon CO2 external heat pump used for MF */ + MODELS_SANCO2_119 = 123, /**< SANCO2 120 gallon CO2 external heat pump */ + + // Sanden synomyms for backward compatability + // allow unmodified code using HPWHsim to build + MODELS_Sanden40 = MODELS_SANCO2_43, + MODELS_Sanden80 = MODELS_SANCO2_83, + MODELS_Sanden_GS3_45HPA_US_SP = MODELS_SANCO2_GS3_45HPA_US_SP, + MODELS_Sanden120 = MODELS_SANCO2_119, + + // The new-ish Rheem + MODELS_RheemHB50 = 140, /**< Rheem 2014 (?) Model */ + MODELS_RheemHBDR2250 = 141, /**< 50 gallon, 2250 W resistance Rheem HB Duct Ready */ + MODELS_RheemHBDR4550 = 142, /**< 50 gallon, 4500 W resistance Rheem HB Duct Ready */ + MODELS_RheemHBDR2265 = 143, /**< 65 gallon, 2250 W resistance Rheem HB Duct Ready */ + MODELS_RheemHBDR4565 = 144, /**< 65 gallon, 4500 W resistance Rheem HB Duct Ready */ + MODELS_RheemHBDR2280 = 145, /**< 80 gallon, 2250 W resistance Rheem HB Duct Ready */ + MODELS_RheemHBDR4580 = 146, /**< 80 gallon, 4500 W resistance Rheem HB Duct Ready */ + + // The new new Rheem + MODELS_Rheem2020Prem40 = 151, /**< 40 gallon, Rheem 2020 Premium */ + MODELS_Rheem2020Prem50 = 152, /**< 50 gallon, Rheem 2020 Premium */ + MODELS_Rheem2020Prem65 = 153, /**< 65 gallon, Rheem 2020 Premium */ + MODELS_Rheem2020Prem80 = 154, /**< 80 gallon, Rheem 2020 Premium */ + MODELS_Rheem2020Build40 = 155, /**< 40 gallon, Rheem 2020 Builder */ + MODELS_Rheem2020Build50 = 156, /**< 50 gallon, Rheem 2020 Builder */ + MODELS_Rheem2020Build65 = 157, /**< 65 gallon, Rheem 2020 Builder */ + MODELS_Rheem2020Build80 = 158, /**< 80 gallon, Rheem 2020 Builder */ + + // Rheem 120V dedicated-circuit product, no resistance elements + MODELS_RheemPlugInDedicated40 = 1160, /**< 40 gallon, Rheem 120V dedicated-circuit */ + MODELS_RheemPlugInDedicated50 = 1161, /**< 50 gallon, Rheem 120V dedicated-circuit */ + + // Rheem 120V shared-circuit products, no resistance elements. + MODELS_RheemPlugInShared40 = 1150, /**< 40 gallon, Rheem 120V shared-circuit */ + MODELS_RheemPlugInShared50 = 1151, /**< 50 gallon, Rheem 120V shared-circuit */ + MODELS_RheemPlugInShared65 = 1152, /**< 65 gallon, Rheem 120V shared-circuit */ + MODELS_RheemPlugInShared80 = 1153, /**< 80 gallon, Rheem 120V shared-circuit */ + + // The new-ish Stiebel + MODELS_Stiebel220E = 160, /**< Stiebel Eltron (2014 model?) */ + + // Generic water heaters, corresponding to the tiers 1, 2, and 3 + MODELS_Generic1 = 170, /**< Generic Tier 1 */ + MODELS_Generic2 = 171, /**< Generic Tier 2 */ + MODELS_Generic3 = 172, /**< Generic Tier 3 */ + MODELS_UEF2generic = 173, /**< UEF 2.0, modified GE2014STDMode case */ + MODELS_genericCustomUEF = 174, /**< used for creating "generic" model with custom uef*/ + + MODELS_AWHSTier3Generic40 = 175, /**< Generic AWHS Tier 3 50 gallons*/ + MODELS_AWHSTier3Generic50 = 176, /**< Generic AWHS Tier 3 50 gallons*/ + MODELS_AWHSTier3Generic65 = 177, /**< Generic AWHS Tier 3 65 gallons*/ + MODELS_AWHSTier3Generic80 = 178, /**< Generic AWHS Tier 3 80 gallons*/ + + MODELS_StorageTank = 180, /**< Generic Tank without heaters */ + MODELS_TamScalable_SP = 190, /** < HPWH input passed off a poor preforming SP model that has + scalable input capacity and COP */ + MODELS_Scalable_MP = + 191, /** < Lower performance MP model that has scalable input capacity and COP */ + + // Non-preset models + MODELS_CustomFile = 200, /**< HPWH parameters were input via file */ + MODELS_CustomResTank = 201, /**< HPWH parameters were input via HPWHinit_resTank */ + MODELS_CustomResTankGeneric = + 202, /**< HPWH parameters were input via HPWHinit_commercialResTank */ + + // Larger Colmac models in single pass configuration + MODELS_ColmacCxV_5_SP = 210, /**< Colmac CxA_5 external heat pump in Single Pass Mode */ + MODELS_ColmacCxA_10_SP = 211, /**< Colmac CxA_10 external heat pump in Single Pass Mode */ + MODELS_ColmacCxA_15_SP = 212, /**< Colmac CxA_15 external heat pump in Single Pass Mode */ + MODELS_ColmacCxA_20_SP = 213, /**< Colmac CxA_20 external heat pump in Single Pass Mode */ + MODELS_ColmacCxA_25_SP = 214, /**< Colmac CxA_25 external heat pump in Single Pass Mode */ + MODELS_ColmacCxA_30_SP = 215, /**< Colmac CxA_30 external heat pump in Single Pass Mode */ + + // Larger Colmac models in multi pass configuration + MODELS_ColmacCxV_5_MP = 310, /**< Colmac CxA_5 external heat pump in Multi Pass Mode */ + MODELS_ColmacCxA_10_MP = 311, /**< Colmac CxA_10 external heat pump in Multi Pass Mode */ + MODELS_ColmacCxA_15_MP = 312, /**< Colmac CxA_15 external heat pump in Multi Pass Mode */ + MODELS_ColmacCxA_20_MP = 313, /**< Colmac CxA_20 external heat pump in Multi Pass Mode */ + MODELS_ColmacCxA_25_MP = 314, /**< Colmac CxA_25 external heat pump in Multi Pass Mode */ + MODELS_ColmacCxA_30_MP = 315, /**< Colmac CxA_30 external heat pump in Multi Pass Mode */ + + // Larger Nyle models in single pass configuration + MODELS_NyleC25A_SP = 230, /*< Nyle C25A external heat pump in Single Pass Mode */ + MODELS_NyleC60A_SP = 231, /*< Nyle C60A external heat pump in Single Pass Mode */ + MODELS_NyleC90A_SP = 232, /*< Nyle C90A external heat pump in Single Pass Mode */ + MODELS_NyleC125A_SP = 233, /*< Nyle C125A external heat pump in Single Pass Mode */ + MODELS_NyleC185A_SP = 234, /*< Nyle C185A external heat pump in Single Pass Mode */ + MODELS_NyleC250A_SP = 235, /*< Nyle C250A external heat pump in Single Pass Mode */ + // Larger Nyle models with the cold weather package! + MODELS_NyleC60A_C_SP = 241, /*< Nyle C60A external heat pump in Single Pass Mode */ + MODELS_NyleC90A_C_SP = 242, /*< Nyle C90A external heat pump in Single Pass Mode */ + MODELS_NyleC125A_C_SP = 243, /*< Nyle C125A external heat pump in Single Pass Mode */ + MODELS_NyleC185A_C_SP = 244, /*< Nyle C185A external heat pump in Single Pass Mode */ + MODELS_NyleC250A_C_SP = 245, /*< Nyle C250A external heat pump in Single Pass Mode */ + + // Mitsubishi Electric Trane + MODELS_MITSUBISHI_QAHV_N136TAU_HPB_SP = + 250, /*< Mitsubishi Electric Trane QAHV external CO2 heat pump */ + + // Larger Nyle models in multi pass configuration + // MODELS_NyleC25A_MP = 330, /*< Nyle C25A external heat pump in Multi Pass Mode */ + MODELS_NyleC60A_MP = 331, /*< Nyle C60A external heat pump in Multi Pass Mode */ + MODELS_NyleC90A_MP = 332, /*< Nyle C90A external heat pump in Multi Pass Mode */ + MODELS_NyleC125A_MP = 333, /*< Nyle C125A external heat pump in Multi Pass Mode */ + MODELS_NyleC185A_MP = 334, /*< Nyle C185A external heat pump in Multi Pass Mode */ + MODELS_NyleC250A_MP = 335, /*< Nyle C250A external heat pump in Multi Pass Mode */ + + MODELS_NyleC60A_C_MP = 341, /*< Nyle C60A external heat pump in Multi Pass Mode */ + MODELS_NyleC90A_C_MP = 342, /*< Nyle C90A external heat pump in Multi Pass Mode */ + MODELS_NyleC125A_C_MP = 343, /*< Nyle C125A external heat pump in Multi Pass Mode */ + MODELS_NyleC185A_C_MP = 344, /*< Nyle C185A external heat pump in Multi Pass Mode */ + MODELS_NyleC250A_C_MP = 345, /*< Nyle C250A external heat pump in Multi Pass Mode */ + + // Large Rheem multi pass models + MODELS_RHEEM_HPHD60HNU_201_MP = 350, + MODELS_RHEEM_HPHD60VNU_201_MP = 351, + MODELS_RHEEM_HPHD135HNU_483_MP = 352, // really bad fit to data due to inconsistency in data + MODELS_RHEEM_HPHD135VNU_483_MP = 353, // really bad fit to data due to inconsistency in data + + MODELS_AquaThermAire = 400 // heat exchanger model + }; + + /// specifies the modes for writing output + /// the specified values are used for >= comparisons, so the numerical order is relevant + enum VERBOSITY + { + VRB_silent = 0, /**< print no outputs */ + VRB_reluctant = 10, /**< print only outputs for fatal errors */ + VRB_minuteOut = 15, /**< print minutely output */ + VRB_typical = 20, /**< print some basic debugging info */ + VRB_emetic = 30 /**< print all the things */ + }; + + enum UNITS + { + UNITS_C, /**< celsius */ + UNITS_F, /**< fahrenheit */ + UNITS_KWH, /**< kilowatt hours */ + UNITS_BTU, /**< british thermal units */ + UNITS_KJ, /**< kilojoules */ + UNITS_KW, /**< kilowatt */ + UNITS_BTUperHr, /**< british thermal units per Hour */ + UNITS_GAL, /**< gallons */ + UNITS_L, /**< liters */ + UNITS_kJperHrC, /**< UA, metric units */ + UNITS_BTUperHrF, /**< UA, imperial units */ + UNITS_FT, /**< feet */ + UNITS_M, /**< meters */ + UNITS_FT2, /**< square feet */ + UNITS_M2, /**< square meters */ + UNITS_MIN, /**< minutes */ + UNITS_SEC, /**< seconds */ + UNITS_HR, /**< hours */ + UNITS_GPM, /**< gallons per minute */ + UNITS_LPS /**< liters per second */ + }; + + /** specifies the type of heat source */ + enum HEATSOURCE_TYPE + { + TYPE_none, /**< a default to check to make sure it's been set */ + TYPE_resistance, /**< a resistance element */ + TYPE_compressor /**< a vapor cycle compressor */ + }; + + /** specifies the extrapolation method based on Tair, from the perfmap for a heat source */ + enum EXTRAP_METHOD + { + EXTRAP_LINEAR, /**< the default extrapolates linearly */ + EXTRAP_NEAREST /**< extrapolates using nearest neighbor, will just continue from closest + point */ + }; + + /** specifies the unit type for outputs in the CSV file-s */ + enum CSVOPTIONS + { + CSVOPT_NONE = 0, + CSVOPT_IPUNITS = 1 << 0, + CSVOPT_IS_DRAWING = 1 << 1 + }; + + struct NodeWeight + { + int nodeNum; + double weight; + NodeWeight(int n, double w) : nodeNum(n), weight(w) {}; + + NodeWeight(int n) : nodeNum(n), weight(1.0) {}; + }; + + struct HeatingLogic + { + public: + std::string description; + std::function compare; + + HeatingLogic(std::string desc, + double decisionPoint_in, + HPWH* hpwh_in, + std::function c, + bool isHTS) + : description(desc) + , decisionPoint(decisionPoint_in) + , hpwh(hpwh_in) + , compare(c) + , isEnteringWaterHighTempShutoff(isHTS) {}; + + /**< checks that the input is all valid. */ + virtual const bool isValid() = 0; + /**< gets the value for comparing the tank value to, i.e. the target SoC */ + virtual const double getComparisonValue() = 0; + /**< gets the calculated value from the tank, i.e. SoC or tank average of node weights*/ + virtual const double getTankValue() = 0; + /**< function to calculate where the average node for a logic set is. */ + virtual const double nodeWeightAvgFract() = 0; + /**< gets the fraction of a node that has to be heated up to met the turnoff condition*/ + virtual const double getFractToMeetComparisonExternal() = 0; + + virtual int setDecisionPoint(double value) = 0; + double getDecisionPoint() { return decisionPoint; } + bool getIsEnteringWaterHighTempShutoff() { return isEnteringWaterHighTempShutoff; } + + protected: + double decisionPoint; + HPWH* hpwh; + bool isEnteringWaterHighTempShutoff; + }; + + struct SoCBasedHeatingLogic : HeatingLogic + { + public: + SoCBasedHeatingLogic(std::string desc, + double decisionPoint, + HPWH* hpwh, + double hF = -0.05, + double tM_C = 43.333, + bool constMains = false, + double mains_C = 18.333, + std::function c = std::less()) + : HeatingLogic(desc, decisionPoint, hpwh, c, false) + , hysteresisFraction(hF) + , tempMinUseful_C(tM_C) + , useCostantMains(constMains) + , constantMains_C(mains_C) {}; + const bool isValid(); + + const double getComparisonValue(); + const double getTankValue(); + const double nodeWeightAvgFract(); + const double getFractToMeetComparisonExternal(); + const double getMainsT_C(); + const double getTempMinUseful_C(); + int setDecisionPoint(double value); + int setConstantMainsTemperature(double mains_C); + + private: + double tempMinUseful_C; + double hysteresisFraction; + bool useCostantMains; + double constantMains_C; + }; + + struct TempBasedHeatingLogic : HeatingLogic + { + public: + TempBasedHeatingLogic(std::string desc, + std::vector n, + double decisionPoint, + HPWH* hpwh, + bool a = false, + std::function c = std::less(), + bool isHTS = false) + : HeatingLogic(desc, decisionPoint, hpwh, c, isHTS), nodeWeights(n), isAbsolute(a) {}; + + const bool isValid(); + + const double getComparisonValue(); + const double getTankValue(); + const double nodeWeightAvgFract(); + const double getFractToMeetComparisonExternal(); + + int setDecisionPoint(double value); + int setDecisionPoint(double value, bool absolute); + + private: + const bool areNodeWeightsValid(); + + bool isAbsolute; + std::vector nodeWeights; + }; + + std::shared_ptr shutOffSoC(std::string desc, + double targetSoC, + double hystFract, + double tempMinUseful_C, + bool constMains, + double mains_C); + std::shared_ptr turnOnSoC(std::string desc, + double targetSoC, + double hystFract, + double tempMinUseful_C, + bool constMains, + double mains_C); + + std::shared_ptr + wholeTank(double decisionPoint, const UNITS units = UNITS_C, const bool absolute = false); + std::shared_ptr topThird(double decisionPoint); + std::shared_ptr topThird_absolute(double decisionPoint); + std::shared_ptr + secondThird(double decisionPoint, const UNITS units = UNITS_C, const bool absolute = false); + std::shared_ptr bottomThird(double decisionPoint); + std::shared_ptr bottomHalf(double decisionPoint); + std::shared_ptr bottomTwelfth(double decisionPoint); + std::shared_ptr bottomSixth(double decisionPoint); + std::shared_ptr bottomSixth_absolute(double decisionPoint); + std::shared_ptr secondSixth(double decisionPoint); + std::shared_ptr thirdSixth(double decisionPoint); + std::shared_ptr fourthSixth(double decisionPoint); + std::shared_ptr fifthSixth(double decisionPoint); + std::shared_ptr topSixth(double decisionPoint); + + std::shared_ptr standby(double decisionPoint); + std::shared_ptr topNodeMaxTemp(double decisionPoint); + std::shared_ptr + bottomNodeMaxTemp(double decisionPoint, bool isEnteringWaterHighTempShutoff = false); + std::shared_ptr bottomTwelfthMaxTemp(double decisionPoint); + std::shared_ptr topThirdMaxTemp(double decisionPoint); + std::shared_ptr bottomSixthMaxTemp(double decisionPoint); + std::shared_ptr secondSixthMaxTemp(double decisionPoint); + std::shared_ptr fifthSixthMaxTemp(double decisionPoint); + std::shared_ptr topSixthMaxTemp(double decisionPoint); + + std::shared_ptr largeDraw(double decisionPoint); + std::shared_ptr largerDraw(double decisionPoint); + + /// this is the value that the public functions will return in case of a simulation + /// destroying error + static const int HPWH_ABORT = -274000; + + static std::string getVersion(); + /**< This function returns a string with the current version number */ + + int HPWHinit_presets(MODELS presetNum); + /**< This function will reset all member variables to defaults and then + * load in a set of parameters that are hardcoded in this function - + * which particular set of parameters is selected by presetNum. + * This is similar to the way the HPWHsim currently operates, as used in SEEM, + * but not quite as versatile. + * My impression is that this could be a useful input paradigm for CSE + * + * The return value is 0 for successful initialization, HPWH_ABORT otherwise + */ + + int HPWHinit_file(std::string configFile); + /**< This function will load in a set of parameters from a file + * The file name is the input - there should be at most one set of parameters per file + * This is useful for testing new variations, and for the sort of variability + * that we typically do when creating SEEM runs + * Appropriate use of this function can be found in the documentation + + * The return value is 0 for successful initialization, HPWH_ABORT otherwise + */ + + int HPWHinit_resTank(); /**< Default resistance tank, EF 0.95, volume 47.5 */ + int HPWHinit_resTank(double tankVol_L, + double energyFactor, + double upperPower_W, + double lowerPower_W); + /**< This function will initialize a HPWH object to be a resistance tank. Since + * resistance tanks are so simple, they can be specified with only four variables: + * tank volume, energy factor, and the power of the upper and lower elements. Energy + * factor is converted into UA internally, although an external setter for UA is + * also provided in case the energy factor is unknown. + * + * Several assumptions regarding the tank configuration are assumed: the lower element + * is at the bottom, the upper element is at the top third. The logics are also set + * to standard setting, with upper as VIP activating when the top third is too cold. + */ + + int HPWHinit_resTankGeneric(double tankVol_L, + double rValue_M2KperW, + double upperPower_W, + double lowerPower_W); + /**< This function will initialize a HPWH object to be a generic resistance storage water + * heater, with a specific R-Value defined at initalization. + * + * Several assumptions regarding the tank configuration are assumed: the lower element + * is at the bottom, the upper element is at the top third. The controls are the same standard + * controls for the HPWHinit_resTank() + */ + + int HPWHinit_genericHPWH(double tankVol_L, double energyFactor, double resUse_C); + /**< This function will initialize a HPWH object to be a non-specific HPWH model + * with an energy factor as specified. Since energy + * factor is not strongly correlated with energy use, most settings + * are taken from the GE2015_STDMode model. + */ + + int runOneStep(double drawVolume_L, + double ambientT_C, + double externalT_C, + DRMODES DRstatus, + double inletVol2_L = 0., + double inletT2_C = 0., + std::vector* extraHeatDist_W = NULL); + /**< This function will progress the simulation forward in time by one step + * all calculated outputs are stored in private variables and accessed through functions + * + * The return value is 0 for successful simulation run, HPWH_ABORT otherwise + */ + + /** An overloaded function that uses takes inletT_C */ + int runOneStep(double inletT_C, + double drawVolume_L, + double ambientT_C, + double externalT_C, + DRMODES DRstatus, + double inletVol2_L = 0., + double inletT2_C = 0., + std::vector* extraHeatDist_W = NULL) + { + setInletT(inletT_C); + return runOneStep(drawVolume_L, + ambientT_C, + externalT_C, + DRstatus, + inletVol2_L, + inletT2_C, + extraHeatDist_W); + }; + + int runNSteps(int N, + double* inletT_C, + double* drawVolume_L, + double* tankAmbientT_C, + double* heatSourceAmbientT_C, + DRMODES* DRstatus); + /**< This function will progress the simulation forward in time by N (equal) steps + * The calculated values will be summed or averaged, as appropriate, and + * then stored in the usual variables to be accessed through functions + * + * The return value is 0 for successful simulation run, HPWH_ABORT otherwise + */ + + /** Setters for the what are typically input variables */ + void setInletT(double newInletT_C) { member_inletT_C = newInletT_C; }; + void setMinutesPerStep(double newMinutesPerStep); + + void setVerbosity(VERBOSITY hpwhVrb); + /**< sets the verbosity to the specified level */ + void setMessageCallback(void (*callbackFunc)(const std::string message, void* pContext), + void* pContext); + /**< sets the function to be used for message passing */ + void printHeatSourceInfo(); + /**< this prints out the heat source info, nicely formatted + specifically input/output energy/power, and runtime + will print to cout if messageCallback pointer is unspecified + does not use verbosity, as it is public and expected to be called only when needed */ + void printTankTemps(); + /**< this prints out all the node temps, kind of nicely formatted + does not use verbosity, as it is public and expected to be called only when needed */ + + int WriteCSVHeading(FILE* outFILE, + const char* preamble = "", + int nTCouples = 6, + int options = CSVOPT_NONE) const; + int WriteCSVRow(FILE* outFILE, + const char* preamble = "", + int nTCouples = 6, + int options = CSVOPT_NONE) const; + /**< a couple of function to write the outputs to a file + they both will return 0 for success + the preamble should be supplied with a trailing comma, as these functions do + not add one. Additionally, a newline is written with each call. */ + + /**< Sets the tank node temps based on the provided vector of temps, which are mapped onto the + existing nodes, regardless of numNodes. */ + int setTankLayerTemperatures(std::vector setTemps, const UNITS units = UNITS_C); + void getTankTemps(std::vector& tankTemps); + + bool isSetpointFixed() const; /**< is the setpoint allowed to be changed */ + int setSetpoint(double newSetpoint, UNITS units = UNITS_C); /** 0 minutes and < 1440 + * minutes. */ + double getTimerLimitTOT_minute() const; + /**< Returns the timer limit in minutes for the DR_TOT call. */ + + int getInletHeight(int whichInlet) const; + /**< returns the water inlet height node number */ + + /**< resizes the tankTemp_C and nextTankTemp_C node vectors */ + void setNumNodes(const std::size_t num_nodes); + + /**< returns the number of nodes */ + int getNumNodes() const; + + /**< returns the index of the top node */ + int getIndexTopNode() const; + + double getTankNodeTemp(int nodeNum, UNITS units = UNITS_C) const; + /**< returns the temperature of the water at the specified node - with specified units + or HPWH_ABORT for incorrect node number or unit failure */ + + double getNthSimTcouple(int iTCouple, int nTCouple, UNITS units = UNITS_C) const; + /**< returns the temperature from a set number of virtual "thermocouples" specified by nTCouple, + which are constructed from the node temperature array. Specify iTCouple from 1-nTCouple, + 1 at the bottom using specified units + returns HPWH_ABORT for iTCouple < 0, > nTCouple, or incorrect units */ + + int getNumHeatSources() const; + /**< returns the number of heat sources */ + + int getNumResistanceElements() const; + /**< returns the number of resistance elements */ + + int getCompressorIndex() const; + /**< returns the index of the compressor in the heat source array. + Note only supports HPWHs with one compressor, if multiple will return the last index + of a compressor */ + + double getCompressorCapacity(double airTemp = 19.722, + double inletTemp = 14.444, + double outTemp = 57.222, + UNITS pwrUnit = UNITS_KW, + UNITS tempUnit = UNITS_C); + /**< Returns the heating output capacity of the compressor for the current HPWH model. + Note only supports HPWHs with one compressor, if multiple will return the last index + of a compressor. Outlet temperatures greater than the max allowable setpoints will return an + error, but for compressors with a fixed setpoint the */ + + int setCompressorOutputCapacity(double newCapacity, + double airTemp = 19.722, + double inletTemp = 14.444, + double outTemp = 57.222, + UNITS pwrUnit = UNITS_KW, + UNITS tempUnit = UNITS_C); + /**< Sets the heating output capacity of the compressor at the defined air, inlet water, and + outlet temperatures. For multi-pass models the capacity is set as the average between the + inletTemp and outTemp since multi-pass models will increase the water temperature only a few + degrees at a time (i.e. maybe 10 degF) until the tank reaches the outTemp, the capacity at + inletTemp might not be accurate for the entire heating cycle. + Note only supports HPWHs with one compressor, if multiple will return the last index + of a compressor */ + + int setScaleHPWHCapacityCOP(double scaleCapacity = 1., double scaleCOP = 1.); + /**< Scales the heatpump water heater input capacity and COP*/ + + int setResistanceCapacity(double power, int which = -1, UNITS pwrUNIT = UNITS_KW); + /**< Scale the resistance elements in the heat source list. Which heat source is chosen is + changes is given by "which" + - If which (-1) sets all the resisistance elements in the tank. + - If which (0, 1, 2...) sets the resistance element in a low to high order. + So if there are 3 elements 0 is the bottom, 1 is the middle, and 2 is the top element, + regardless of their order in heatSources. If the elements exist on at the same node then all of + the elements are set. + + The only valid values for which are between -1 and getNumResistanceElements()-1. Since which is + defined as the by the ordered height of the resistance elements it cannot refer to a compressor. + */ + + double getResistanceCapacity(int which = -1, UNITS pwrUNIT = UNITS_KW); + /**< Returns the resistance elements capacity. Which heat source is chosen is changes is given + by "which" + - If which (-1) gets all the resisistance elements in the tank. + - If which (0, 1, 2...) sets the resistance element in a low to high order. + So if there are 3 elements 0 is the bottom, 1 is the middle, and 2 is the top element, + regardless of their order in heatSources. If the elements exist on at the same node then all of + the elements are set. + + The only valid values for which are between -1 and getNumResistanceElements()-1. Since which is + defined as the by the ordered height of the resistance elements it cannot refer to a compressor. + */ + + int getResistancePosition(int elementIndex) const; + + double getNthHeatSourceEnergyInput(int N, UNITS units = UNITS_KWH) const; + /**< returns the energy input to the Nth heat source, with the specified units + energy used by the heat source is positive - should always be positive + returns HPWH_ABORT for N out of bounds or incorrect units */ + + double getNthHeatSourceEnergyOutput(int N, UNITS units = UNITS_KWH) const; + /**< returns the energy output from the Nth heat source, with the specified units + energy put into the water is positive - should always be positive + returns HPWH_ABORT for N out of bounds or incorrect units */ + + double getNthHeatSourceRunTime(int N) const; + /**< returns the run time for the Nth heat source, in minutes + note: they may sum to more than 1 time step for concurrently running heat sources + returns HPWH_ABORT for N out of bounds */ + int isNthHeatSourceRunning(int N) const; + /**< returns 1 if the Nth heat source is currently engaged, 0 if it is not, and + returns HPWH_ABORT for N out of bounds */ + HEATSOURCE_TYPE getNthHeatSourceType(int N) const; + /**< returns the enum value for what type of heat source the Nth heat source is */ + + double getOutletTemp(UNITS units = UNITS_C) const; + /**< returns the outlet temperature in the specified units + returns 0 when no draw occurs, or HPWH_ABORT for incorrect unit specifier */ + double getCondenserWaterInletTemp(UNITS units = UNITS_C) const; + /**< returns the condenser inlet temperature in the specified units + returns 0 when no HP not running occurs, or HPWH_ABORT for incorrect unit specifier */ + + double getCondenserWaterOutletTemp(UNITS units = UNITS_C) const; + /**< returns the condenser outlet temperature in the specified units + returns 0 when no HP not running occurs, or HPWH_ABORT for incorrect unit specifier */ + + double getExternalVolumeHeated(UNITS units = UNITS_L) const; + /**< returns the volume of water heated in an external in the specified units + returns 0 when no external heat source is running */ + + double getEnergyRemovedFromEnvironment(UNITS units = UNITS_KWH) const; + /**< get the total energy removed from the environment by all heat sources in specified units + (not net energy - does not include standby) + moving heat from the space to the water is the positive direction + returns HPWH_ABORT for incorrect units */ + + double getStandbyLosses(UNITS units = UNITS_KWH) const; + /**< get the amount of heat lost through the tank in specified units + moving heat from the water to the space is the positive direction + negative should occur seldom + returns HPWH_ABORT for incorrect units */ + + double getTankHeatContent_kJ() const; + /**< get the heat content of the tank, relative to zero celsius + * returns using kilojoules */ + + int getHPWHModel() const; + /**< get the model number of the HPWHsim model number of the hpwh */ + + int getCompressorCoilConfig() const; + bool isCompressorMultipass() const; + bool isCompressoExternalMultipass() const; + + bool hasACompressor() const; + /**< Returns if the HPWH model has a compressor or not, could be a storage or resistance tank. + */ + + bool hasExternalHeatSource() const; + /**< Returns if the HPWH model has any external heat sources or not, could be a compressor or + * resistance element. */ + double getExternalMPFlowRate(UNITS units = UNITS_GPM) const; + /**< Returns the constant flow rate for an external multipass heat sources. */ + + double getCompressorMinRuntime(UNITS units = UNITS_MIN) const; + + int getSizingFractions(double& aquafract, double& percentUseable) const; + /**< returns the fraction of total tank volume from the bottom up where the aquastat is + or the turn on logic for the compressor, and the USEable fraction of storage or 1 minus + where the shut off logic is for the compressor. If the logic spans multiple nodes it + returns the weighted average of the nodes */ + + bool isHPWHScalable() const; + /**< returns if the HPWH is scalable or not*/ + + bool shouldDRLockOut(HEATSOURCE_TYPE hs, DRMODES DR_signal) const; + /**< Checks the demand response signal against the different heat source types */ + + void resetTopOffTimer(); + /**< resets variables for timer associated with the DR_TOT call */ + + double getLocationTemp_C() const; + int setMaxTempDepression(double maxDepression, UNITS units = UNITS_C); + + bool hasEnteringWaterHighTempShutOff(int heatSourceIndex); + int setEnteringWaterHighTempShutOff(double highTemp, + bool tempIsAbsolute, + int heatSourceIndex, + UNITS units = UNITS_C); + /**< functions to check for and set specific high temperature shut off logics. + HPWHs can only have one of these, which is at least typical */ + + int setTargetSoCFraction(double target); + + bool canUseSoCControls(); + + int switchToSoCControls(double targetSoC, + double hysteresisFraction = 0.05, + double tempMinUseful = 43.333, + bool constantMainsT = false, + double mainsT = 18.333, + UNITS tempUnit = UNITS_C); + + bool isSoCControlled() const; + + /// Checks whether energy is balanced during a simulation step. + bool isEnergyBalanced(const double drawVol_L, + const double prevHeatContent_kJ, + const double fracEnergyTolerance = 0.001); + + /// Overloaded version of above that allows specification of inlet temperature. + bool isEnergyBalanced(const double drawVol_L, + double inletT_C_in, + const double prevHeatContent_kJ, + const double fracEnergyTolerance) + { + setInletT(inletT_C_in); + return isEnergyBalanced(drawVol_L, prevHeatContent_kJ, fracEnergyTolerance); + } + /// Addition of heat from a normal heat sources; return excess heat, if needed, to prevent + /// exceeding maximum or setpoint + double addHeatAboveNode(double qAdd_kJ, const int nodeNum, const double maxT_C); - MODELS hpwhModel; - /**< The hpwh should know which preset initialized it, or if it was from a fileget */ + /// Addition of extra heat handled separately from normal heat sources + void addExtraHeatAboveNode(double qAdd_kJ, const int nodeNum); - // a std::vector containing the HeatSources, in order of priority - std::vector heatSources; + private: + class HeatSource; - int compressorIndex; - /**< The index of the compressor heat source (set to -1 if no compressor)*/ + void setAllDefaults(); /**< sets all the defaults default */ - int lowestElementIndex; - /**< The index of the lowest resistance element heat source (set to -1 if no resistance elements)*/ + void updateTankTemps( + double draw, double inletT_C, double ambientT_C, double inletVol2_L, double inletT2_L); + void mixTankInversions(); + /**< Mixes the any temperature inversions in the tank after all the temperature calculations */ + void updateSoCIfNecessary(); - int highestElementIndex; - /**< The index of the highest resistance element heat source. if only one element it equals lowestElementIndex (set to -1 if no resistance elements)*/ + bool areAllHeatSourcesOff() const; + /**< test if all the heat sources are off */ + void turnAllHeatSourcesOff(); + /**< disengage each heat source */ - int VIPIndex; - /**< The index of the VIP resistance element heat source (set to -1 if no VIP resistance elements)*/ + void addHeatParent(HeatSource* heatSourcePtr, double heatSourceAmbientT_C, double minutesToRun); - int inletHeight; - /**< the number of a node in the tank that the inlet water enters the tank at, must be between 0 and numNodes-1 */ + /// adds extra heat to the set of nodes that are at the same temperature, above the + /// specified node number + void modifyHeatDistribution(std::vector& heatDistribution); + void addExtraHeat(std::vector& extraHeatDist_W); - int inlet2Height; - /**< the number of a node in the tank that the 2nd inlet water enters the tank at, must be between 0 and numNodes-1 */ + /// "extra" heat added during a simulation step + double extraEnergyInput_kWh; - /**< the volume in liters of the tank */ - double tankVolume_L; + double tankAvg_C(const std::vector nodeWeights) const; + /**< functions to calculate what the temperature in a portion of the tank is */ - /**< the UA of the tank, in metric units */ - double tankUA_kJperHrC; + void mixTankNodes(int mixedAboveNode, int mixedBelowNode, double mixFactor); + /**< function to average the nodes in a tank together bewtween the mixed abovenode and mixed + * below node. */ - /**< the UA of the fittings for the tank, in metric units */ - double fittingsUA_kJperHrC; + void calcDerivedValues(); + /**< a helper function for the inits, calculating condentropy and the lowest node */ + void calcSizeConstants(); + /**< a helper function to set constants for the UA and tank size*/ + void calcDerivedHeatingValues(); + /**< a helper for the helper, calculating condentropy and the lowest node*/ + void mapResRelativePosToHeatSources(); + /**< a helper function for the inits, creating a mapping function for the position of the + resistance elements to their indexes in heatSources. */ - /**< the volume (L) of a single node */ - double nodeVolume_L; + int checkInputs(); + /**< a helper function to run a few checks on the HPWH input parameters */ - /**< the mass of water (kg) in a single node */ - double nodeMass_kg; + double getChargePerNode(double tCold, double tMix, double tHot) const; - /**< the heat capacity of the water (kJ/�C) in a single node */ - double nodeCp_kJperC; + void calcAndSetSoCFraction(); - /**< the height in meters of the one node */ - double nodeHeight_m; + void sayMessage(const std::string message) const; + /**< if the messagePriority is >= the hpwh verbosity, + either pass your message out to the callback function or print it to cout + otherwise do nothing */ + void msg(const char* fmt, ...) const; + void msgV(const char* fmt, va_list ap = NULL) const; - double fracAreaTop; - /**< the fraction of the UA on the top and bottom of the tank, assuming it's a cylinder */ - double fracAreaSide; - /**< the fraction of the UA on the sides of the tank, assuming it's a cylinder */ + bool simHasFailed; + /**< did an internal error cause the simulation to fail? */ - double currentSoCFraction; - /**< the current state of charge according to the logic */ + bool isHeating; + /**< is the hpwh currently heating or not? */ - double setpoint_C; - /**< the setpoint of the tank */ + bool setpointFixed; + /**< does the HPWH allow the setpoint to vary */ - /**< holds the temperature of each node - 0 is the bottom node */ - std::vector tankTemps_C; + bool tankSizeFixed; + /**< does the HPWH have a constant tank size or can it be changed */ - /**< holds the future temperature of each node for the conduction calculation - 0 is the bottom node */ - std::vector nextTankTemps_C; + bool canScale; + /**< can the HPWH scale capactiy and COP or not */ - DRMODES prevDRstatus; - /**< the DRstatus of the tank in the previous time step and at the end of runOneStep */ + VERBOSITY hpwhVerbosity; + /**< an enum to let the sim know how much output to say */ - double timerLimitTOT; - /**< the time limit in minutes on the timer when the compressor and resistance elements are turned back on, used with DR_TOT. */ - double timerTOT; - /**< the timer used for DR_TOT to turn on the compressor and resistance elements. */ + void (*messageCallback)(const std::string message, void* contextPtr); + /**< function pointer to indicate an external message processing function */ + void* messageCallbackContextPtr; + /**< caller context pointer for external message processing */ - bool usesSoCLogic; + MODELS hpwhModel; + /**< The hpwh should know which preset initialized it, or if it was from a fileget */ - // Some outputs - double outletTemp_C; - /**< the temperature of the outlet water - taken from top of tank, 0 if no flow */ + // a std::vector containing the HeatSources, in order of priority + std::vector heatSources; - double condenserInlet_C; - /**< the temperature of the inlet water to the condensor either an average of tank nodes or taken from the bottom, 0 if no flow or no compressor */ - double condenserOutlet_C; - /**< the temperature of the outlet water from the condensor either, 0 if no flow or no compressor */ - double externalVolumeHeated_L; - /**< the volume of water heated by an external source, 0 if no flow or no external heat source */ + int compressorIndex; + /**< The index of the compressor heat source (set to -1 if no compressor)*/ - double energyRemovedFromEnvironment_kWh; - /**< the total energy removed from the environment, to heat the water */ - double standbyLosses_kWh; - /**< the amount of heat lost to standby */ + int lowestElementIndex; + /**< The index of the lowest resistance element heat source (set to -1 if no resistance + * elements)*/ - // special variables for adding abilities - bool tankMixesOnDraw; - /**< whether or not the bottom fraction (defined by mixBelowFraction) - of the tank should mix during draws */ - double mixBelowFractionOnDraw; - /**< mixes the tank below this fraction on draws iff tankMixesOnDraw */ + int highestElementIndex; + /**< The index of the highest resistance element heat source. if only one element it equals + * lowestElementIndex (set to -1 if no resistance elements)*/ - bool doTempDepression; - /**< whether the HPWH should use the alternate ambient temperature that - gets depressed when a compressor is running - NOTE: this only works for 1 minute steps */ - double locationTemperature_C; - /**< this is the special location temperature that stands in for the the - ambient temperature if you are doing temp. depression */ - double maxDepression_C = 2.5; - /** a couple variables to hold values which are typically inputs */ - double member_inletT_C; + int VIPIndex; + /**< The index of the VIP resistance element heat source (set to -1 if no VIP resistance + * elements)*/ - double minutesPerStep = 1.; - double secondsPerStep,hoursPerStep; + int inletHeight; + /**< the number of a node in the tank that the inlet water enters the tank at, must be between 0 + * and numNodes-1 */ - bool doInversionMixing; - /**< If and only if true will model temperature inversion mixing in the tank */ + int inlet2Height; + /**< the number of a node in the tank that the 2nd inlet water enters the tank at, must be + * between 0 and numNodes-1 */ - bool doConduction; - /**< If and only if true will model conduction between the internal nodes of the tank */ + /**< the volume in liters of the tank */ + double tankVolume_L; + + /**< the UA of the tank, in metric units */ + double tankUA_kJperHrC; - struct resPoint { - int index; - int position; - }; - std::vector resistanceHeightMap; - /**< A map from index of an resistance element in heatSources to position in the tank, its - is sorted by height from lowest to highest*/ - - /// Generates a vector of logical nodes - std::vector getNodeWeightRange(double bottomFraction,double topFraction); - - /// False: water is drawn from the tank itself; True: tank provides heat exchange only - bool hasHeatExchanger; - - /// Coefficient (0-1) of effectiveness for heat exchange between tank and water line (used by heat-exchange models only). - double heatExchangerEffectiveness; - - /// Coefficient (0-1) of effectiveness for heat exchange between a single tank node and water line (derived from heatExchangerEffectiveness). - double nodeHeatExchangerEffectiveness; - -}; //end of HPWH class - -class HPWH::HeatSource { -public: - friend class HPWH; - - HeatSource(){} /**< default constructor, does not create a useful HeatSource */ - HeatSource(HPWH *parentHPWH); - /**< constructor assigns a pointer to the hpwh that owns this heat source */ - HeatSource(const HeatSource &hSource); ///copy constructor - HeatSource& operator=(const HeatSource &hSource); ///assignment operator - /**< the copy constructor and assignment operator basically just checks if there - are backup/companion pointers - these can't be copied */ - - void setupAsResistiveElement(int node,double Watts,int condensitySize = CONDENSITY_SIZE); - /**< configure the heat source to be a resisive element, positioned at the - specified node, with the specified power in watts */ - - bool isEngaged() const; - /**< return whether or not the heat source is engaged */ - void engageHeatSource(DRMODES DRstatus = DR_ALLOW); - /**< turn heat source on, i.e. set isEngaged to TRUE */ - void disengageHeatSource(); - /**< turn heat source off, i.e. set isEngaged to FALSE */ - - bool isLockedOut() const; - /**< return whether or not the heat source is locked out */ - void lockOutHeatSource(); - /**< lockout heat source, i.e. set isLockedOut to TRUE */ - void unlockHeatSource(); - /**< unlock heat source, i.e. set isLockedOut to FALSE */ - - bool shouldLockOut(double heatSourceAmbientT_C) const; - /**< queries the heat source as to whether it should lock out */ - bool shouldUnlock(double heatSourceAmbientT_C) const; - /**< queries the heat source as to whether it should unlock */ - - bool toLockOrUnlock(double heatSourceAmbientT_C); - /**< combines shouldLockOut and shouldUnlock to one master function which locks or unlocks the heatsource. Return boolean lockedOut (true if locked, false if unlocked)*/ - - bool shouldHeat() const; - /**< queries the heat source as to whether or not it should turn on */ - bool shutsOff() const; - /**< queries the heat source whether should shut off */ - - bool maxedOut() const; - /**< queries the heat source as to if it shouldn't produce hotter water and the tank isn't at setpoint. */ - - int findParent() const; - /**< returns the index of the heat source where this heat source is a backup. - returns -1 if none found. */ - - double fractToMeetComparisonExternal() const; - /**< calculates the distance the current state is from the shutOff logic for external configurations*/ - - void addHeat(double externalT_C,double minutesToRun); - /**< adds heat to the hpwh - this is the function that interprets the - various configurations (internal/external, resistance/heat pump) to add heat */ - - /// Assign new condensity values from supplied vector. Note the input vector is currently resampled - /// to preserve a condensity vector of size CONDENSITY_SIZE. - void setCondensity(const std::vector &condensity_in); - - int getCondensitySize() const; - - void linearInterp(double &ynew,double xnew,double x0,double x1,double y0,double y1); - /**< Does a simple linear interpolation between two points to the xnew point */ - - void regressedMethod(double &ynew,std::vector &coefficents,double x1,double x2,double x3); - /**< Does a calculation based on the ten term regression equation */ - - void regressedMethodMP(double &ynew,std::vector &coefficents,double x1,double x2); - /**< Does a calculation based on the five term regression equation for MP split systems */ - - void btwxtInterp(double& input_BTUperHr,double& cop,std::vector& target); - /**< Does a linear interpolation in btwxt to the target point*/ - - void setupDefrostMap(double derate35 = 0.8865); - /**< configure the heat source with a default for the defrost derating */ - void defrostDerate(double &to_derate,double airT_C); - /**< Derates the COP of a system based on the air temperature */ - -private: - //start with a few type definitions - enum COIL_CONFIG { - CONFIG_SUBMERGED, - CONFIG_WRAPPED, - CONFIG_EXTERNAL - }; - - /** the creator of the heat source, necessary to access HPWH variables */ - HPWH *hpwh; - - // these are the heat source state/output variables - bool isOn; - /**< is the heat source running or not */ - - bool lockedOut; - /**< is the heat source locked out */ - - bool doDefrost; - /**< If and only if true will derate the COP of a compressor to simulate a defrost cycle */ - - // some outputs - double runtime_min; - /**< this is the percentage of the step that the heat source was running */ - double energyInput_kWh; - /**< the energy used by the heat source */ - double energyOutput_kWh; - /**< the energy put into the water by the heat source */ - -// these are the heat source property variables - bool isVIP; - /**< is this heat source a high priority heat source? (e.g. upper resisitor) */ - HeatSource* backupHeatSource; - /**< a pointer to the heat source which serves as backup to this one - should be NULL if no backup exists */ - HeatSource* companionHeatSource; - /**< a pointer to the heat source which will run concurrently with this one - it still will only turn on if shutsOff is false */ - - HeatSource* followedByHeatSource; - /**< a pointer to the heat source which will attempt to run after this one */ - - // condensity is represented as a std::vector of size CONDENSITY_SIZE. - // It represents the location within the tank where heat will be distributed, - // and it also is used to calculate the condenser temperature for inputPower/COP calcs. - // It is conceptually linked to the way condenser coils are wrapped around - // (or within) the tank, however a resistance heat source can also be simulated - // by specifying the entire condensity in one node. */ - std::vector condensity; - - double Tshrinkage_C; - /**< Tshrinkage_C is a derived from the condentropy (conditional entropy), - using the condensity and fixed parameters Talpha_C and Tbeta_C. - Talpha_C and Tbeta_C are not intended to be settable - see the hpwh_init functions for calculation of shrinkage */ - - struct perfPoint { - double T_F; - std::vector inputPower_coeffs; // c0 + c1*T + c2*T*T - std::vector COP_coeffs; // c0 + c1*T + c2*T*T - }; - - std::vector perfMap; - /**< A map with input/COP quadratic curve coefficients at a given external temperature */ - - std::vector< std::vector > perfGrid; - /**< The axis values defining the regular grid for the performance data. - SP would have 3 axis, MP would have 2 axis*/ - - std::vector< std::vector > perfGridValues; - /**< The values for input power and cop use matching to the grid. Should be long format with { { inputPower_W }, { COP } }. */ - - class Btwxt::RegularGridInterpolator *perfRGI; - /**< The grid interpolator used for mapping performance*/ - - bool useBtwxtGrid; - - /** a vector to hold the set of logical choices for turning this element on */ - std::vector> turnOnLogicSet; - /** a vector to hold the set of logical choices that can cause an element to turn off */ - std::vector> shutOffLogicSet; - /** a single logic that checks the bottom point is below a temperature so the system doesn't short cycle*/ - std::shared_ptr standbyLogic; - - /** some compressors have a resistance element for defrost*/ - struct resistanceElementDefrost - { - double inputPwr_kW; - double constTempLift_dF; - double onBelowT_F; - }; - resistanceElementDefrost resDefrost; - - struct defrostPoint { - double T_F; - double derate_fraction; - }; - std::vector defrostMap; - /**< A list of points for the defrost derate factor ordered by increasing external temperature */ - - struct maxOut_minAir { - double outT_C; - double airT_C; - }; - maxOut_minAir maxOut_at_LowT; - /**< maximum output temperature at the minimum operating temperature of HPWH environment (minT)*/ - - struct SecondaryHeatExchanger { - double coldSideTemperatureOffest_dC; - double hotSideTemperatureOffset_dC; - double extraPumpPower_W; - }; - - SecondaryHeatExchanger secondaryHeatExchanger; /**< adjustments for a approximating a secondary heat exchanger by adding extra input energy for the pump and - an increaes in the water to the incoming waater temperature to the heatpump*/ - - void addTurnOnLogic(std::shared_ptr logic); - void addShutOffLogic(std::shared_ptr logic); - /**< these are two small functions to remove some of the cruft in initiation functions */ - void clearAllTurnOnLogic(); - void clearAllShutOffLogic(); - void clearAllLogic(); - /**< these are two small functions to remove some of the cruft in initiation functions */ - - - - void changeResistanceWatts(double watts); - /**< function to change the resistance wattage */ - - bool isACompressor() const; - /**< returns if the heat source uses a compressor or not */ - bool isAResistance() const; - /**< returns if the heat source uses a resistance element or not */ - bool isExternalMultipass() const; - - double minT; - /**< minimum operating temperature of HPWH environment */ - - double maxT; - /**< maximum operating temperature of HPWH environment */ - - double maxSetpoint_C; - /**< the maximum setpoint of the heat source can create, used for compressors predominately */ - - double hysteresis_dC; - /**< a hysteresis term that prevents short cycling due to heat pump self-interaction - when the heat source is engaged, it is subtracted from lowT cutoffs and - added to lowTreheat cutoffs */ + /**< the UA of the fittings for the tank, in metric units */ + double fittingsUA_kJperHrC; - bool depressesTemperature; - /**< heat pumps can depress the temperature of their space in certain instances - - whether or not this occurs is a bool in HPWH, but a heat source must - know if it is capable of contributing to this effect or not - NOTE: this only works for 1 minute steps - ALSO: this is set according the the heat source type, not user-specified */ + /**< the volume (L) of a single node */ + double nodeVolume_L; - double airflowFreedom; - /**< airflowFreedom is the fraction of full flow. This is used to de-rate compressor - cop (not capacity) for cases where the air flow is restricted - typically ducting */ + /**< the mass of water (kg) in a single node */ + double nodeMass_kg; - int externalInletHeight; /** tankTemps_C; - // some private functions, mostly used for heating the water with the addHeat function + /**< holds the future temperature of each node for the conduction calculation - 0 is the bottom + * node */ + std::vector nextTankTemps_C; - double addHeatExternal(double externalT_C,double minutesToRun,double &cap_BTUperHr,double &input_BTUperHr,double &cop); - /**< Add heat from a source outside of the tank. Assume the condensity is where - the water is drawn from and hot water is put at the top of the tank. */ + DRMODES prevDRstatus; + /**< the DRstatus of the tank in the previous time step and at the end of runOneStep */ - /** I wrote some methods to help with the add heat interface - MJL */ - void getCapacity(double externalT_C,double condenserTemp_C,double setpointTemp_C,double &input_BTUperHr,double &cap_BTUperHr,double &cop); + double timerLimitTOT; + /**< the time limit in minutes on the timer when the compressor and resistance elements are + * turned back on, used with DR_TOT. */ + double timerTOT; + /**< the timer used for DR_TOT to turn on the compressor and resistance elements. */ - /** An overloaded function that uses uses the setpoint temperature */ - void getCapacity(double externalT_C,double condenserTemp_C,double &input_BTUperHr,double &cap_BTUperHr,double &cop) { - getCapacity(externalT_C,condenserTemp_C,hpwh->getSetpoint(),input_BTUperHr,cap_BTUperHr,cop); - }; - /** An equivalent getCapcity function just for multipass external (or split) HPWHs */ - void getCapacityMP(double externalT_C,double condenserTemp_C,double &input_BTUperHr,double &cap_BTUperHr,double &cop); + bool usesSoCLogic; - double calcMPOutletTemperature(double heatingCapacity_KW); - /**< returns the temperature of outlet of a external multipass hpwh */ + // Some outputs + double outletTemp_C; + /**< the temperature of the outlet water - taken from top of tank, 0 if no flow */ - void calcHeatDist(std::vector &heatDistribution); + double condenserInlet_C; + /**< the temperature of the inlet water to the condensor either an average of tank nodes or + * taken from the bottom, 0 if no flow or no compressor */ + double condenserOutlet_C; + /**< the temperature of the outlet water from the condensor either, 0 if no flow or no + * compressor */ + double externalVolumeHeated_L; + /**< the volume of water heated by an external source, 0 if no flow or no external heat source + */ - double getTankTemp() const; - /**< returns the tank temperature weighted by the condensity for this heat source */ + double energyRemovedFromEnvironment_kWh; + /**< the total energy removed from the environment, to heat the water */ + double standbyLosses_kWh; + /**< the amount of heat lost to standby */ - void sortPerformanceMap(); - /**< sorts the Performance Map by increasing external temperatures */ + // special variables for adding abilities + bool tankMixesOnDraw; + /**< whether or not the bottom fraction (defined by mixBelowFraction) + of the tank should mix during draws */ + double mixBelowFractionOnDraw; + /**< mixes the tank below this fraction on draws iff tankMixesOnDraw */ -}; // end of HeatSource class + bool doTempDepression; + /**< whether the HPWH should use the alternate ambient temperature that + gets depressed when a compressor is running + NOTE: this only works for 1 minute steps */ + double locationTemperature_C; + /**< this is the special location temperature that stands in for the the + ambient temperature if you are doing temp. depression */ + double maxDepression_C = 2.5; + /** a couple variables to hold values which are typically inputs */ + double member_inletT_C; + + double minutesPerStep = 1.; + double secondsPerStep, hoursPerStep; + + bool doInversionMixing; + /**< If and only if true will model temperature inversion mixing in the tank */ + + bool doConduction; + /**< If and only if true will model conduction between the internal nodes of the tank */ -constexpr double BTUperKWH = 3412.14163312794; // https://www.rapidtables.com/convert/energy/kWh_to_BTU.html -constexpr double FperC = 9. / 5.; // degF / degC -constexpr double offsetF = 32.; // degF offset + struct resPoint + { + int index; + int position; + }; + std::vector resistanceHeightMap; + /**< A map from index of an resistance element in heatSources to position in the tank, its + is sorted by height from lowest to highest*/ + + /// Generates a vector of logical nodes + std::vector getNodeWeightRange(double bottomFraction, double topFraction); + + /// False: water is drawn from the tank itself; True: tank provides heat exchange only + bool hasHeatExchanger; + + /// Coefficient (0-1) of effectiveness for heat exchange between tank and water line (used by + /// heat-exchange models only). + double heatExchangerEffectiveness; + + /// Coefficient (0-1) of effectiveness for heat exchange between a single tank node and water + /// line (derived from heatExchangerEffectiveness). + double nodeHeatExchangerEffectiveness; + +}; // end of HPWH class + +class HPWH::HeatSource +{ + public: + friend class HPWH; + + HeatSource() {} /**< default constructor, does not create a useful HeatSource */ + HeatSource(HPWH* parentHPWH); + /**< constructor assigns a pointer to the hpwh that owns this heat source */ + HeatSource(const HeatSource& hSource); /// copy constructor + HeatSource& operator=(const HeatSource& hSource); /// assignment operator + /**< the copy constructor and assignment operator basically just checks if there + are backup/companion pointers - these can't be copied */ + + void setupAsResistiveElement(int node, double Watts, int condensitySize = CONDENSITY_SIZE); + /**< configure the heat source to be a resisive element, positioned at the + specified node, with the specified power in watts */ + + bool isEngaged() const; + /**< return whether or not the heat source is engaged */ + void engageHeatSource(DRMODES DRstatus = DR_ALLOW); + /**< turn heat source on, i.e. set isEngaged to TRUE */ + void disengageHeatSource(); + /**< turn heat source off, i.e. set isEngaged to FALSE */ + + bool isLockedOut() const; + /**< return whether or not the heat source is locked out */ + void lockOutHeatSource(); + /**< lockout heat source, i.e. set isLockedOut to TRUE */ + void unlockHeatSource(); + /**< unlock heat source, i.e. set isLockedOut to FALSE */ + + bool shouldLockOut(double heatSourceAmbientT_C) const; + /**< queries the heat source as to whether it should lock out */ + bool shouldUnlock(double heatSourceAmbientT_C) const; + /**< queries the heat source as to whether it should unlock */ + + bool toLockOrUnlock(double heatSourceAmbientT_C); + /**< combines shouldLockOut and shouldUnlock to one master function which locks or unlocks the + * heatsource. Return boolean lockedOut (true if locked, false if unlocked)*/ + + bool shouldHeat() const; + /**< queries the heat source as to whether or not it should turn on */ + bool shutsOff() const; + /**< queries the heat source whether should shut off */ + + bool maxedOut() const; + /**< queries the heat source as to if it shouldn't produce hotter water and the tank isn't at + * setpoint. */ + + int findParent() const; + /**< returns the index of the heat source where this heat source is a backup. + returns -1 if none found. */ + + double fractToMeetComparisonExternal() const; + /**< calculates the distance the current state is from the shutOff logic for external + * configurations*/ + + void addHeat(double externalT_C, double minutesToRun); + /**< adds heat to the hpwh - this is the function that interprets the + various configurations (internal/external, resistance/heat pump) to add heat */ + + /// Assign new condensity values from supplied vector. Note the input vector is currently + /// resampled to preserve a condensity vector of size CONDENSITY_SIZE. + void setCondensity(const std::vector& condensity_in); + + int getCondensitySize() const; + + void linearInterp(double& ynew, double xnew, double x0, double x1, double y0, double y1); + /**< Does a simple linear interpolation between two points to the xnew point */ + + void regressedMethod( + double& ynew, std::vector& coefficents, double x1, double x2, double x3); + /**< Does a calculation based on the ten term regression equation */ + + void regressedMethodMP(double& ynew, std::vector& coefficents, double x1, double x2); + /**< Does a calculation based on the five term regression equation for MP split systems */ + + void btwxtInterp(double& input_BTUperHr, double& cop, std::vector& target); + /**< Does a linear interpolation in btwxt to the target point*/ + + void setupDefrostMap(double derate35 = 0.8865); + /**< configure the heat source with a default for the defrost derating */ + void defrostDerate(double& to_derate, double airT_C); + /**< Derates the COP of a system based on the air temperature */ + + private: + // start with a few type definitions + enum COIL_CONFIG + { + CONFIG_SUBMERGED, + CONFIG_WRAPPED, + CONFIG_EXTERNAL + }; + + /** the creator of the heat source, necessary to access HPWH variables */ + HPWH* hpwh; + + // these are the heat source state/output variables + bool isOn; + /**< is the heat source running or not */ + + bool lockedOut; + /**< is the heat source locked out */ + + bool doDefrost; + /**< If and only if true will derate the COP of a compressor to simulate a defrost cycle */ + + // some outputs + double runtime_min; + /**< this is the percentage of the step that the heat source was running */ + double energyInput_kWh; + /**< the energy used by the heat source */ + double energyOutput_kWh; + /**< the energy put into the water by the heat source */ + + // these are the heat source property variables + bool isVIP; + /**< is this heat source a high priority heat source? (e.g. upper resisitor) */ + HeatSource* backupHeatSource; + /**< a pointer to the heat source which serves as backup to this one + should be NULL if no backup exists */ + HeatSource* companionHeatSource; + /**< a pointer to the heat source which will run concurrently with this one + it still will only turn on if shutsOff is false */ + + HeatSource* followedByHeatSource; + /**< a pointer to the heat source which will attempt to run after this one */ + + // condensity is represented as a std::vector of size CONDENSITY_SIZE. + // It represents the location within the tank where heat will be distributed, + // and it also is used to calculate the condenser temperature for inputPower/COP calcs. + // It is conceptually linked to the way condenser coils are wrapped around + // (or within) the tank, however a resistance heat source can also be simulated + // by specifying the entire condensity in one node. */ + std::vector condensity; + + double Tshrinkage_C; + /**< Tshrinkage_C is a derived from the condentropy (conditional entropy), + using the condensity and fixed parameters Talpha_C and Tbeta_C. + Talpha_C and Tbeta_C are not intended to be settable + see the hpwh_init functions for calculation of shrinkage */ + + struct perfPoint + { + double T_F; + std::vector inputPower_coeffs; // c0 + c1*T + c2*T*T + std::vector COP_coeffs; // c0 + c1*T + c2*T*T + }; + + std::vector perfMap; + /**< A map with input/COP quadratic curve coefficients at a given external temperature */ + + std::vector> perfGrid; + /**< The axis values defining the regular grid for the performance data. + SP would have 3 axis, MP would have 2 axis*/ + + std::vector> perfGridValues; + /**< The values for input power and cop use matching to the grid. Should be long format with { { + * inputPower_W }, { COP } }. */ + + class Btwxt::RegularGridInterpolator* perfRGI; + /**< The grid interpolator used for mapping performance*/ + + bool useBtwxtGrid; + + /** a vector to hold the set of logical choices for turning this element on */ + std::vector> turnOnLogicSet; + /** a vector to hold the set of logical choices that can cause an element to turn off */ + std::vector> shutOffLogicSet; + /** a single logic that checks the bottom point is below a temperature so the system doesn't + * short cycle*/ + std::shared_ptr standbyLogic; + + /** some compressors have a resistance element for defrost*/ + struct resistanceElementDefrost + { + double inputPwr_kW; + double constTempLift_dF; + double onBelowT_F; + }; + resistanceElementDefrost resDefrost; + + struct defrostPoint + { + double T_F; + double derate_fraction; + }; + std::vector defrostMap; + /**< A list of points for the defrost derate factor ordered by increasing external temperature + */ + + struct maxOut_minAir + { + double outT_C; + double airT_C; + }; + maxOut_minAir maxOut_at_LowT; + /**< maximum output temperature at the minimum operating temperature of HPWH environment + * (minT)*/ + + struct SecondaryHeatExchanger + { + double coldSideTemperatureOffest_dC; + double hotSideTemperatureOffset_dC; + double extraPumpPower_W; + }; + + SecondaryHeatExchanger secondaryHeatExchanger; /**< adjustments for a approximating a secondary + heat exchanger by adding extra input energy for the pump and an increaes in the water to the + incoming waater temperature to the heatpump*/ + + void addTurnOnLogic(std::shared_ptr logic); + void addShutOffLogic(std::shared_ptr logic); + /**< these are two small functions to remove some of the cruft in initiation functions */ + void clearAllTurnOnLogic(); + void clearAllShutOffLogic(); + void clearAllLogic(); + /**< these are two small functions to remove some of the cruft in initiation functions */ + + void changeResistanceWatts(double watts); + /**< function to change the resistance wattage */ + + bool isACompressor() const; + /**< returns if the heat source uses a compressor or not */ + bool isAResistance() const; + /**< returns if the heat source uses a resistance element or not */ + bool isExternalMultipass() const; + + double minT; + /**< minimum operating temperature of HPWH environment */ + + double maxT; + /**< maximum operating temperature of HPWH environment */ + + double maxSetpoint_C; + /**< the maximum setpoint of the heat source can create, used for compressors predominately */ + + double hysteresis_dC; + /**< a hysteresis term that prevents short cycling due to heat pump self-interaction + when the heat source is engaged, it is subtracted from lowT cutoffs and + added to lowTreheat cutoffs */ + + bool depressesTemperature; + /**< heat pumps can depress the temperature of their space in certain instances - + whether or not this occurs is a bool in HPWH, but a heat source must + know if it is capable of contributing to this effect or not + NOTE: this only works for 1 minute steps + ALSO: this is set according the the heat source type, not user-specified */ + + double airflowFreedom; + /**< airflowFreedom is the fraction of full flow. This is used to de-rate compressor + cop (not capacity) for cases where the air flow is restricted - typically ducting */ + + int externalInletHeight; /**getSetpoint(), input_BTUperHr, cap_BTUperHr, cop); + }; + /** An equivalent getCapcity function just for multipass external (or split) HPWHs */ + void getCapacityMP(double externalT_C, + double condenserTemp_C, + double& input_BTUperHr, + double& cap_BTUperHr, + double& cop); + + double calcMPOutletTemperature(double heatingCapacity_KW); + /**< returns the temperature of outlet of a external multipass hpwh */ + + void calcHeatDist(std::vector& heatDistribution); + + double getTankTemp() const; + /**< returns the tank temperature weighted by the condensity for this heat source */ + + void sortPerformanceMap(); + /**< sorts the Performance Map by increasing external temperatures */ + +}; // end of HeatSource class + +constexpr double BTUperKWH = + 3412.14163312794; // https://www.rapidtables.com/convert/energy/kWh_to_BTU.html +constexpr double FperC = 9. / 5.; // degF / degC +constexpr double offsetF = 32.; // degF offset constexpr double sec_per_min = 60.; // seconds / min -constexpr double min_per_hr = 60.; // min / hr +constexpr double min_per_hr = 60.; // min / hr constexpr double sec_per_hr = sec_per_min * min_per_hr; // seconds / hr // a few extra functions for unit conversion @@ -1351,37 +1525,42 @@ inline double FT2_TO_M2(double feet2) { return (feet2 / 10.7640); } inline double MIN_TO_SEC(double minute) { return minute * sec_per_min; } inline double MIN_TO_HR(double minute) { return minute / min_per_hr; } -inline HPWH::DRMODES operator|(HPWH::DRMODES a,HPWH::DRMODES b) +inline HPWH::DRMODES operator|(HPWH::DRMODES a, HPWH::DRMODES b) { - return static_cast(static_cast(a) | static_cast(b)); + return static_cast(static_cast(a) | static_cast(b)); } -template< typename T> inline bool aboutEqual(T a,T b) { return fabs(a - b) < HPWH::TOL_MINVALUE; } +template +inline bool aboutEqual(T a, T b) +{ + return fabs(a - b) < HPWH::TOL_MINVALUE; +} /// Generate an absolute or relative temperature in degC. -inline double convertTempToC(const double T_F_or_C,const HPWH::UNITS units,const bool absolute){ - return (units == HPWH::UNITS_C) ? T_F_or_C : (absolute ? F_TO_C(T_F_or_C) : dF_TO_dC(T_F_or_C)); +inline double convertTempToC(const double T_F_or_C, const HPWH::UNITS units, const bool absolute) +{ + return (units == HPWH::UNITS_C) ? T_F_or_C : (absolute ? F_TO_C(T_F_or_C) : dF_TO_dC(T_F_or_C)); } // resampling utility functions -double getResampledValue(const std::vector &values,double beginFraction,double endFraction); -bool resample(std::vector &values,const std::vector &sampleValues); -inline bool resampleIntensive(std::vector &values,const std::vector &sampleValues) +double +getResampledValue(const std::vector& values, double beginFraction, double endFraction); +bool resample(std::vector& values, const std::vector& sampleValues); +inline bool resampleIntensive(std::vector& values, const std::vector& sampleValues) { - return resample(values,sampleValues); + return resample(values, sampleValues); } -bool resampleExtensive(std::vector &values,const std::vector &sampleValues); +bool resampleExtensive(std::vector& values, const std::vector& sampleValues); /// helper functions -double expitFunc(double x,double offset); -void normalize(std::vector &distribution); -int findLowestNode(const std::vector &nodeDist,const int numTankNodes); -double findShrinkageT_C(const std::vector &nodeDist); -void calcThermalDist( - std::vector &thermalDist, - const double shrinkageT_C, - const int lowestNode, - const std::vector &nodeTemp_C, - const double setpointT_C); +double expitFunc(double x, double offset); +void normalize(std::vector& distribution); +int findLowestNode(const std::vector& nodeDist, const int numTankNodes); +double findShrinkageT_C(const std::vector& nodeDist); +void calcThermalDist(std::vector& thermalDist, + const double shrinkageT_C, + const int lowestNode, + const std::vector& nodeTemp_C, + const double setpointT_C); #endif diff --git a/src/HPWHversion.in.hh b/src/HPWHversion.in.hh index 7adffdc4..b7a093d4 100644 --- a/src/HPWHversion.in.hh +++ b/src/HPWHversion.in.hh @@ -1,13 +1,15 @@ /* -* Version control -*/ + * Version control + */ #ifndef HPWHversion_hh #define HPWHversion_hh +// clang-format off #define HPWHVRSN_MAJOR @HPWHsim_VRSN_MAJOR@ #define HPWHVRSN_MINOR @HPWHsim_VRSN_MINOR@ #define HPWHVRSN_PATCH @HPWHsim_VRSN_PATCH@ #define HPWHVRSN_META "@HPWHsim_VRSN_META@" +// clang-format on #endif