diff --git a/src/CNDTYPES.DEF b/src/CNDTYPES.DEF index 9dc446cbc..a4cee721f 100644 --- a/src/CNDTYPES.DEF +++ b/src/CNDTYPES.DEF @@ -531,6 +531,10 @@ PIPESEGP -- "class PIPESEG*" AWHSTIER4GENERIC50 "AWHSTier4Generic50" // 50-gal tier-4 generic AWHSTIER4GENERIC65 "AWHSTier4Generic65" // 65-gal tier-4 generic AWHSTIER4GENERIC80 "AWHSTier4Generic80" // 80-gal tier-4 generic + + BRADFORDWHITEAEROTHERMRE2H50 "BradfordWhiteAeroThermRE2H50" // 50-gal AeroTherm2023 + BRADFORDWHITEAEROTHERMRE2H65 "BradfordWhiteAeroThermRE2H65" // 65-gal AeroTherm2023 + BRADFORDWHITEAEROTHERMRE2H80 "BradfordWhiteAeroThermRE2H80" // 80-gal AeroTherm2023 } *choicb WHRESTYCH { // resistance heater types diff --git a/src/RCDEF/rcdef.cpp b/src/RCDEF/rcdef.cpp index d56e84c8e..ea0fe9ebf 100644 --- a/src/RCDEF/rcdef.cpp +++ b/src/RCDEF/rcdef.cpp @@ -212,7 +212,7 @@ const int MAXFDREC=600; // Max fields in a record. Separated from MAXFIELDS, 4- const int MAXDTH=600; // max+1 data type handle. 800-->200 1-92 ->400 3-92. ->432(0x1b0) 2-94. ->352 (0x160) 5-95. // 352->400, 1-16; 400->500, 4-16; 500->600, 9-20 -const int MAXDTC=105; // maximum number of choices for choice data type. +const int MAXDTC=108; // maximum number of choices for choice data type. //#define MAXARRAY 20 // largest number of record array structure members * NOT checked, but should be. const int MAXNAMEL = 40; // Max length of name, etc ("s" token) const int MAXQSTRL = 512; // Max length for quoted string ("q" token). assumed >= MAXNAMEL for array allocations. diff --git a/src/dhwcalc.cpp b/src/dhwcalc.cpp index 626bc8f70..a1e15cb3a 100644 --- a/src/dhwcalc.cpp +++ b/src/dhwcalc.cpp @@ -24,6 +24,7 @@ #include "cnguts.h" #include "exman.h" +#include "hvac.h" // CourierMsgHandler, CourierMsgHandlerBase, MessageLevel #include "HPWH.hh" // decls/defns for Ecotope heat pump water heater model @@ -2916,6 +2917,19 @@ void HPWHLINK::hw_HPWHReceiveMessage(const std::string message) } // HPWHLINK::hw_HPWHReceiveMessage //----------------------------------------------------------------------------- +static void HPWHLINK_Callback( // message dispatcher + void *pContext, // pointer to specific RSYS + MSGTY msgTy, // message type: bsxmsgERROR etc + const char *msg) // message text +{ + HPWHLINK *pHPWHLINK = reinterpret_cast(pContext); + + record *pParent = pHPWHLINK->hw_pOwner; + const char *msgx = strtprintf("HPWHLINK: %s", msg); + pParent->ReceiveMessage(msgTy, msgx); + +} // HPWHLINK_Callback +//----------------------------------------------------------------------------- RC HPWHLINK::hw_Init( // 1st initialization record* pOwner) // owner object (DHWHEATER, DHWSOLARSYS, ...) { @@ -2934,10 +2948,8 @@ RC HPWHLINK::hw_Init( // 1st initialization hw_fMixUse = hw_fMixRL = 1.f; - hw_pHPWH = new HPWH(); - - hw_pHPWH->setMessageCallback(hw_HPWHMessageCallback, this); - hw_pHPWH->setVerbosity(HPWH::VRB_reluctant); // messages only for fatal errors + auto MX = std::make_shared(HPWHLINK_Callback, this); + hw_pHPWH = new HPWH(MX); hw_pHPWH->setMinutesPerStep(Top.tp_tickDurMin); // minutesPerStep @@ -2951,11 +2963,8 @@ RC HPWHLINK::hw_InitGeneric( // init HPWH as generic ASHP // default = 7.22, not understood // initialize EF-rated generic HPWH (no preset) { - RC rc = RCOK; - if (hw_pHPWH->initGeneric( - GAL_TO_L(max( vol, 1.f)), EF, resUse) != 0) - rc |= RCBAD; - return rc; + hw_pHPWH->initGeneric(GAL_TO_L(max(vol, 1.f)), EF, resUse); + return RCOK; } // HPWHLINK::hw_InitGeneric //----------------------------------------------------------------------------- RC HPWHLINK::hw_InitResistance( // set up HPWH has EF-rated resistance heater @@ -2970,18 +2979,16 @@ RC HPWHLINK::hw_InitResistance( // set up HPWH has EF-rated resistance heater float resHtPwr2) // lower resistance heat element power, W // returns RCOK iff success { - RC rc = RCOK; - int ret = EF > 0.f - ? hw_pHPWH->initResistanceTank(GAL_TO_L(max(vol, 1.f)), - EF, resHtPwr, resHtPwr2) - : hw_pHPWH->initResistanceTankGeneric(GAL_TO_L(max(vol, 1.f)), - insulR / 5.678f, resHtPwr, resHtPwr2); + if (EF > 0.f) + hw_pHPWH->initResistanceTank(GAL_TO_L(max(vol, 1.f)), EF, resHtPwr, + resHtPwr2); - if (ret) - rc |= RCBAD; + else + hw_pHPWH->initResistanceTankGeneric(GAL_TO_L(max(vol, 1.f)), + insulR / 5.678f, resHtPwr, resHtPwr2); - return rc; + return RCOK; } // HPWHLINK::hw_InitResistance //----------------------------------------------------------------------------- /*static*/ int HPWHLINK::hw_HPWHInfo( @@ -3119,6 +3126,10 @@ RC HPWHLINK::hw_InitResistance( // set up HPWH has EF-rated resistance heater { C_WHASHPTYCH_AWHSTIER4GENERIC65, hwatSMALL | HPWH::MODELS_AWHSTier4Generic65 }, { C_WHASHPTYCH_AWHSTIER4GENERIC80, hwatSMALL | HPWH::MODELS_AWHSTier4Generic80 }, + { C_WHASHPTYCH_BRADFORDWHITEAEROTHERMRE2H50,hwatSMALL | HPWH::MODELS_BradfordWhiteAeroThermRE2H50}, + { C_WHASHPTYCH_BRADFORDWHITEAEROTHERMRE2H65,hwatSMALL | HPWH::MODELS_BradfordWhiteAeroThermRE2H65}, + { C_WHASHPTYCH_BRADFORDWHITEAEROTHERMRE2H80,hwatSMALL | HPWH::MODELS_BradfordWhiteAeroThermRE2H80}, + { 32767, HPWH::MODELS(-1) } }; SI tableVal = presetTbl->lookup(ashpTy); @@ -3168,13 +3179,17 @@ RC HPWHLINK::hw_InitPreset( // set up HPWH from model type choice volX = 80.7f; UAX = 4.7f; } - if (hw_pHPWH->initPreset(preset) != 0) - rc |= RCBAD; - // force modify tank size (avoids tankSizeFixed error) - if (volX > 0.f && hw_pHPWH->setTankSize(volX, HPWH::UNITS_GAL, true) != 0) - rc |= RCBAD; - if (UAX >= 0.f && hw_pHPWH->setUA(UAX, HPWH::UNITS_BTUperHrF) != 0) - rc |= RCBAD; + + hw_pHPWH->initPreset(preset); + + // force modify tank size (avoids tankSizeFixed error) + if (volX > 0.f) { + hw_pHPWH->setTankSize(volX, HPWH::UNITS_GAL, true); + } + + if (UAX >= 0.f) { + hw_pHPWH->setUA(UAX, HPWH::UNITS_BTUperHrF); + } return rc; } // HPWHLINK::hw_InitPreset @@ -3186,15 +3201,11 @@ RC HPWHLINK::hw_InitTank( // init HPWH for use as storage tank // use hw_AdjustUAIf() to set UA // returns RCOK iff success { - RC rc = RCOK; - HPWH::MODELS preset = HPWH::MODELS_StorageTank; + hw_pHPWH->initPreset(preset); + hw_pHPWH->setTankSize(vol, HPWH::UNITS_GAL); - if (hw_pHPWH->initPreset(preset) != 0) - rc |= RCBAD; - if (hw_pHPWH->setTankSize(vol, HPWH::UNITS_GAL) != 0) - rc |= RCBAD; - return rc; + return RCOK; } // HPWHLINK::hw_InitTank //----------------------------------------------------------------------------- RC HPWHLINK::hw_AdjustUAIf( // adjust tank UA @@ -3207,17 +3218,15 @@ RC HPWHLINK::hw_AdjustUAIf( // adjust tank UA // uses current tank surface area (derived from volume) // returns RCOK iff success { - RC rc = RCOK; - if (insulR >= 0.f && UA < 0.f) - { // get total surface area - float surfA = hw_GetTankSurfaceArea( tankCount); + if (insulR >= 0.f && UA < 0.f) { // get total surface area + float surfA = hw_GetTankSurfaceArea(tankCount); UA = surfA / max(insulR, .68f); } - if (UA >= 0.f) - { if (hw_pHPWH->setUA(UA, HPWH::UNITS_BTUperHrF) != 0) - rc |= RCBAD; + if (UA >= 0.f) { + hw_pHPWH->setUA(UA, HPWH::UNITS_BTUperHrF); } - return rc; + + return RCOK; } // HPWHLINK::hw_AdjustUAIf //----------------------------------------------------------------------------- RC HPWHLINK::hw_InitFinalize( // final initialization actions @@ -3227,40 +3236,42 @@ RC HPWHLINK::hw_InitFinalize( // final initialization actions RC rc = RCOK; // tank inlet placement - if (inHtSupply >= 0.f) - hw_pHPWH->setInletByFraction( inHtSupply); - if (inHtLoopRet >= 0.f) - hw_pHPWH->setInlet2ByFraction( inHtLoopRet); - - // make map of heat sources = idxs for hw_HPWHUse[] - // WHY: HPWH model frequently uses 3 heat sources in - // preset-specific order - hw_HSCount = hw_pHPWH->getNumHeatSources(); - delete hw_HSMap; // insurance: delete any pre-existing - if (hw_HSCount == 0) - hw_HSMap = NULL; - else - { hw_HSMap = new int[hw_HSCount]; - if (!hw_HasCompressor()) - // no compressor, all use is primary - VSet(hw_HSMap, hw_HSCount, 0); - else for (int iHS = 0; iHS < hw_HSCount; iHS++) - { - HPWH::HEATSOURCE_TYPE hsTy = hw_pHPWH->getNthHeatSourceType(iHS); - hw_HSMap[iHS] = hsTy == HPWH::TYPE_resistance; - // primary ( =compressor) + anything else -> hw_inElec[ 0] - // resistance use -> hw_inElec[ 1] - } - } + if (inHtSupply >= 0.f) + hw_pHPWH->setInletByFraction(inHtSupply); + if (inHtLoopRet >= 0.f) + hw_pHPWH->setInlet2ByFraction(inHtLoopRet); + + // make map of heat sources = idxs for hw_HPWHUse[] + // WHY: HPWH model frequently uses 3 heat sources in + // preset-specific order + hw_HSCount = hw_pHPWH->getNumHeatSources(); + delete hw_HSMap; // insurance: delete any pre-existing + if (hw_HSCount == 0) + hw_HSMap = NULL; + else { + hw_HSMap = new int[hw_HSCount]; + if (!hw_HasCompressor()) + // no compressor, all use is primary + VSet(hw_HSMap, hw_HSCount, 0); + else + for (int iHS = 0; iHS < hw_HSCount; iHS++) { + HPWH::HEATSOURCE_TYPE hsTy = + hw_pHPWH->getNthHeatSourceType(iHS); + hw_HSMap[iHS] = hsTy == HPWH::TYPE_resistance; + // primary ( =compressor) + anything else -> hw_inElec[ 0] + // resistance use -> hw_inElec[ 1] + } + } + + // nominal tank heat content, kWh + hw_tankHCNominal = + KJ_TO_KWH(40. * HPWH::DENSITYWATER_kgperL * + HPWH::CPWATER_kJperkgC * hw_pHPWH->getTankSize()); + + // end-of-step heat content + hw_tankHCEnd = 0.; // insurance, triggers later initialization - // nominal tank heat content, kWh - hw_tankHCNominal = KJ_TO_KWH(40. * HPWH::DENSITYWATER_kgperL * HPWH::CPWATER_kJperkgC - * hw_pHPWH->getTankSize()); - - // end-of-step heat content - hw_tankHCEnd = 0.; // insurance, triggers later initialization - - return rc; + return RCOK; } // HPWHLINK::hw_InitFinalize //----------------------------------------------------------------------------- @@ -3273,37 +3284,24 @@ RC HPWHLINK::hw_SetHeatingCap( // set heating capacity // sets both compressor and resistance (if any) power // returns RCOK iff success { - RC rc = RCOK; + double minT = hw_pHPWH->getMinOperatingTemp(HPWH::UNITS_F); + if (ashpTSrcDes < minT) + ashpTSrcDes = minT; // constrain source air temp to + // HPWH lockout temp - int hpwhRet = 0; - double minT = hw_pHPWH->getMinOperatingTemp(HPWH::UNITS_F); - if (minT == double(HPWH::HPWH_ABORT)) - ++hpwhRet; - else - { if (ashpTSrcDes < minT) - ashpTSrcDes = minT; // constrain source air temp to - // HPWH lockout temp - - // set compressor capacity at design conditions - hpwhRet = hw_pHPWH->setCompressorOutputCapacity( - heatingCap, - ashpTSrcDes, // design source air temp, F - tInletDes, // inlet temp, F - tUseDes, // outlet temp, F - HPWH::UNITS_BTUperHr, HPWH::UNITS_F); - - if (!hpwhRet) - // set capacity of all reistance elements to design cap - // (handles e.g. possible low-temp lockout) - hpwhRet = hw_pHPWH->setResistanceCapacity( heatingCap, 0, HPWH::UNITS_BTUperHr); - } - if (hpwhRet) - // unexpected HPWH error (inconsistent HPWH::isHPWHScalable() logic?) - // isHPWHScalable() checked in wh_HPWHInit() - rc = hw_pOwner->oer("Program error (HPWHLINK::hw_SetHeatingCap): HPWH error"); + // set compressor capacity at design conditions + hw_pHPWH->setCompressorOutputCapacity( + heatingCap, + ashpTSrcDes, // design source air temp, F + tInletDes, // inlet temp, F + tUseDes, // outlet temp, F + HPWH::UNITS_BTUperHr, HPWH::UNITS_F); - return rc; + // set capacity of all reistance elements to design cap + // (handles e.g. possible low-temp lockout) + hw_pHPWH->setResistanceCapacity(heatingCap, 0, HPWH::UNITS_BTUperHr); + return RCOK; } // HPWHLINK::hw_SetHeatingCap //----------------------------------------------------------------------------- RC HPWHLINK::hw_GetHeatingCap( // get heating capacity @@ -3314,43 +3312,38 @@ RC HPWHLINK::hw_GetHeatingCap( // get heating capacity // returns RCOK and heatingCap iff success // else RCBAD (heatingCap = 0) { - RC rc = RCOK; heatingCap = 0.f; if (!hw_pHPWH) return RCBAD; // bad setup + double cap = 0.; - if (hw_pHPWH->hasACompressor()) - { double minT = hw_pHPWH->getMinOperatingTemp(HPWH::UNITS_F); - if (minT == double(HPWH::HPWH_ABORT)) - rc = RCBAD; - else - { - if (ashpTSrcDes < minT) - ashpTSrcDes = minT; // constrain source air temp to - // HPWH lockout temp - - cap = hw_pHPWH->getCompressorCapacity( - ashpTSrcDes, // design source air temp, F - tInletDes, // inlet temp, F - tUseDes, // outlet temp, F - HPWH::UNITS_BTUperHr, HPWH::UNITS_F); - if (cap == double(HPWH::HPWH_ABORT)) - rc = RCBAD; - } - } - else - { // resistance: return capacity of largest heating element - // TODO: recode to return max when HPWH is fixed - int nRE = hw_pHPWH->getNumResistanceElements(); - for (int iRE = 0; iRE < nRE; iRE++) - { double capx = hw_pHPWH->getResistanceCapacity(iRE, HPWH::UNITS_BTUperHr); - if (capx != double(HPWH::HPWH_ABORT) && capx > cap) - cap = capx; - } - } - if (!rc) - heatingCap = float(cap); - return rc; + if (hw_pHPWH->hasACompressor()) { + double minT = hw_pHPWH->getMinOperatingTemp(HPWH::UNITS_F); + + if (ashpTSrcDes < minT) + ashpTSrcDes = minT; // constrain source air temp to + // HPWH lockout temp + + cap = hw_pHPWH->getCompressorCapacity( + ashpTSrcDes, // design source air temp, F + tInletDes, // inlet temp, F + tUseDes, // outlet temp, F + HPWH::UNITS_BTUperHr, HPWH::UNITS_F); + } + + else { // resistance: return capacity of largest heating element + // TODO: recode to return max when HPWH is fixed + int nRE = hw_pHPWH->getNumResistanceElements(); + for (int iRE = 0; iRE < nRE; iRE++) { + double capx = + hw_pHPWH->getResistanceCapacity(iRE, HPWH::UNITS_BTUperHr); + if (capx > cap) + cap = capx; + } + } + heatingCap = float(cap); + + return RCOK; } // HPWHLINK::hw_GetHeatingCap //----------------------------------------------------------------------------- RC HPWHLINK::hw_GetInfo( // return HPWH tank values @@ -3360,20 +3353,18 @@ RC HPWHLINK::hw_GetInfo( // return HPWH tank values float tankCount /*=1.f*/) const // # of tanks // returns RC iff success { - RC rc = RCOK; - vol = hw_pHPWH->getTankSize(HPWH::UNITS_GAL); - double UAd; - if (hw_pHPWH->getUA(UAd, HPWH::UNITS_BTUperHrF) != 0) - rc |= RCBAD; - UA = float(UAd); + vol = hw_pHPWH->getTankSize(HPWH::UNITS_GAL); - // surface area: account for multiple tanks - float surfA = hw_GetTankSurfaceArea( tankCount, vol); + double UAd; + hw_pHPWH->getUA(UAd, HPWH::UNITS_BTUperHrF); + UA = float(UAd); - insulR = UA > 0. ? surfA / UA : 1.e6f; + // surface area: account for multiple tanks + float surfA = hw_GetTankSurfaceArea(tankCount, vol); - return rc; + insulR = UA > 0. ? surfA / UA : 1.e6f; + return RCOK; } // HPWHLINK::hw_GetInfo //----------------------------------------------------------------------------- float HPWHLINK::hw_GetTankSurfaceArea( // tank surface area @@ -3383,12 +3374,12 @@ float HPWHLINK::hw_GetTankSurfaceArea( // tank surface area // returns total tank surface area, ft2 // (accounting for possible multiple tanks) { - if (vol < 0) - vol = hw_pHPWH->getTankSize(HPWH::UNITS_GAL); - float volPerTank = vol / tankCount; - double surfAPerTank = HPWH::getTankSurfaceArea(volPerTank, HPWH::UNITS_GAL, HPWH::UNITS_FT2); - float surfA = surfAPerTank * tankCount; - return surfA; + if (vol < 0) + vol = hw_pHPWH->getTankSize(HPWH::UNITS_GAL); + float volPerTank = vol / tankCount; + double surfAPerTank = + HPWH::getTankSurfaceArea(volPerTank, HPWH::UNITS_GAL, HPWH::UNITS_FT2); + return surfAPerTank * tankCount; } // HPWHLINK::hw_GetTankSurfaceArea //----------------------------------------------------------------------------- RC HPWHLINK::hw_DeriveVolFromVolRunning( // calc required volume from running vol @@ -3400,35 +3391,32 @@ RC HPWHLINK::hw_DeriveVolFromVolRunning( // calc required volume from running v // Does not actually set volume // returns RCOK iff success { - RC rc = RCOK; - // retrieve tank volume fractions // apply insurance (crash-proof) limits double aquaFract; // fraction of volume below aquastat double useableFract; // fraction of volume that is useable - if (hw_pHPWH->getSizingFractions(aquaFract, useableFract) != 0) - { rc |= RCBAD; - aquaFract = .4f; // plausible values - useableFract = .9f; - } - useableFract = bracket(.6, useableFract, 1.); - double unuseableFract = 1. - useableFract; - aquaFract = bracket(unuseableFract + .1, aquaFract, .75); - // total volume req'd based on aquastat position - // Running vol is vol above aquastat - float totVolRun = float(volRunning / (1. - aquaFract)); + hw_pHPWH->getSizingFractions(aquaFract, useableFract); + useableFract = bracket(.6, useableFract, 1.); + double unuseableFract = 1. - useableFract; + aquaFract = bracket(unuseableFract + .1, aquaFract, .75); - // total volume req'd based on minimum run time (avoid short cycle) - // Determine vol of water heated in minimum compressor cycle. - // Usable volume below aquastat must be >= to this vol - float runHrMin = hw_pHPWH->getCompressorMinRuntime( HPWH::UNITS_HR); // minimum compressor run time, hr - float volCycMin = heatingCap * runHrMin / (waterRhoCp * max(tempRise, 10.f)); - float totVolCyc = volCycMin / (aquaFract - unuseableFract); + // total volume req'd based on aquastat position + // Running vol is vol above aquastat + float totVolRun = float(volRunning / (1. - aquaFract)); - totVol = max(totVolRun, totVolCyc); // caller must set volume + // total volume req'd based on minimum run time (avoid short cycle) + // Determine vol of water heated in minimum compressor cycle. + // Usable volume below aquastat must be >= to this vol + float runHrMin = hw_pHPWH->getCompressorMinRuntime( + HPWH::UNITS_HR); // minimum compressor run time, hr + float volCycMin = + heatingCap * runHrMin / (waterRhoCp * max(tempRise, 10.f)); + float totVolCyc = volCycMin / (aquaFract - unuseableFract); - return rc; + totVol = max(totVolRun, totVolCyc); // caller must set volume + + return RCOK; } // HPWHLINK::hw_DeriveVolFromVolRunning //----------------------------------------------------------------------------- @@ -3477,9 +3465,10 @@ double HPWHLINK::hw_GetTankAvgTemp( // average temp of range of tank nodes int incr = nNodes < 0 ? -1 : 1; double T = 0.; - for (int iN=iNode0; iN != iNodeN; iN+=incr) - T += hw_pHPWH->getTankNodeTemp(iN, HPWH::UNITS_C); - T /= max(1, abs(iNodeN - iNode0)); + for (int iN = iNode0; iN != iNodeN; iN += incr) + T += hw_pHPWH->getTankNodeTemp(iN, HPWH::UNITS_C); + T /= max(1, abs(iNodeN - iNode0)); + return DegCtoF(T); } // HPWHLINK::hw_GetTankAvgTemp //----------------------------------------------------------------------------- @@ -3487,7 +3476,7 @@ double HPWHLINK::hw_GetEstimatedTOut() const // returns estimate of tank output temp, F // = current top node temp (no consideration of draw etc.) { - int iNodeTop = hw_pHPWH->getNumNodes() - 1; + int iNodeTop = hw_pHPWH->getNumNodes() - 1; return hw_pHPWH->getTankNodeTemp(iNodeTop, HPWH::UNITS_F); } // HPWHLINK::hw_GetEstimatedTOut //----------------------------------------------------------------------------- @@ -3515,57 +3504,50 @@ RC HPWHLINK::hw_DoHour( // hourly HPWH calcs // Does HPWH setup etc that need not be done subhourly // returns RCOK iff success { - RC rc = RCOK; - if (Top.tp_isBegMainSim) hw_balErrCount = 0; // setpoint temp: ws_tUse has hourly variability // some HPWHs (e.g. SANCO2) have fixed setpoints, don't attempt - if (!hw_pHPWH->isSetpointFixed()) - { double tSetpointMax; - std::string whyNot; // HPWH explanatory text, ignored - bool bSPP = hw_pHPWH->isNewSetpointPossible(tSetpoint, tSetpointMax, whyNot, HPWH::UNITS_F); - // silently limit to max acceptable - // if HPWH has resistance, max = 212 - float tSetpointX = bSPP ? tSetpoint : tSetpointMax; - hw_pHPWH->setSetpoint(tSetpointX, HPWH::UNITS_F); - } - - // retrieve resulting setpoint after HPWH restrictions - tSetpoint = hw_pHPWH->getSetpoint(HPWH::UNITS_F); - if (hw_tHWOut == 0.f) - hw_tHWOut = tSetpoint; // initial guess for HW output temp - // updated every substep with nz draw - - // tank temp initialization - if (!hw_tankTempSet) - { // initialize tank temp on 1st call - // must be done after setting HPWH setpoint (=ws_tSetpoint) - // (ws_tSetpoint may be expression) - if (tankTInit != nullptr) - { - std::vector vTankTInit; - vTankTInit.assign(tankTInit, tankTInit + 12); - if (hw_pHPWH->setTankLayerTemperatures(vTankTInit, HPWH::UNITS_F)) - rc |= RCBAD; - } - else - { - if (hw_pHPWH->resetTankToSetpoint()) - rc |= RCBAD; - } - hw_tankTempSet = true; - } - - // state of charge (SoO) controls - if (hw_pHPWH->isSoCControlled()) - { - if (hw_pHPWH->setTargetSoCFraction(targetSoC)) - rc |= RCBAD; - } + if (!hw_pHPWH->isSetpointFixed()) { + double tSetpointMax; + std::string whyNot; // HPWH explanatory text, ignored + bool bSPP = hw_pHPWH->isNewSetpointPossible(tSetpoint, tSetpointMax, + whyNot, HPWH::UNITS_F); + // silently limit to max acceptable + // if HPWH has resistance, max = 212 + float tSetpointX = bSPP ? tSetpoint : tSetpointMax; + hw_pHPWH->setSetpoint(tSetpointX, HPWH::UNITS_F); + } + + // retrieve resulting setpoint after HPWH restrictions + tSetpoint = hw_pHPWH->getSetpoint(HPWH::UNITS_F); + if (hw_tHWOut == 0.f) + hw_tHWOut = tSetpoint; // initial guess for HW output temp + // updated every substep with nz draw + + // tank temp initialization + if (!hw_tankTempSet) { + // initialize tank temp on 1st call + // must be done after setting HPWH setpoint (=ws_tSetpoint) + // (ws_tSetpoint may be expression) + if (tankTInit != nullptr) { + std::vector vTankTInit; + vTankTInit.assign(tankTInit, tankTInit + 12); + hw_pHPWH->setTankLayerTemperatures(vTankTInit, HPWH::UNITS_F); + + } else { + hw_pHPWH->resetTankToSetpoint(); + } + hw_tankTempSet = true; + } + + // state of charge (SoO) controls + if (hw_pHPWH->isSoCControlled()) { + hw_pHPWH->setTargetSoCFraction(targetSoC); + } - return rc; + return RCOK; } // HPWHLINK::hw_DoHour //----------------------------------------------------------------------------- @@ -3733,24 +3715,23 @@ RC HPWHLINK::hw_DoSubhrTick( // calcs for 1 tick pNPX = &hw_pNodePowerExtra_W; } - int hpwhRet = hw_pHPWH->runOneStep( - DegFtoC(tInlet), // inlet temp, C - GAL_TO_L(drawForTick), // draw volume, L - DegFtoC(hw_tEx), // ambient T (=tank surround), C - DegFtoC(hw_tASHPSrc), // heat source T, C - // aka HPWH "external temp" - HPWH::DRMODES( drStatus), // DRstatus: demand response signal - GAL_TO_L(drawRC), DegFtoC(tRC), // 2ndary draw for DHWLOOP and CHDHW - // note drawForTick includes drawRC - pNPX); // additional node power (re e.g. solar tanks) - - if (hpwhRet) // 0 means success - rc |= RCBAD; - - hw_qEnv += hw_pHPWH->getEnergyRemovedFromEnvironment(); - hw_qLoss += hw_pHPWH->getStandbyLosses(); - float HPWHxBU = 0.f; // add'l resistance backup, this tick, Btu - hw_tOut = hw_pHPWH->getOutletTemp(); // output temp, C (0 if no draw) + hw_pHPWH->runOneStep( + DegFtoC(tInlet), // inlet temp, C + GAL_TO_L(drawForTick), // draw volume, L + DegFtoC(hw_tEx), // ambient T (=tank surround), C + DegFtoC(hw_tASHPSrc), // heat source T, C + // aka HPWH "external temp" + HPWH::DRMODES(drStatus), // DRstatus: demand response signal + GAL_TO_L(drawRC), + DegFtoC(tRC), // 2ndary draw for DHWLOOP and CHDHW + // note drawForTick includes drawRC + pNPX); // additional node power (re e.g. solar tanks) + + hw_qEnv += hw_pHPWH->getEnergyRemovedFromEnvironment(); + hw_qLoss += hw_pHPWH->getStandbyLosses(); + hw_tOut = hw_pHPWH->getOutletTemp(); // output temp, C (0 if no draw) + + float HPWHxBU = 0.f; // add'l resistance backup, this tick, Btu #if 0 printf("\n%d HPWH drawCHDHW=%0.4f tOut=%0.1f", Top.iSubhr, drawRC, hw_tOut); #endif @@ -4706,16 +4687,14 @@ RC DHWHEATER::wh_HPWHInit() // initialize HPWH model else { double tMin = 110.f; - int ret = wh_HPWH.hw_pHPWH->switchToSoCControls( - 0.9, // initial target SoC (altered hourly, see DHWHEATER::wh_DoHour()) - 0.05, // hysteresis - tMin, // reference temp (= min useful temp) - false, // mains temp varies - 55., // placeholder mains temp - HPWH::UNITS_F); // temps are F - - if (ret != 0) - rc |= oer("HPWH::switchToSoCControls() failed."); + wh_HPWH.hw_pHPWH->switchToSoCControls( + 0.9, // initial target SoC (altered hourly, see + // DHWHEATER::wh_DoHour()) + 0.05, // hysteresis + tMin, // reference temp (= min useful temp) + false, // mains temp varies + 55., // placeholder mains temp + HPWH::UNITS_F); // temps are F } } diff --git a/vendor/HPWHsim b/vendor/HPWHsim index 2c3b1992e..b816b0c76 160000 --- a/vendor/HPWHsim +++ b/vendor/HPWHsim @@ -1 +1 @@ -Subproject commit 2c3b1992ee2322c3024286c478908d75d9d1b00b +Subproject commit b816b0c768b7a8c30da2edd0737c015dd3380d37