LCOV - code coverage report
Current view: top level - EnergyPlus - WaterThermalTanks.cc (source / functions) Coverage Total Hit
Test: lcov.output.filtered Lines: 48.6 % 6513 3164
Test Date: 2025-05-22 16:09:37 Functions: 70.0 % 70 49

            Line data    Source code
       1              : // EnergyPlus, Copyright (c) 1996-2025, The Board of Trustees of the University of Illinois,
       2              : // The Regents of the University of California, through Lawrence Berkeley National Laboratory
       3              : // (subject to receipt of any required approvals from the U.S. Dept. of Energy), Oak Ridge
       4              : // National Laboratory, managed by UT-Battelle, Alliance for Sustainable Energy, LLC, and other
       5              : // contributors. All rights reserved.
       6              : //
       7              : // NOTICE: This Software was developed under funding from the U.S. Department of Energy and the
       8              : // U.S. Government consequently retains certain rights. As such, the U.S. Government has been
       9              : // granted for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable,
      10              : // worldwide license in the Software to reproduce, distribute copies to the public, prepare
      11              : // derivative works, and perform publicly and display publicly, and to permit others to do so.
      12              : //
      13              : // Redistribution and use in source and binary forms, with or without modification, are permitted
      14              : // provided that the following conditions are met:
      15              : //
      16              : // (1) Redistributions of source code must retain the above copyright notice, this list of
      17              : //     conditions and the following disclaimer.
      18              : //
      19              : // (2) Redistributions in binary form must reproduce the above copyright notice, this list of
      20              : //     conditions and the following disclaimer in the documentation and/or other materials
      21              : //     provided with the distribution.
      22              : //
      23              : // (3) Neither the name of the University of California, Lawrence Berkeley National Laboratory,
      24              : //     the University of Illinois, U.S. Dept. of Energy nor the names of its contributors may be
      25              : //     used to endorse or promote products derived from this software without specific prior
      26              : //     written permission.
      27              : //
      28              : // (4) Use of EnergyPlus(TM) Name. If Licensee (i) distributes the software in stand-alone form
      29              : //     without changes from the version obtained under this License, or (ii) Licensee makes a
      30              : //     reference solely to the software portion of its product, Licensee must refer to the
      31              : //     software as "EnergyPlus version X" software, where "X" is the version number Licensee
      32              : //     obtained under this License and may not use a different name for the software. Except as
      33              : //     specifically required in this Section (4), Licensee shall not use in a company name, a
      34              : //     product name, in advertising, publicity, or other promotional activities any name, trade
      35              : //     name, trademark, logo, or other designation of "EnergyPlus", "E+", "e+" or confusingly
      36              : //     similar designation, without the U.S. Department of Energy's prior written consent.
      37              : //
      38              : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
      39              : // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
      40              : // AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
      41              : // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
      42              : // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
      43              : // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      44              : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
      45              : // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
      46              : // POSSIBILITY OF SUCH DAMAGE.
      47              : 
      48              : // ObjexxFCL Headers
      49              : #include <ObjexxFCL/Array.functions.hh>
      50              : #include <ObjexxFCL/floops.hh>
      51              : #include <ObjexxFCL/member.functions.hh>
      52              : 
      53              : // EnergyPlus Headers
      54              : #include <EnergyPlus/Autosizing/Base.hh>
      55              : #include <EnergyPlus/BranchNodeConnections.hh>
      56              : #include <EnergyPlus/Coils/CoilCoolingDX.hh>
      57              : #include <EnergyPlus/CurveManager.hh>
      58              : #include <EnergyPlus/DXCoils.hh>
      59              : #include <EnergyPlus/Data/EnergyPlusData.hh>
      60              : #include <EnergyPlus/DataBranchAirLoopPlant.hh>
      61              : #include <EnergyPlus/DataGlobalConstants.hh>
      62              : #include <EnergyPlus/DataHVACGlobals.hh>
      63              : #include <EnergyPlus/DataHeatBalance.hh>
      64              : #include <EnergyPlus/DataIPShortCuts.hh>
      65              : #include <EnergyPlus/DataLoopNode.hh>
      66              : #include <EnergyPlus/DataSizing.hh>
      67              : #include <EnergyPlus/DataZoneEquipment.hh>
      68              : #include <EnergyPlus/Fans.hh>
      69              : #include <EnergyPlus/FluidProperties.hh>
      70              : #include <EnergyPlus/General.hh>
      71              : #include <EnergyPlus/GeneralRoutines.hh>
      72              : #include <EnergyPlus/GlobalNames.hh>
      73              : #include <EnergyPlus/HeatBalanceInternalHeatGains.hh>
      74              : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
      75              : #include <EnergyPlus/IntegratedHeatPump.hh>
      76              : #include <EnergyPlus/NodeInputManager.hh>
      77              : #include <EnergyPlus/OutAirNodeManager.hh>
      78              : #include <EnergyPlus/OutputProcessor.hh>
      79              : #include <EnergyPlus/OutputReportPredefined.hh>
      80              : #include <EnergyPlus/PhotovoltaicThermalCollectors.hh>
      81              : #include <EnergyPlus/Plant/DataPlant.hh>
      82              : #include <EnergyPlus/Plant/PlantLocation.hh>
      83              : #include <EnergyPlus/PlantUtilities.hh>
      84              : #include <EnergyPlus/Psychrometrics.hh>
      85              : #include <EnergyPlus/RefrigeratedCase.hh>
      86              : #include <EnergyPlus/ScheduleManager.hh>
      87              : #include <EnergyPlus/SolarCollectors.hh>
      88              : #include <EnergyPlus/VariableSpeedCoils.hh>
      89              : #include <EnergyPlus/WaterThermalTanks.hh>
      90              : #include <EnergyPlus/WaterToAirHeatPumpSimple.hh>
      91              : #include <EnergyPlus/ZoneTempPredictorCorrector.hh>
      92              : 
      93              : namespace EnergyPlus::WaterThermalTanks {
      94              : 
      95              : // MODULE INFORMATION:
      96              : //       AUTHOR         Brandon Anderson
      97              : //       DATE WRITTEN   May 2000
      98              : //       MODIFIED       Feb 2005, PGE; July 2005, FSEC - added HPWH's and desuperheater water heating coils
      99              : //                      Jan 2007, PGE - added stratified water heater
     100              : //                      Oct 2007, BTG - extended for indirect water heater
     101              : //                      May 2008, Stovall - added desup from condenser and removed double counting
     102              : //                           (includes "d0"s from revision 145)
     103              : //                       Nov 2011, BAN; corrected use and source outlet temp. calculation of stratified tank
     104              : //       RE-ENGINEERED  Feb 2004, PGE
     105              : //                      Sep 2008, BTG - refactored, was PlantWaterHeater.cc is now PlantWaterThermalTank.cc
     106              : //                                 reuse water heater code for chilled water storage
     107              : 
     108              : // PURPOSE OF THIS MODULE:
     109              : // This module simulates water thermal storage tanks heaters in the plant loop.  Tanks can
     110              : // be positioned as supply side equipment or demand side equipment.  Water heater versions can be stand-alone as
     111              : // non-zone equipment.
     112              : 
     113              : // METHODOLOGY EMPLOYED:
     114              : // Two water thermal tank models are implemented, MIXED and STRATIFIED with hot and cold versions of each:
     115              : // WaterHeater:Mixed simulates a well-mixed, single-node tank for hot water applications.  Source (e.g. heat recovery) and
     116              : // use plant connections are allowed.  A scheduled domestic hot water demand can also be specified
     117              : // to directly utilize the hot water without use side connections.
     118              : // WaterHeater:Stratified simulates a stratified, multi-node tank for hot water applications.
     119              : // The model shares most of the same capabilities as WaterHeater:Mixed
     120              : // but also has up to two heating elements which can be operated in
     121              : // a master-slave mode or simultaneous mode.
     122              : 
     123              : // ThermalStorage:ChilledWater:Mixed simulates a well-mixed, single-node tank for chilled water applications
     124              : 
     125              : // ThermalStorage:ChilledWater:Stratified simulates a stratified, multi-node tank for chilled water applications.
     126              : 
     127              : std::string const cMixedWHModuleObj = "WaterHeater:Mixed";
     128              : std::string const cStratifiedWHModuleObj = "WaterHeater:Stratified";
     129              : std::string const cMixedCWTankModuleObj = "ThermalStorage:ChilledWater:Mixed";
     130              : std::string const cStratifiedCWTankModuleObj = "ThermalStorage:ChilledWater:Stratified";
     131              : std::string const cHPWHPumpedCondenser = "WaterHeater:HeatPump:PumpedCondenser";
     132              : std::string const cHPWHWrappedCondenser = "WaterHeater:HeatPump:WrappedCondenser";
     133              : std::string const cCoilDesuperheater = "Coil:WaterHeating:Desuperheater";
     134              : 
     135            0 : PlantComponent *WaterThermalTankData::factory(EnergyPlusData &state, std::string const &objectName)
     136              : {
     137              :     // Process the input data
     138            0 :     if (state.dataWaterThermalTanks->getWaterThermalTankInputFlag) {
     139            0 :         GetWaterThermalTankInput(state);
     140            0 :         state.dataWaterThermalTanks->getWaterThermalTankInputFlag = false;
     141              :     }
     142              : 
     143              :     // Now look for this object in the list
     144            0 :     for (auto &tank : state.dataWaterThermalTanks->WaterThermalTank) {
     145            0 :         if (tank.Name == objectName) {
     146            0 :             return &tank;
     147              :         }
     148              :     }
     149              :     // If we didn't find it, fatal
     150              :     ShowFatalError(state, format("LocalWaterTankFactory: Error getting inputs for tank named: {}", objectName)); // LCOV_EXCL_LINE
     151              :     // Shut up the compiler
     152              :     return nullptr; // LCOV_EXCL_LINE
     153              : }
     154              : 
     155            1 : void WaterThermalTankData::onInitLoopEquip(EnergyPlusData &state, const PlantLocation &calledFromLocation)
     156              : {
     157            1 :     this->initialize(state, true);
     158            1 :     this->MinePlantStructForInfo(state);
     159            1 :     if (calledFromLocation.loopNum > 0) {
     160            1 :         if ((this->SrcSidePlantLoc.loopNum == calledFromLocation.loopNum) || (this->UseSidePlantLoc.loopNum == calledFromLocation.loopNum)) {
     161            1 :             this->SizeTankForDemandSide(state);
     162            1 :             this->SizeDemandSidePlantConnections(state);
     163            1 :             this->SizeSupplySidePlantConnections(state, calledFromLocation.loopNum);
     164            1 :             this->SizeTankForSupplySide(state);
     165              :         } else {
     166            0 :             return;
     167              :         }
     168              :     } else {
     169            0 :         this->SizeTankForDemandSide(state);
     170            0 :         this->SizeDemandSidePlantConnections(state);
     171            0 :         this->SizeSupplySidePlantConnections(state, this->SrcSidePlantLoc.loopNum);
     172            0 :         this->SizeTankForSupplySide(state);
     173              :     }
     174              : 
     175            1 :     if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
     176            1 :         if (!this->IsChilledWaterTank) {
     177            1 :             this->CalcStandardRatings(state);
     178              :         } else {
     179            0 :             this->ReportCWTankInits(state);
     180              :         }
     181              :     }
     182              : }
     183              : 
     184            0 : void WaterThermalTankData::getDesignCapacities([[maybe_unused]] EnergyPlusData &state,
     185              :                                                [[maybe_unused]] const PlantLocation &calledFromLocation,
     186              :                                                Real64 &MaxLoad,
     187              :                                                Real64 &MinLoad,
     188              :                                                Real64 &OptLoad)
     189              : {
     190            0 :     MinLoad = 0.0;
     191            0 :     MaxLoad = this->MaxCapacity;
     192            0 :     OptLoad = this->MaxCapacity;
     193            0 : }
     194              : 
     195            0 : int getTankIDX(EnergyPlusData &state, std::string_view CompName, int &CompIndex)
     196              : {
     197            0 :     if (state.dataWaterThermalTanks->getWaterThermalTankInputFlag) {
     198            0 :         GetWaterThermalTankInput(state);
     199            0 :         state.dataWaterThermalTanks->getWaterThermalTankInputFlag = false;
     200              :     }
     201              : 
     202              :     int CompNum;
     203              : 
     204            0 :     if (CompIndex == 0) {
     205            0 :         CompNum = Util::FindItem(CompName, state.dataWaterThermalTanks->WaterThermalTank);
     206            0 :         if (CompNum == 0) {
     207            0 :             ShowFatalError(state, format("SimWaterThermalTank_WaterTank:  Unit not found={}", CompName));
     208              :         }
     209            0 :         CompIndex = CompNum;
     210              :     } else {
     211            0 :         CompNum = CompIndex;
     212            0 :         if (CompNum > state.dataWaterThermalTanks->numWaterThermalTank || CompNum < 1) {
     213            0 :             ShowFatalError(state,
     214            0 :                            format("SimWaterThermalTank_WaterTank:  Invalid CompIndex passed={}, Number of Units={}, Entered Unit name={}",
     215              :                                   CompNum,
     216            0 :                                   state.dataWaterThermalTanks->numWaterThermalTank,
     217              :                                   CompName));
     218              :         }
     219            0 :         if (state.dataWaterThermalTanks->WaterThermalTank(CompNum).CheckWTTEquipName) {
     220            0 :             if (CompName != state.dataWaterThermalTanks->WaterThermalTank(CompNum).Name) {
     221            0 :                 ShowFatalError(state,
     222            0 :                                format("SimWaterThermalTank_WaterTank: Invalid CompIndex passed={}, Unit name={}, stored Unit Name for that index={}",
     223              :                                       CompNum,
     224              :                                       CompName,
     225            0 :                                       state.dataWaterThermalTanks->WaterThermalTank(CompNum).Name));
     226              :             }
     227            0 :             state.dataWaterThermalTanks->WaterThermalTank(CompNum).CheckWTTEquipName = false;
     228              :         }
     229              :     }
     230              : 
     231            0 :     return CompNum;
     232              : }
     233              : 
     234            0 : int getHPTankIDX(EnergyPlusData &state, std::string_view CompName, int &CompIndex)
     235              : {
     236            0 :     if (state.dataWaterThermalTanks->getWaterThermalTankInputFlag) {
     237            0 :         GetWaterThermalTankInput(state);
     238            0 :         state.dataWaterThermalTanks->getWaterThermalTankInputFlag = false;
     239              :     }
     240              : 
     241              :     int CompNum;
     242              : 
     243            0 :     if (CompIndex == 0) {
     244            0 :         CompNum = Util::FindItem(CompName, state.dataWaterThermalTanks->HPWaterHeater);
     245            0 :         if (CompNum == 0) {
     246            0 :             ShowFatalError(state, format("SimWaterThermalTank_HeatPump:  Unit not found={}", CompName));
     247              :         }
     248            0 :         CompIndex = CompNum;
     249              :     } else {
     250            0 :         CompNum = CompIndex;
     251            0 :         if (CompNum > state.dataWaterThermalTanks->numWaterThermalTank || CompNum < 1) {
     252            0 :             ShowFatalError(state,
     253            0 :                            format("SimWaterThermalTank_HeatPump:  Invalid CompIndex passed={}, Number of Units={}, Entered Unit name={}",
     254              :                                   CompNum,
     255            0 :                                   state.dataWaterThermalTanks->numHeatPumpWaterHeater,
     256              :                                   CompName));
     257              :         }
     258            0 :         if (state.dataWaterThermalTanks->HPWaterHeater(CompNum).CheckHPWHEquipName) {
     259            0 :             if (CompName != state.dataWaterThermalTanks->HPWaterHeater(CompNum).Name) {
     260            0 :                 ShowFatalError(state,
     261            0 :                                format("SimWaterThermalTank_HeatPump: Invalid CompIndex passed={}, Unit name={}, stored Unit Name for that index={}",
     262              :                                       CompNum,
     263              :                                       CompName,
     264            0 :                                       state.dataWaterThermalTanks->HPWaterHeater(CompNum).Name));
     265              :             }
     266            0 :             state.dataWaterThermalTanks->HPWaterHeater(CompNum).CheckHPWHEquipName = false;
     267              :         }
     268              :     }
     269              : 
     270            0 :     return CompNum;
     271              : }
     272              : 
     273            0 : void WaterThermalTankData::simulate(
     274              :     EnergyPlusData &state, const PlantLocation &calledFromLocation, bool FirstHVACIteration, Real64 &CurLoad, [[maybe_unused]] bool RunFlag)
     275              : {
     276              :     // SUBROUTINE INFORMATION:
     277              :     //       AUTHOR         Brandon Anderson
     278              :     //       DATE WRITTEN   May 2000
     279              :     //       MODIFIED       FSEC, July 2005
     280              :     //       RE-ENGINEERED  na
     281              : 
     282              :     // set the caller loop num to mimic what was happening in plant loop equip
     283            0 :     this->callerLoopNum = calledFromLocation.loopNum;
     284              : 
     285            0 :     this->oneTimeInit(state);
     286              : 
     287            0 :     if (this->MyOneTimeFlagWH) {
     288            0 :         this->MyOneTimeFlagWH = false;
     289              :     } else {
     290            0 :         if (this->MyTwoTimeFlagWH) {
     291            0 :             this->MinePlantStructForInfo(state); // call it again to get control types filled out
     292            0 :             this->MyTwoTimeFlagWH = false;
     293              :         }
     294              :     }
     295            0 :     this->UseSideLoadRequested = std::abs(CurLoad);
     296            0 :     if (this->UseSidePlantLoc.loopNum > 0 && this->UseSidePlantLoc.loopSideNum != DataPlant::LoopSideLocation::Invalid &&
     297            0 :         !state.dataGlobal->KickOffSimulation) {
     298            0 :         this->UseCurrentFlowLock = state.dataPlnt->PlantLoop(this->UseSidePlantLoc.loopNum).LoopSide(this->UseSidePlantLoc.loopSideNum).FlowLock;
     299              :     } else {
     300            0 :         this->UseCurrentFlowLock = DataPlant::FlowLock::Locked;
     301              :     }
     302            0 :     this->initialize(state, FirstHVACIteration);
     303              :     //       Plant connected water heaters may have a desuperheater heating coil attached
     304            0 :     if (this->DesuperheaterNum == 0) {
     305            0 :         if ((this->WaterThermalTankType == DataPlant::PlantEquipmentType::WtrHeaterMixed) ||
     306            0 :             (this->WaterThermalTankType == DataPlant::PlantEquipmentType::ChilledWaterTankMixed)) {
     307            0 :             this->CalcWaterThermalTankMixed(state);
     308            0 :         } else if ((this->WaterThermalTankType == DataPlant::PlantEquipmentType::WtrHeaterStratified) ||
     309            0 :                    (this->WaterThermalTankType == DataPlant::PlantEquipmentType::ChilledWaterTankStratified)) {
     310            0 :             this->CalcWaterThermalTankStratified(state);
     311              :         }
     312            0 :     } else if (this->DesuperheaterNum > 0) {
     313            0 :         this->CalcDesuperheaterWaterHeater(state, FirstHVACIteration);
     314              :     }
     315            0 :     this->UpdateWaterThermalTank(state);
     316            0 :     this->ReportWaterThermalTank(state);
     317              :     // reset the caller loop num to mimic what was happening in PlantLoopEquip
     318            0 :     this->callerLoopNum = 0;
     319            0 : }
     320              : 
     321            0 : PlantComponent *HeatPumpWaterHeaterData::factory(EnergyPlusData &state, std::string const &objectName)
     322              : {
     323              :     // Process the input data
     324            0 :     if (state.dataWaterThermalTanks->getWaterThermalTankInputFlag) {
     325            0 :         GetWaterThermalTankInput(state);
     326            0 :         state.dataWaterThermalTanks->getWaterThermalTankInputFlag = false;
     327              :     }
     328              : 
     329              :     // Now look for this object in the list
     330            0 :     for (auto &HPWH : state.dataWaterThermalTanks->HPWaterHeater) {
     331            0 :         if (HPWH.Name == objectName) {
     332            0 :             return &HPWH;
     333              :         }
     334              :     }
     335              :     // If we didn't find it, fatal
     336              :     ShowFatalError(state, format("LocalHeatPumpWaterHeaterFactory: Error getting inputs for object named: {}", objectName)); // LCOV_EXCL_LINE
     337              :     // Shut up the compiler
     338              :     return nullptr; // LCOV_EXCL_LINE
     339              : }
     340              : 
     341            0 : void HeatPumpWaterHeaterData::onInitLoopEquip(EnergyPlusData &state, const PlantLocation &calledFromLocation)
     342              : {
     343            0 :     auto &Tank = state.dataWaterThermalTanks->WaterThermalTank(this->WaterHeaterTankNum);
     344            0 :     Tank.onInitLoopEquip(state, calledFromLocation);
     345            0 : }
     346              : 
     347            0 : void HeatPumpWaterHeaterData::getDesignCapacities([[maybe_unused]] EnergyPlusData &state,
     348              :                                                   [[maybe_unused]] const PlantLocation &calledFromLocation,
     349              :                                                   Real64 &MaxLoad,
     350              :                                                   Real64 &MinLoad,
     351              :                                                   Real64 &OptLoad)
     352              : {
     353            0 :     MinLoad = 0.0;
     354            0 :     MaxLoad = this->Capacity;
     355            0 :     OptLoad = this->Capacity;
     356            0 : }
     357              : 
     358            1 : void HeatPumpWaterHeaterData::simulate(
     359              :     EnergyPlusData &state, const PlantLocation &calledFromLocation, bool FirstHVACIteration, Real64 &CurLoad, [[maybe_unused]] bool RunFlag)
     360              : {
     361              :     // SUBROUTINE INFORMATION:
     362              :     //       AUTHOR         Brandon Anderson
     363              :     //       DATE WRITTEN   May 2000
     364              :     //       MODIFIED       FSEC, July 2005
     365              :     //       RE-ENGINEERED  na
     366              : 
     367            1 :     auto &Tank = state.dataWaterThermalTanks->WaterThermalTank(this->WaterHeaterTankNum);
     368              : 
     369              :     // set caller loop num to mimic what plantloopequip was doing
     370            1 :     Tank.callerLoopNum = calledFromLocation.loopNum;
     371              : 
     372            1 :     if (this->myOneTimeInitFlag) {
     373            1 :         if (Tank.myOneTimeInitFlag) {
     374            1 :             Tank.setupOutputVars(state);
     375            1 :             Tank.myOneTimeInitFlag = false;
     376              :         }
     377            1 :         this->myOneTimeInitFlag = false;
     378              :     }
     379              : 
     380            1 :     if (this->MyOneTimeFlagHP) {
     381            1 :         this->MyOneTimeFlagHP = false;
     382              :     } else {
     383            0 :         if (this->MyTwoTimeFlagHP) {
     384            0 :             Tank.MinePlantStructForInfo(state); // call it again to get control types filled out
     385            0 :             this->MyTwoTimeFlagHP = false;
     386              :         }
     387              :     }
     388            1 :     Tank.UseSideLoadRequested = std::abs(CurLoad);
     389            1 :     if (Tank.UseSidePlantLoc.loopNum > 0 && Tank.UseSidePlantLoc.loopSideNum != DataPlant::LoopSideLocation::Invalid &&
     390            0 :         !state.dataGlobal->KickOffSimulation) {
     391            0 :         Tank.UseCurrentFlowLock = state.dataPlnt->PlantLoop(Tank.UseSidePlantLoc.loopNum).LoopSide(Tank.UseSidePlantLoc.loopSideNum).FlowLock;
     392              :     } else {
     393            1 :         Tank.UseCurrentFlowLock = DataPlant::FlowLock::Locked;
     394              :     }
     395              : 
     396            1 :     Tank.initialize(state, FirstHVACIteration);
     397              : 
     398            1 :     int InletNodeSav = this->HeatPumpAirInletNode;
     399            1 :     int OutletNodeSav = this->HeatPumpAirOutletNode;
     400            1 :     int DXINletNodeSav = this->DXCoilAirInletNode;
     401            1 :     int IHPFanIndexSav = this->FanNum;
     402            1 :     std::string IHPFanNameSave = this->FanName;
     403            1 :     HVAC::FanPlace IHPFanplaceSav = this->fanPlace;
     404              : 
     405            1 :     if (this->bIsIHP) // pass the tank indexes to the IHP object
     406              :     {
     407            0 :         state.dataIntegratedHP->IntegratedHeatPumps(this->DXCoilNum).WHtankType = this->HPWHType;
     408            0 :         state.dataIntegratedHP->IntegratedHeatPumps(this->DXCoilNum).WHtankName = this->Name;
     409            0 :         state.dataIntegratedHP->IntegratedHeatPumps(this->DXCoilNum).WHtankID = this->WaterHeaterTankNum;
     410            0 :         IntegratedHeatPump::IHPOperationMode IHPMode = IntegratedHeatPump::GetCurWorkMode(state, this->DXCoilNum);
     411              : 
     412            0 :         if ((IntegratedHeatPump::IHPOperationMode::DedicatedWaterHtg == IHPMode) ||
     413            0 :             (IntegratedHeatPump::IHPOperationMode::SpaceClgDedicatedWaterHtg == IHPMode) ||
     414            0 :             (IntegratedHeatPump::IHPOperationMode::SHDWHElecHeatOff == IHPMode) ||
     415              :             (IntegratedHeatPump::IHPOperationMode::SHDWHElecHeatOn == IHPMode)) { // default is to specify the air nodes for SCWH mode
     416            0 :             bool bDWHCoilReading = false;
     417            0 :             this->HeatPumpAirInletNode =
     418            0 :                 VariableSpeedCoils::GetCoilInletNodeVariableSpeed(state,
     419              :                                                                   "COIL:WATERHEATING:AIRTOWATERHEATPUMP:VARIABLESPEED",
     420            0 :                                                                   state.dataIntegratedHP->IntegratedHeatPumps(this->DXCoilNum).DWHCoilName,
     421              :                                                                   bDWHCoilReading);
     422            0 :             this->HeatPumpAirOutletNode =
     423            0 :                 VariableSpeedCoils::GetCoilOutletNodeVariableSpeed(state,
     424              :                                                                    "COIL:WATERHEATING:AIRTOWATERHEATPUMP:VARIABLESPEED",
     425            0 :                                                                    state.dataIntegratedHP->IntegratedHeatPumps(this->DXCoilNum).DWHCoilName,
     426              :                                                                    bDWHCoilReading);
     427            0 :             this->DXCoilAirInletNode = this->HeatPumpAirInletNode;
     428            0 :         } else // default is to input outdoor fan to the HPWH
     429              :         {
     430            0 :             this->FanNum = state.dataIntegratedHP->IntegratedHeatPumps(this->DXCoilNum).IDFanID;
     431            0 :             this->FanName = state.dataIntegratedHP->IntegratedHeatPumps(this->DXCoilNum).IDFanName;
     432            0 :             this->fanPlace = state.dataIntegratedHP->IntegratedHeatPumps(this->DXCoilNum).fanPlace;
     433              :         }
     434              :     }
     435              : 
     436            1 :     Tank.CalcHeatPumpWaterHeater(state, FirstHVACIteration);
     437            1 :     Tank.UpdateWaterThermalTank(state);
     438            1 :     Tank.ReportWaterThermalTank(state);
     439              : 
     440            1 :     this->HeatPumpAirInletNode = InletNodeSav;
     441            1 :     this->HeatPumpAirOutletNode = OutletNodeSav;
     442            1 :     this->DXCoilAirInletNode = DXINletNodeSav;
     443            1 :     this->FanNum = IHPFanIndexSav;
     444            1 :     this->FanName = IHPFanNameSave;
     445            1 :     this->fanPlace = IHPFanplaceSav;
     446              :     // reset caller loop num to 0 to mimic what plantloopequip was doing
     447            1 :     Tank.callerLoopNum = 0;
     448            1 : }
     449            0 : void HeatPumpWaterHeaterData::oneTimeInit([[maybe_unused]] EnergyPlusData &state)
     450              : {
     451            0 : }
     452              : 
     453            0 : void SimulateWaterHeaterStandAlone(EnergyPlusData &state, int const WaterHeaterNum, bool const FirstHVACIteration)
     454              : {
     455              : 
     456              :     // SUBROUTINE INFORMATION:
     457              :     //       AUTHOR         Peter Graham Ellis
     458              :     //       DATE WRITTEN   January 2004
     459              :     //       MODIFIED       July 2005, FSEC - added HPWHs and desuperheater water heating coils
     460              :     //       RE-ENGINEERED  na
     461              : 
     462              :     // PURPOSE OF THIS SUBROUTINE:
     463              :     // This subroutine acts an interface to SimWaterHeater for stand-alone water heaters with no plant connections,
     464              :     // HPWHs not defined as zone equipment with no plant connections, and stand-alone water heaters with
     465              :     // desuperheater heating coils with no plant connections.
     466              : 
     467              :     // METHODOLOGY EMPLOYED:
     468              :     // The necessary control flags and dummy variables are set and passed into SimWaterHeater. This subroutine is
     469              :     // called from NonZoneEquipmentManager.
     470              : 
     471              :     Real64 MyLoad;
     472              : 
     473            0 :     if (state.dataWaterThermalTanks->getWaterThermalTankInputFlag) {
     474            0 :         GetWaterThermalTankInput(state);
     475            0 :         state.dataWaterThermalTanks->getWaterThermalTankInputFlag = false;
     476              :     }
     477              : 
     478            0 :     auto &Tank = state.dataWaterThermalTanks->WaterThermalTank(WaterHeaterNum);
     479              : 
     480              :     // Only simulate stand-alone water heaters here.  Plant connected water heaters are called by the PlantLoopEquipments.
     481            0 :     if (Tank.StandAlone) {
     482            0 :         bool localRunFlag = true;
     483            0 :         PlantLocation A(0, DataPlant::LoopSideLocation::Invalid, 0, 0);
     484            0 :         Tank.simulate(state, A, FirstHVACIteration, MyLoad, localRunFlag);
     485              : 
     486              :         // HPWHs with inlet air from a zone and not connected to a plant loop are simulated through a CALL from ZoneEquipmentManager.
     487              :         // HPWHs that are plant connected are always simulated through a CALL from PlantLoopEquipments directly to SimWaterThermalTank.
     488              : 
     489              :         // NOTE: HPWHs with inlet air from a zone AND plant connected are not stand alone and are simulated in PlantLoopEquipments
     490            0 :     } else if (Tank.HeatPumpNum > 0) {
     491              :         //   Only HPWHs with inlet air from outdoors or scheduled HPWHs (not connected to a plant loop) are simulated here.
     492              : 
     493            0 :         auto &HPWaterHtr = state.dataWaterThermalTanks->HPWaterHeater(Tank.HeatPumpNum);
     494              : 
     495            0 :         if (HPWaterHtr.StandAlone &&
     496            0 :             (HPWaterHtr.InletAirConfiguration == WTTAmbientTemp::OutsideAir || HPWaterHtr.InletAirConfiguration == WTTAmbientTemp::Schedule)) {
     497            0 :             bool LocalRunFlag = true;
     498            0 :             PlantLocation A(0, DataPlant::LoopSideLocation::Invalid, 0, 0);
     499            0 :             HPWaterHtr.simulate(state, A, FirstHVACIteration, MyLoad, LocalRunFlag);
     500              :         }
     501              : 
     502              :         // Only simulate stand-alone water heaters with desuperheater water heating coils here.  Plant connected water heaters
     503              :         // with desuperheater water heating coils are called by PlantLoopEquipments.
     504            0 :     } else if (Tank.DesuperheaterNum > 0) {
     505            0 :         if (state.dataWaterThermalTanks->WaterHeaterDesuperheater(Tank.DesuperheaterNum).StandAlone) {
     506            0 :             bool localRunFlag = true;
     507            0 :             PlantLocation A(0, DataPlant::LoopSideLocation::Invalid, 0, 0);
     508            0 :             Tank.simulate(state, A, FirstHVACIteration, MyLoad, localRunFlag);
     509              :         }
     510              :     }
     511            0 : }
     512              : 
     513            1 : void SimHeatPumpWaterHeater(EnergyPlusData &state,
     514              :                             std::string_view CompName,
     515              :                             bool const FirstHVACIteration,
     516              :                             Real64 &SensLoadMet, // sensible load met by this equipment and sent to zone, W
     517              :                             Real64 &LatLoadMet,  // net latent load met and sent to zone (kg/s), dehumid = negative
     518              :                             int &CompIndex)
     519              : {
     520              :     // SUBROUTINE INFORMATION:
     521              :     //       AUTHOR         Richard Raustad
     522              :     //       DATE WRITTEN   April 2005
     523              :     //       MODIFIED       Don Shirey, Aug 2009 (LatLoadMet)
     524              :     //       RE-ENGINEERED  na
     525              : 
     526              :     // PURPOSE OF THIS SUBROUTINE:
     527              :     // This subroutine acts as an interface to SimWaterHeater.
     528              :     // HPWHs defined as zone equipment and not connected to a plant loop are called here by ZoneEquipmentManager
     529              : 
     530              :     // METHODOLOGY EMPLOYED:
     531              :     // The necessary control flags and dummy variables are set and passed into SimWaterHeater.
     532              : 
     533            1 :     if (state.dataWaterThermalTanks->getWaterThermalTankInputFlag) {
     534            1 :         GetWaterThermalTankInput(state);
     535            1 :         state.dataWaterThermalTanks->getWaterThermalTankInputFlag = false;
     536              :     }
     537              : 
     538              :     // Find the correct Heat Pump Water Heater
     539              :     int HeatPumpNum;
     540            1 :     if (CompIndex == 0) {
     541            0 :         HeatPumpNum = Util::FindItemInList(CompName, state.dataWaterThermalTanks->HPWaterHeater);
     542            0 :         if (HeatPumpNum == 0) {
     543            0 :             ShowFatalError(state, format("SimHeatPumpWaterHeater: Unit not found={}", CompName));
     544              :         }
     545            0 :         CompIndex = HeatPumpNum;
     546              :     } else {
     547            1 :         HeatPumpNum = CompIndex;
     548            1 :         if (HeatPumpNum > state.dataWaterThermalTanks->numHeatPumpWaterHeater || HeatPumpNum < 1) {
     549            0 :             ShowFatalError(state,
     550            0 :                            format("SimHeatPumpWaterHeater:  Invalid CompIndex passed={}, Number of Units={}, Entered Unit name={}",
     551              :                                   HeatPumpNum,
     552            0 :                                   state.dataWaterThermalTanks->numHeatPumpWaterHeater,
     553              :                                   CompName));
     554              :         }
     555              :     }
     556              : 
     557              :     // Only simulate HPWHs specified as zone equipment and not connected to a plant loop.
     558              :     // HPWHs not defined as zone equipment with no plant connections are simulated in NonZoneEquipmentManager.
     559              :     // Plant connected HPWHs are called by PlantLoopEquipments (but only those on supply side ).
     560              :     // HPWH will not be included in sizing calculations, fan is initialized only during BeginEnvrnFlag (FALSE during sizing)
     561              :     // (fan will be turned off during Standard Ratings procedure yielding incorrect results)
     562            1 :     if (state.dataGlobal->DoingSizing) return;
     563              : 
     564              :     // For HPWHs, StandAlone means not connected to a plant loop (use nodes are not used, source nodes are connected to a HPWH)
     565            1 :     if (state.dataWaterThermalTanks->HPWaterHeater(HeatPumpNum).StandAlone) {
     566            1 :         bool LocalRunFlag = true;
     567              :         Real64 MyLoad;
     568              : 
     569            1 :         PlantLocation A(0, DataPlant::LoopSideLocation::Invalid, 0, 0);
     570            1 :         state.dataWaterThermalTanks->HPWaterHeater(HeatPumpNum).simulate(state, A, FirstHVACIteration, MyLoad, LocalRunFlag);
     571              : 
     572            1 :         SensLoadMet = state.dataWaterThermalTanks->HPWaterHeater(HeatPumpNum).HPWaterHeaterSensibleCapacity;
     573            1 :         LatLoadMet = state.dataWaterThermalTanks->HPWaterHeater(HeatPumpNum).HPWaterHeaterLatentCapacity;
     574              :     } else {
     575              :         // HPWH is plant connected and will get simulated when called from plant SimWaterThermalTank, but need to update loads met here
     576            0 :         SensLoadMet = state.dataWaterThermalTanks->HPWaterHeater(HeatPumpNum).HPWaterHeaterSensibleCapacity;
     577            0 :         LatLoadMet = state.dataWaterThermalTanks->HPWaterHeater(HeatPumpNum).HPWaterHeaterLatentCapacity;
     578              :     }
     579              : }
     580              : 
     581       249958 : void CalcWaterThermalTankZoneGains(EnergyPlusData &state)
     582              : {
     583              : 
     584              :     // SUBROUTINE INFORMATION:
     585              :     //       AUTHOR         Peter Graham Ellis
     586              :     //       DATE WRITTEN   March 2005
     587              :     //       MODIFIED       B. Griffith November 2011, new internal gains structure
     588              :     //       RE-ENGINEERED  na
     589              : 
     590              :     // PURPOSE OF THIS SUBROUTINE:
     591              :     // Calculates the zone internal gains due to water heater skin losses during sizing.
     592              :     // initializes gains to zone at begin environment.
     593              : 
     594              :     // METHODOLOGY EMPLOYED:
     595              :     // Sums the tank losses from all of the water heaters in the zone to add as a gain to the zone.
     596              :     // Now used to determine tank losses during sizing.  Internal gains are summed in a centralized way now
     597              : 
     598       249958 :     if (state.dataWaterThermalTanks->numWaterThermalTank == 0) {
     599              : 
     600       249958 :         if (!state.dataGlobal->DoingSizing) {
     601       184216 :             return;
     602              :         } else {
     603        65742 :             if (state.dataWaterThermalTanks->getWaterThermalTankInputFlag) {
     604           40 :                 GetWaterThermalTankInput(state);
     605           40 :                 state.dataWaterThermalTanks->getWaterThermalTankInputFlag = false;
     606              :             }
     607        65742 :             if (state.dataWaterThermalTanks->numWaterThermalTank == 0) return;
     608              :         }
     609              :     }
     610              : 
     611            0 :     if (state.dataGlobal->BeginEnvrnFlag && state.dataWaterThermalTanks->calcWaterThermalTankZoneGainsMyEnvrnFlag) {
     612            0 :         for (auto &e : state.dataWaterThermalTanks->WaterThermalTank) {
     613            0 :             e.AmbientZoneGain = 0.0;
     614            0 :             e.FuelEnergy = 0.0;
     615            0 :             e.OffCycParaFuelEnergy = 0.0;
     616            0 :             e.OnCycParaFuelEnergy = 0.0;
     617              :         }
     618            0 :         state.dataWaterThermalTanks->calcWaterThermalTankZoneGainsMyEnvrnFlag = false;
     619              :     }
     620              : 
     621            0 :     if (!state.dataGlobal->BeginEnvrnFlag) state.dataWaterThermalTanks->calcWaterThermalTankZoneGainsMyEnvrnFlag = true;
     622              : 
     623            0 :     for (int WaterThermalTankNum = 1; WaterThermalTankNum <= state.dataWaterThermalTanks->numWaterThermalTank; ++WaterThermalTankNum) {
     624            0 :         auto &Tank = state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum);
     625            0 :         if (Tank.AmbientTempZone == 0) continue;
     626            0 :         auto const &thisZoneHB = state.dataZoneTempPredictorCorrector->zoneHeatBalance(Tank.AmbientTempZone);
     627            0 :         if (state.dataGlobal->DoingSizing) {
     628              :             // Initialize tank temperature to setpoint
     629              :             // (use HPWH or Desuperheater heating coil set point if applicable)
     630            0 :             Sched::Schedule *sched = nullptr;
     631            0 :             if (Tank.HeatPumpNum > 0) {
     632            0 :                 sched = state.dataWaterThermalTanks->HPWaterHeater(Tank.HeatPumpNum).setptTempSched;
     633            0 :             } else if (Tank.DesuperheaterNum > 0) {
     634            0 :                 sched = state.dataWaterThermalTanks->WaterHeaterDesuperheater(Tank.DesuperheaterNum).setptTempSched;
     635              :             } else {
     636            0 :                 sched = Tank.setptTempSched;
     637              :             }
     638              : 
     639            0 :             Real64 TankTemp = (sched != nullptr) ? sched->getCurrentVal() : 20.0;
     640              : 
     641            0 :             Real64 QLossToZone = 0.0;
     642            0 :             switch (Tank.WaterThermalTankType) {
     643            0 :             case DataPlant::PlantEquipmentType::WtrHeaterMixed: {
     644            0 :                 QLossToZone = max(Tank.OnCycLossCoeff * Tank.OnCycLossFracToZone, Tank.OffCycLossCoeff * Tank.OffCycLossFracToZone) *
     645            0 :                               (TankTemp - thisZoneHB.MAT);
     646            0 :                 break;
     647              :             }
     648            0 :             case DataPlant::PlantEquipmentType::WtrHeaterStratified: {
     649            0 :                 QLossToZone = max(Tank.Node(1).OnCycLossCoeff * Tank.SkinLossFracToZone, Tank.Node(1).OffCycLossCoeff * Tank.SkinLossFracToZone) *
     650            0 :                               (TankTemp - thisZoneHB.MAT);
     651            0 :                 break;
     652              :             }
     653            0 :             case DataPlant::PlantEquipmentType::ChilledWaterTankMixed: {
     654            0 :                 QLossToZone = Tank.OffCycLossCoeff * Tank.OffCycLossFracToZone * (TankTemp - thisZoneHB.MAT);
     655            0 :                 break;
     656              :             }
     657            0 :             case DataPlant::PlantEquipmentType::ChilledWaterTankStratified: {
     658            0 :                 QLossToZone = Tank.Node(1).OffCycLossCoeff * Tank.SkinLossFracToZone * (TankTemp - thisZoneHB.MAT);
     659            0 :                 break;
     660              :             }
     661            0 :             default:
     662            0 :                 break;
     663              :             }
     664            0 :             Tank.AmbientZoneGain = QLossToZone;
     665              :         }
     666              :     }
     667              : }
     668              : 
     669            5 : bool getDesuperHtrInput(EnergyPlusData &state)
     670              : {
     671            5 :     bool ErrorsFound = false;
     672              :     static constexpr std::string_view routineName = "getDesuperHtrInput";
     673              :     // Make local copies of IPShortCut because other getinputs might overwrite the ones in state <-- need to fix this idiom
     674            5 :     std::string cCurrentModuleObject = state.dataIPShortCut->cCurrentModuleObject;
     675            5 :     Array1D<std::string> cAlphaArgs = state.dataIPShortCut->cAlphaArgs;
     676            5 :     Array1D<Real64> rNumericArgs = state.dataIPShortCut->rNumericArgs;
     677            5 :     Array1D<bool> lNumericFieldBlanks = state.dataIPShortCut->lNumericFieldBlanks;
     678            5 :     Array1D<bool> lAlphaFieldBlanks = state.dataIPShortCut->lAlphaFieldBlanks;
     679            5 :     Array1D<std::string> cAlphaFieldNames = state.dataIPShortCut->cAlphaFieldNames;
     680            5 :     Array1D<std::string> cNumericFieldNames = state.dataIPShortCut->cNumericFieldNames;
     681              : 
     682            5 :     cCurrentModuleObject = cCoilDesuperheater;
     683           11 :     for (int DesuperheaterNum = 1; DesuperheaterNum <= state.dataWaterThermalTanks->numWaterHeaterDesuperheater; ++DesuperheaterNum) {
     684              :         int NumAlphas;
     685              :         int NumNums;
     686              :         int IOStat;
     687            6 :         state.dataInputProcessing->inputProcessor->getObjectItem(state,
     688              :                                                                  cCurrentModuleObject,
     689              :                                                                  DesuperheaterNum,
     690              :                                                                  cAlphaArgs,
     691              :                                                                  NumAlphas,
     692              :                                                                  rNumericArgs,
     693              :                                                                  NumNums,
     694              :                                                                  IOStat,
     695              :                                                                  lNumericFieldBlanks,
     696              :                                                                  lAlphaFieldBlanks,
     697              :                                                                  cAlphaFieldNames,
     698              :                                                                  cNumericFieldNames);
     699              : 
     700            6 :         ErrorObjectHeader eoh{routineName, cCurrentModuleObject, cAlphaArgs(1)};
     701              : 
     702            6 :         Util::IsNameEmpty(state, cAlphaArgs(1), cCurrentModuleObject, ErrorsFound);
     703              : 
     704              :         // ErrorsFound will be set to True if problem was found, left untouched otherwise
     705            6 :         GlobalNames::VerifyUniqueCoilName(state, cCurrentModuleObject, cAlphaArgs(1), ErrorsFound, cCurrentModuleObject + " Name");
     706              : 
     707            6 :         auto &DesupHtr = state.dataWaterThermalTanks->WaterHeaterDesuperheater(DesuperheaterNum);
     708              : 
     709            6 :         DesupHtr.Name = cAlphaArgs(1);
     710            6 :         DesupHtr.Type = cCurrentModuleObject;
     711              : 
     712              :         //       convert availability schedule name to pointer
     713            6 :         if (lAlphaFieldBlanks(2)) {
     714            0 :             DesupHtr.availSched = Sched::GetScheduleAlwaysOn(state);
     715            6 :         } else if ((DesupHtr.availSched = Sched::GetSchedule(state, cAlphaArgs(2))) == nullptr) {
     716            0 :             ShowSevereItemNotFound(state, eoh, cAlphaFieldNames(2), cAlphaArgs(2));
     717            0 :             ErrorsFound = true;
     718              :         }
     719              : 
     720              :         // convert schedule name to pointer
     721            6 :         if (lAlphaFieldBlanks(3)) {
     722            6 :         } else if ((DesupHtr.setptTempSched = Sched::GetSchedule(state, cAlphaArgs(3))) == nullptr) {
     723            0 :             ShowSevereItemNotFound(state, eoh, cAlphaFieldNames(3), cAlphaArgs(3));
     724            0 :             ErrorsFound = true;
     725              :         }
     726              : 
     727            6 :         DesupHtr.DeadBandTempDiff = rNumericArgs(1);
     728            6 :         if (DesupHtr.DeadBandTempDiff <= 0.0 || DesupHtr.DeadBandTempDiff > 20.0) {
     729            0 :             ShowSevereError(state,
     730            0 :                             format("{} = {}: {} must be > 0 and <= 20. {} = {:.1T}",
     731              :                                    cCurrentModuleObject,
     732            0 :                                    DesupHtr.Name,
     733              :                                    cNumericFieldNames(1),
     734              :                                    cNumericFieldNames(1),
     735              :                                    rNumericArgs(1)));
     736            0 :             ErrorsFound = true;
     737              :         }
     738              : 
     739              :         // Error limits on heat reclaim efficiency applied after source type identified
     740              : 
     741            6 :         DesupHtr.RatedInletWaterTemp = rNumericArgs(3);
     742            6 :         DesupHtr.RatedOutdoorAirTemp = rNumericArgs(4);
     743            6 :         DesupHtr.MaxInletWaterTemp = rNumericArgs(5);
     744              : 
     745            6 :         if (!lAlphaFieldBlanks(4)) {
     746            0 :             DesupHtr.HEffFTemp = Curve::GetCurveIndex(state, cAlphaArgs(4));
     747            0 :             if (DesupHtr.HEffFTemp == 0) {
     748            0 :                 ShowSevereError(state,
     749            0 :                                 format("{} = {}:  {} not found = {}", cCurrentModuleObject, DesupHtr.Name, cAlphaFieldNames(4), cAlphaArgs(4)));
     750            0 :                 ErrorsFound = true;
     751              :             } else {
     752            0 :                 ErrorsFound |= Curve::CheckCurveDims(state,
     753              :                                                      DesupHtr.HEffFTemp,   // Curve index
     754              :                                                      {2},                  // Valid dimensions
     755              :                                                      routineName,          // Routine name
     756              :                                                      cCurrentModuleObject, // Object Type
     757              :                                                      DesupHtr.Name,        // Object Name
     758            0 :                                                      cAlphaFieldNames(4)); // Field Name
     759            0 :                 if (!ErrorsFound) {
     760            0 :                     if (DesupHtr.HEffFTemp > 0) {
     761            0 :                         Real64 HEffFTemp = min(
     762            0 :                             1.0, max(0.0, Curve::CurveValue(state, DesupHtr.HEffFTemp, DesupHtr.RatedInletWaterTemp, DesupHtr.RatedOutdoorAirTemp)));
     763            0 :                         if (std::abs(HEffFTemp - 1.0) > 0.05) {
     764            0 :                             ShowWarningError(state, format("{}, \"{}\":", cCurrentModuleObject, DesupHtr.Name));
     765            0 :                             ShowContinueError(state, format("The {} should be normalized ", cAlphaFieldNames(4)));
     766            0 :                             ShowContinueError(state, format(" to 1.0 at the rating point. Curve output at the rating point = {:.3T}", HEffFTemp));
     767            0 :                             ShowContinueError(state, " The simulation continues using the user-specified curve.");
     768              :                         }
     769              :                     }
     770              :                 }
     771              :             }
     772              :         }
     773              : 
     774            6 :         DesupHtr.WaterInletNode = NodeInputManager::GetOnlySingleNode(state,
     775            6 :                                                                       cAlphaArgs(5),
     776              :                                                                       ErrorsFound,
     777              :                                                                       DataLoopNode::ConnectionObjectType::CoilWaterHeatingDesuperheater,
     778            6 :                                                                       cAlphaArgs(1),
     779              :                                                                       DataLoopNode::NodeFluidType::Water,
     780              :                                                                       DataLoopNode::ConnectionType::Inlet,
     781              :                                                                       NodeInputManager::CompFluidStream::Primary,
     782              :                                                                       DataLoopNode::ObjectIsParent);
     783              : 
     784            6 :         DesupHtr.WaterOutletNode = NodeInputManager::GetOnlySingleNode(state,
     785            6 :                                                                        cAlphaArgs(6),
     786              :                                                                        ErrorsFound,
     787              :                                                                        DataLoopNode::ConnectionObjectType::CoilWaterHeatingDesuperheater,
     788            6 :                                                                        cAlphaArgs(1),
     789              :                                                                        DataLoopNode::NodeFluidType::Water,
     790              :                                                                        DataLoopNode::ConnectionType::Outlet,
     791              :                                                                        NodeInputManager::CompFluidStream::Primary,
     792              :                                                                        DataLoopNode::ObjectIsParent);
     793              : 
     794            6 :         DesupHtr.InletNodeName1 = cAlphaArgs(5);
     795            6 :         DesupHtr.OutletNodeName1 = cAlphaArgs(6);
     796              : 
     797            6 :         DesupHtr.TankType = cAlphaArgs(7);
     798              : 
     799            6 :         if (!Util::SameString(DesupHtr.TankType, cMixedWHModuleObj) && !Util::SameString(DesupHtr.TankType, cStratifiedWHModuleObj)) {
     800              : 
     801            0 :             ShowSevereError(state, format("{} = {}:", cCurrentModuleObject, state.dataWaterThermalTanks->HPWaterHeater(DesuperheaterNum).Name));
     802            0 :             ShowContinueError(state, format("Desuperheater can only be used with {} or {}.", cMixedWHModuleObj, cStratifiedWHModuleObj));
     803            0 :             ErrorsFound = true;
     804              :         }
     805              : 
     806            6 :         DesupHtr.TankName = cAlphaArgs(8);
     807              : 
     808              :         // Set up comp set for water side nodes (reverse inlet/outlet for water heater)
     809            6 :         BranchNodeConnections::SetUpCompSets(state, DesupHtr.Type, DesupHtr.Name, DesupHtr.TankType, DesupHtr.TankName, cAlphaArgs(6), cAlphaArgs(5));
     810              : 
     811            6 :         std::string const heatSourceObjType = cAlphaArgs(9);
     812              : 
     813           12 :         if ((Util::SameString(heatSourceObjType, "Refrigeration:Condenser:AirCooled")) ||
     814           12 :             (Util::SameString(heatSourceObjType, "Refrigeration:Condenser:EvaporativeCooled")) ||
     815           12 :             (Util::SameString(heatSourceObjType, "Refrigeration:Condenser:WaterCooled"))) {
     816            0 :             if (lNumericFieldBlanks(2)) {
     817            0 :                 DesupHtr.HeatReclaimRecoveryEff = 0.8;
     818              :             } else {
     819            0 :                 DesupHtr.HeatReclaimRecoveryEff = rNumericArgs(2);
     820            0 :                 if (DesupHtr.HeatReclaimRecoveryEff <= 0.0 || DesupHtr.HeatReclaimRecoveryEff > 0.9) {
     821            0 :                     ShowSevereError(state,
     822            0 :                                     format("{} = {}: {} must be > 0.0 and <= 0.9, Efficiency = {:.3T}",
     823              :                                            cCurrentModuleObject,
     824            0 :                                            DesupHtr.Name,
     825              :                                            cNumericFieldNames(2),
     826            0 :                                            DesupHtr.HeatReclaimRecoveryEff));
     827            0 :                     ErrorsFound = true;
     828              :                 }
     829              :             }    // Blank Num(2)
     830              :         } else { // max is 0.3 for all other sources
     831            6 :             if (lNumericFieldBlanks(2)) {
     832            0 :                 DesupHtr.HeatReclaimRecoveryEff = 0.25;
     833              :             } else {
     834            6 :                 DesupHtr.HeatReclaimRecoveryEff = rNumericArgs(2);
     835            6 :                 if (DesupHtr.HeatReclaimRecoveryEff <= 0.0 || DesupHtr.HeatReclaimRecoveryEff > 0.3) {
     836            0 :                     ShowSevereError(state,
     837            0 :                                     format("{} = {}: {} must be > 0.0 and <= 0.3, {} = {:.3T}",
     838              :                                            cCurrentModuleObject,
     839            0 :                                            DesupHtr.Name,
     840              :                                            cNumericFieldNames(2),
     841              :                                            cNumericFieldNames(2),
     842            0 :                                            DesupHtr.HeatReclaimRecoveryEff));
     843            0 :                     ErrorsFound = true;
     844              :                 }
     845              :             } // Blank Num(2)
     846              :         }     // setting limits on heat recovery efficiency
     847              : 
     848              :         //       Find the Refrigeration equipment index associated with the desuperheater heating coil.
     849            6 :         bool errFlag = false;
     850            6 :         DesupHtr.HeatingSourceType = heatSourceObjType;
     851            6 :         DesupHtr.HeatingSourceName = cAlphaArgs(10);
     852            6 :         if (Util::SameString(heatSourceObjType, "Refrigeration:CompressorRack")) {
     853            0 :             DesupHtr.ReclaimHeatingSource = ReclaimHeatObjectType::CompressorRackRefrigeratedCase;
     854            0 :             for (int RackNum = 1; RackNum <= state.dataRefrigCase->NumRefrigeratedRacks; ++RackNum) {
     855            0 :                 if (!Util::SameString(state.dataHeatBal->HeatReclaimRefrigeratedRack(RackNum).Name, cAlphaArgs(10))) continue;
     856            0 :                 DesupHtr.ReclaimHeatingSourceIndexNum = RackNum;
     857            0 :                 if (allocated(state.dataHeatBal->HeatReclaimRefrigeratedRack)) {
     858              :                     DataHeatBalance::HeatReclaimDataBase &HeatReclaim =
     859            0 :                         state.dataHeatBal->HeatReclaimRefrigeratedRack(DesupHtr.ReclaimHeatingSourceIndexNum);
     860            0 :                     if (!allocated(HeatReclaim.WaterHeatingDesuperheaterReclaimedHeat)) {
     861            0 :                         HeatReclaim.WaterHeatingDesuperheaterReclaimedHeat.allocate(state.dataWaterThermalTanks->numWaterHeaterDesuperheater);
     862            0 :                         for (auto &num : HeatReclaim.WaterHeatingDesuperheaterReclaimedHeat)
     863            0 :                             num = 0.0;
     864              :                     }
     865            0 :                     DesupHtr.ValidSourceType = true;
     866            0 :                     HeatReclaim.ReclaimEfficiencyTotal += DesupHtr.HeatReclaimRecoveryEff;
     867            0 :                     if (HeatReclaim.ReclaimEfficiencyTotal > 0.3) {
     868            0 :                         ShowSevereError(
     869              :                             state,
     870            0 :                             format("{} = {}:  sum of heat reclaim recovery efficiencies from the same source coil: \"{}\" cannot be over 0.3",
     871              :                                    cCurrentModuleObject,
     872            0 :                                    DesupHtr.Name,
     873            0 :                                    DesupHtr.HeatingSourceName));
     874            0 :                         ErrorsFound = true;
     875              :                     }
     876              :                 }
     877            0 :                 break;
     878              :             }
     879           12 :         } else if ((Util::SameString(heatSourceObjType, "Refrigeration:Condenser:AirCooled")) ||
     880           12 :                    (Util::SameString(heatSourceObjType, "Refrigeration:Condenser:EvaporativeCooled")) ||
     881           12 :                    (Util::SameString(heatSourceObjType, "Refrigeration:Condenser:WaterCooled"))) {
     882            0 :             DesupHtr.ReclaimHeatingSource = ReclaimHeatObjectType::CondenserRefrigeration;
     883            0 :             for (int CondNum = 1; CondNum <= state.dataRefrigCase->NumRefrigCondensers; ++CondNum) {
     884            0 :                 if (!Util::SameString(state.dataHeatBal->HeatReclaimRefrigCondenser(CondNum).Name, cAlphaArgs(10))) continue;
     885            0 :                 DesupHtr.ReclaimHeatingSourceIndexNum = CondNum;
     886            0 :                 if (allocated(state.dataHeatBal->HeatReclaimRefrigCondenser)) {
     887              :                     DataHeatBalance::HeatReclaimDataBase &HeatReclaim =
     888            0 :                         state.dataHeatBal->HeatReclaimRefrigCondenser(DesupHtr.ReclaimHeatingSourceIndexNum);
     889            0 :                     if (!allocated(HeatReclaim.WaterHeatingDesuperheaterReclaimedHeat)) {
     890            0 :                         HeatReclaim.WaterHeatingDesuperheaterReclaimedHeat.allocate(state.dataWaterThermalTanks->numWaterHeaterDesuperheater);
     891            0 :                         for (auto &num : HeatReclaim.WaterHeatingDesuperheaterReclaimedHeat)
     892            0 :                             num = 0.0;
     893              :                     }
     894            0 :                     DesupHtr.ValidSourceType = true;
     895            0 :                     HeatReclaim.ReclaimEfficiencyTotal += DesupHtr.HeatReclaimRecoveryEff;
     896            0 :                     if (HeatReclaim.ReclaimEfficiencyTotal > 0.9) {
     897            0 :                         ShowSevereError(
     898              :                             state,
     899            0 :                             format("{} = {}:  sum of heat reclaim recovery efficiencies from the same source coil: \"{}\" cannot be over 0.9",
     900              :                                    cCurrentModuleObject,
     901            0 :                                    DesupHtr.Name,
     902            0 :                                    DesupHtr.HeatingSourceName));
     903            0 :                         ErrorsFound = true;
     904              :                     }
     905              :                 }
     906            0 :                 break;
     907              :             }
     908            9 :         } else if (Util::SameString(heatSourceObjType, "Coil:Cooling:DX:SingleSpeed") ||
     909            6 :                    Util::SameString(heatSourceObjType, "Coil:Cooling:DX:TwoSpeed") ||
     910           12 :                    Util::SameString(heatSourceObjType, "Coil:Cooling:DX:MultiSpeed") ||
     911            8 :                    Util::SameString(heatSourceObjType, "Coil:Cooling:DX:TwoStageWithHumidityControlMode")) {
     912              : 
     913            4 :             if (Util::SameString(heatSourceObjType, "Coil:Cooling:DX:SingleSpeed")) {
     914            3 :                 DesupHtr.ReclaimHeatingSource = ReclaimHeatObjectType::DXCooling;
     915            1 :             } else if (Util::SameString(heatSourceObjType, "Coil:Cooling:DX:TwoStageWithHumidityControlMode")) {
     916            0 :                 DesupHtr.ReclaimHeatingSource = ReclaimHeatObjectType::DXMultiMode;
     917              :             } else {
     918            1 :                 DesupHtr.ReclaimHeatingSource = ReclaimHeatObjectType::DXMultiSpeed;
     919              :             }
     920            4 :             DXCoils::GetDXCoilIndex(state, DesupHtr.HeatingSourceName, DesupHtr.ReclaimHeatingSourceIndexNum, errFlag, cCurrentModuleObject);
     921            4 :             if (allocated(state.dataHeatBal->HeatReclaimDXCoil)) {
     922            4 :                 DataHeatBalance::HeatReclaimDataBase &HeatReclaim = state.dataHeatBal->HeatReclaimDXCoil(DesupHtr.ReclaimHeatingSourceIndexNum);
     923            4 :                 if (!allocated(HeatReclaim.WaterHeatingDesuperheaterReclaimedHeat)) {
     924            3 :                     HeatReclaim.WaterHeatingDesuperheaterReclaimedHeat.allocate(state.dataWaterThermalTanks->numWaterHeaterDesuperheater);
     925            7 :                     for (auto &num : HeatReclaim.WaterHeatingDesuperheaterReclaimedHeat)
     926            4 :                         num = 0.0;
     927              :                 }
     928            4 :                 DesupHtr.ValidSourceType = true;
     929            4 :                 HeatReclaim.ReclaimEfficiencyTotal += DesupHtr.HeatReclaimRecoveryEff;
     930            4 :                 if (HeatReclaim.ReclaimEfficiencyTotal > 0.3) {
     931            0 :                     ShowSevereError(state,
     932            0 :                                     format("{} = {}:  sum of heat reclaim recovery efficiencies from the same source coil: \"{}\" cannot be over 0.3",
     933              :                                            cCurrentModuleObject,
     934            0 :                                            DesupHtr.Name,
     935            0 :                                            DesupHtr.HeatingSourceName));
     936            0 :                     ErrorsFound = true;
     937              :                 }
     938              :             }
     939            4 :         } else if (Util::SameString(heatSourceObjType, "Coil:Cooling:DX:VariableSpeed") ||
     940            4 :                    Util::SameString(heatSourceObjType, "Coil:Cooling:WaterToAirHeatPump:VariableSpeedEquationFit")) {
     941              : 
     942            1 :             if (Util::SameString(heatSourceObjType, "Coil:Cooling:DX:VariableSpeed")) {
     943            0 :                 DesupHtr.ReclaimHeatingSource = ReclaimHeatObjectType::DXVariableCooling;
     944              :             } else {
     945            1 :                 DesupHtr.ReclaimHeatingSource = ReclaimHeatObjectType::AirWaterHeatPumpVSEQ;
     946              :             }
     947            1 :             DesupHtr.ReclaimHeatingSourceIndexNum = VariableSpeedCoils::GetCoilIndexVariableSpeed(state, heatSourceObjType, cAlphaArgs(10), errFlag);
     948            1 :             if (allocated(state.dataHeatBal->HeatReclaimVS_Coil)) {
     949            1 :                 DataHeatBalance::HeatReclaimDataBase &HeatReclaim = state.dataHeatBal->HeatReclaimVS_Coil(DesupHtr.ReclaimHeatingSourceIndexNum);
     950            1 :                 if (!allocated(HeatReclaim.WaterHeatingDesuperheaterReclaimedHeat)) {
     951            1 :                     HeatReclaim.WaterHeatingDesuperheaterReclaimedHeat.allocate(state.dataWaterThermalTanks->numWaterHeaterDesuperheater);
     952            2 :                     for (auto &num : HeatReclaim.WaterHeatingDesuperheaterReclaimedHeat)
     953            1 :                         num = 0.0;
     954              :                 }
     955            1 :                 DesupHtr.ValidSourceType = true;
     956            1 :                 HeatReclaim.ReclaimEfficiencyTotal += DesupHtr.HeatReclaimRecoveryEff;
     957            1 :                 if (HeatReclaim.ReclaimEfficiencyTotal > 0.3) {
     958            0 :                     ShowSevereError(state,
     959            0 :                                     format("{} = {}:  sum of heat reclaim recovery efficiencies from the same source coil: \"{}\" cannot be over 0.3",
     960              :                                            cCurrentModuleObject,
     961            0 :                                            DesupHtr.Name,
     962            0 :                                            DesupHtr.HeatingSourceName));
     963            0 :                     ErrorsFound = true;
     964              :                 }
     965              :             }
     966            1 :         } else if (Util::SameString(heatSourceObjType, "Coil:Cooling:WaterToAirHeatPump:EquationFit")) {
     967            1 :             DesupHtr.ReclaimHeatingSource = ReclaimHeatObjectType::AirWaterHeatPumpEQ;
     968            1 :             DesupHtr.ReclaimHeatingSourceIndexNum = WaterToAirHeatPumpSimple::GetCoilIndex(state, heatSourceObjType, cAlphaArgs(10), errFlag);
     969            1 :             if (allocated(state.dataHeatBal->HeatReclaimSimple_WAHPCoil)) {
     970              :                 DataHeatBalance::HeatReclaimDataBase &HeatReclaim =
     971            1 :                     state.dataHeatBal->HeatReclaimSimple_WAHPCoil(DesupHtr.ReclaimHeatingSourceIndexNum);
     972            1 :                 if (!allocated(HeatReclaim.WaterHeatingDesuperheaterReclaimedHeat)) {
     973            1 :                     HeatReclaim.WaterHeatingDesuperheaterReclaimedHeat.allocate(state.dataWaterThermalTanks->numWaterHeaterDesuperheater);
     974            2 :                     for (auto &num : HeatReclaim.WaterHeatingDesuperheaterReclaimedHeat)
     975            1 :                         num = 0.0;
     976              :                 }
     977            1 :                 DesupHtr.ValidSourceType = true;
     978            1 :                 HeatReclaim.ReclaimEfficiencyTotal += DesupHtr.HeatReclaimRecoveryEff;
     979            1 :                 if (HeatReclaim.ReclaimEfficiencyTotal > 0.3) {
     980            0 :                     ShowSevereError(state,
     981            0 :                                     format("{} = {}:  sum of heat reclaim recovery efficiencies from the same source coil: \"{}\" cannot be over 0.3",
     982              :                                            cCurrentModuleObject,
     983            0 :                                            DesupHtr.Name,
     984            0 :                                            DesupHtr.HeatingSourceName));
     985            0 :                     ErrorsFound = true;
     986              :                 }
     987              :             }
     988            0 :         } else if (Util::SameString(heatSourceObjType, "Coil:Cooling:DX")) {
     989            0 :             DesupHtr.ReclaimHeatingSource = ReclaimHeatObjectType::CoilCoolingDX;
     990            0 :             DesupHtr.ReclaimHeatingSourceIndexNum = CoilCoolingDX::factory(state, cAlphaArgs(10));
     991            0 :             if (DesupHtr.ReclaimHeatingSourceIndexNum < 0) {
     992            0 :                 ShowSevereError(
     993              :                     state,
     994            0 :                     format("{}={}, could not find desuperheater coil {}={}", cCurrentModuleObject, DesupHtr.Name, cAlphaArgs(9), cAlphaArgs(10)));
     995            0 :                 ErrorsFound = true;
     996              :             } else {
     997              :                 DataHeatBalance::HeatReclaimDataBase &HeatReclaim =
     998            0 :                     state.dataCoilCoolingDX->coilCoolingDXs[DesupHtr.ReclaimHeatingSourceIndexNum].reclaimHeat;
     999            0 :                 if (!allocated(HeatReclaim.WaterHeatingDesuperheaterReclaimedHeat)) {
    1000            0 :                     HeatReclaim.WaterHeatingDesuperheaterReclaimedHeat.allocate(state.dataWaterThermalTanks->numWaterHeaterDesuperheater);
    1001            0 :                     for (auto &num : HeatReclaim.WaterHeatingDesuperheaterReclaimedHeat)
    1002            0 :                         num = 0.0;
    1003              :                 }
    1004            0 :                 DesupHtr.ValidSourceType = true;
    1005            0 :                 HeatReclaim.ReclaimEfficiencyTotal += DesupHtr.HeatReclaimRecoveryEff;
    1006            0 :                 if (HeatReclaim.ReclaimEfficiencyTotal > 0.3) {
    1007            0 :                     ShowSevereError(
    1008              :                         state,
    1009            0 :                         format("{}, \"{}\" sum of heat reclaim recovery efficiencies from the same source coil: \"{}\" cannot be over 0.3",
    1010              :                                cCurrentModuleObject,
    1011            0 :                                DesupHtr.Name,
    1012            0 :                                DesupHtr.HeatingSourceName));
    1013            0 :                     ErrorsFound = true;
    1014              :                 }
    1015              :             }
    1016              :         } else {
    1017            0 :             ShowSevereError(state, format("{} = {}:", cCurrentModuleObject, DesupHtr.Name));
    1018            0 :             ShowContinueError(state, " desuperheater can only be used with Coil:Cooling:DX:SingleSpeed, ");
    1019            0 :             ShowContinueError(state,
    1020              :                               " Coil:Cooling:DX:TwoSpeed, Coil:Cooling:DX:MultiSpeed, Coil:Cooling:DX:TwoStageWithHumidityControlMode, "
    1021              :                               "Coil:Cooling:DX:VariableSpeed, Coil:Cooling:WaterToAirHeatPump:VariableSpeedEquationFit, "
    1022              :                               "Coil:Cooling:WaterToAirHeatPump:EquationFit, Refrigeration:CompressorRack,");
    1023            0 :             ShowContinueError(state, " Refrigeration:Condenser:AirCooled ,Refrigeration:Condenser:EvaporativeCooled, ");
    1024            0 :             ShowContinueError(state, " or Refrigeration:Condenser:WaterCooled.");
    1025            0 :             ShowContinueError(state, format(" Invalid desuperheater heat source object: {} \"{}\"", heatSourceObjType, cAlphaArgs(10)));
    1026            0 :             ErrorsFound = true;
    1027              :         }
    1028            6 :         if (errFlag) {
    1029            0 :             ShowContinueError(state, format("...occurs in {}={}", cCurrentModuleObject, DesupHtr.Name));
    1030            0 :             ErrorsFound = true;
    1031              :         }
    1032              : 
    1033            6 :         if (DesupHtr.ReclaimHeatingSourceIndexNum == 0 && DesupHtr.ReclaimHeatingSource != ReclaimHeatObjectType::CoilCoolingDX) {
    1034            0 :             ShowSevereError(state,
    1035            0 :                             format("{}, \"{}\" desuperheater heat source object not found: {} \"{}\"",
    1036              :                                    cCurrentModuleObject,
    1037            0 :                                    DesupHtr.Name,
    1038              :                                    heatSourceObjType,
    1039              :                                    cAlphaArgs(10)));
    1040            0 :             ErrorsFound = true;
    1041              :         }
    1042              : 
    1043            6 :         DesupHtr.OperatingWaterFlowRate = rNumericArgs(6);
    1044            6 :         if (DesupHtr.OperatingWaterFlowRate <= 0.0) {
    1045            0 :             ShowSevereError(state,
    1046            0 :                             format("{} = {}: {} must be greater than 0. {} = {:.6T}",
    1047              :                                    cCurrentModuleObject,
    1048            0 :                                    DesupHtr.Name,
    1049              :                                    cNumericFieldNames(6),
    1050              :                                    cNumericFieldNames(6),
    1051              :                                    rNumericArgs(6)));
    1052            0 :             ErrorsFound = true;
    1053              :         }
    1054              : 
    1055            6 :         DesupHtr.PumpElecPower = rNumericArgs(7);
    1056            6 :         if (DesupHtr.PumpElecPower < 0.0) {
    1057            0 :             ShowSevereError(state,
    1058            0 :                             format("{} = {}: {} must be >= 0. {} = {:.2T}",
    1059              :                                    cCurrentModuleObject,
    1060            0 :                                    DesupHtr.Name,
    1061              :                                    cNumericFieldNames(7),
    1062              :                                    cNumericFieldNames(7),
    1063              :                                    rNumericArgs(7)));
    1064            0 :             ErrorsFound = true;
    1065              :         }
    1066              : 
    1067            6 :         if ((DesupHtr.PumpElecPower / DesupHtr.OperatingWaterFlowRate) > 7.9264e6) {
    1068            0 :             ShowWarningError(state,
    1069            0 :                              format("{} = {}: {} to {} ratio > 7.9264E6. {} to {} = {:.3T}",
    1070              :                                     cCurrentModuleObject,
    1071            0 :                                     DesupHtr.Name,
    1072              :                                     cNumericFieldNames(7),
    1073              :                                     cNumericFieldNames(6),
    1074              :                                     cNumericFieldNames(7),
    1075              :                                     cNumericFieldNames(6),
    1076            0 :                                     (DesupHtr.PumpElecPower / DesupHtr.OperatingWaterFlowRate)));
    1077            0 :             ShowContinueError(state, format(" Suggest reducing {} or increasing {}.", cNumericFieldNames(7), cNumericFieldNames(6)));
    1078            0 :             ShowContinueError(state, " The simulation will continue using the user defined values.");
    1079              :         }
    1080              : 
    1081            6 :         DesupHtr.PumpFracToWater = rNumericArgs(8);
    1082            6 :         if (DesupHtr.PumpFracToWater < 0.0 || DesupHtr.PumpFracToWater > 1.0) {
    1083            0 :             ShowSevereError(state,
    1084            0 :                             format("{} = {}: {} must be >= 0 or <= 1. {} = {:.3T}",
    1085              :                                    cCurrentModuleObject,
    1086            0 :                                    DesupHtr.Name,
    1087              :                                    cNumericFieldNames(8),
    1088              :                                    cNumericFieldNames(8),
    1089              :                                    rNumericArgs(8)));
    1090            0 :             ErrorsFound = true;
    1091              :         }
    1092              : 
    1093            6 :         DesupHtr.OnCycParaLoad = rNumericArgs(9);
    1094            6 :         if (DesupHtr.OnCycParaLoad < 0.0) {
    1095            0 :             ShowSevereError(state,
    1096            0 :                             format("{} = {}: {} must be >= 0. {} = {:.2T}",
    1097              :                                    cCurrentModuleObject,
    1098            0 :                                    DesupHtr.Name,
    1099              :                                    cNumericFieldNames(9),
    1100              :                                    cNumericFieldNames(9),
    1101              :                                    rNumericArgs(9)));
    1102            0 :             ErrorsFound = true;
    1103              :         }
    1104              : 
    1105            6 :         DesupHtr.OffCycParaLoad = rNumericArgs(10);
    1106            6 :         if (DesupHtr.OffCycParaLoad < 0.0) {
    1107            0 :             ShowSevereError(state,
    1108            0 :                             format("{} = {}: {} must be >= 0. {} = {:.2T}",
    1109              :                                    cCurrentModuleObject,
    1110            0 :                                    DesupHtr.Name,
    1111              :                                    cNumericFieldNames(10),
    1112              :                                    cNumericFieldNames(10),
    1113              :                                    rNumericArgs(10)));
    1114            0 :             ErrorsFound = true;
    1115              :         }
    1116            6 :     }
    1117              : 
    1118            5 :     if (ErrorsFound) {
    1119            0 :         ShowFatalError(state, format("Errors found in getting {} input. Preceding condition causes termination.", cCurrentModuleObject));
    1120              :     }
    1121              : 
    1122            5 :     return ErrorsFound;
    1123              : 
    1124            5 : } // namespace WaterThermalTanks
    1125              : 
    1126           10 : bool getHPWaterHeaterInput(EnergyPlusData &state)
    1127              : {
    1128              : 
    1129              :     static constexpr std::string_view routineName = "getHPWaterHeaterInput";
    1130           10 :     bool ErrorsFound = false;
    1131              : 
    1132           10 :     int const NumPumpedCondenser = state.dataInputProcessing->inputProcessor->getNumObjectsFound(
    1133              :         state, cHPWHPumpedCondenser); // number of WaterHeater:HeatPump:PumpedCondenser objects
    1134              :     int nAlphaOffset;                 // the difference of array location between alpha items between pumped and wrapped condensers
    1135              :     int nNumericOffset;               // the difference of array location between numeric items between pumped and wrapped condensers
    1136              :     int nNumPossibleNumericArgs;      // the number of possible numeric arguments in the idd
    1137              :     int nNumPossibleAlphaArgs;        // the number of possible numeric arguments in the idd
    1138              : 
    1139              :     // For looking up in IDF/epJSON, you need the index that corresponds to the actual object type (Pumped or Wrapped)
    1140              :     int HPWaterHeaterNumOfSpecificType;
    1141              : 
    1142           22 :     for (int HPWaterHeaterNum = 1; HPWaterHeaterNum <= state.dataWaterThermalTanks->numHeatPumpWaterHeater; ++HPWaterHeaterNum) {
    1143              : 
    1144              :         // Create reference to current HPWH object in array.
    1145           12 :         HeatPumpWaterHeaterData &HPWH = state.dataWaterThermalTanks->HPWaterHeater(HPWaterHeaterNum);
    1146              : 
    1147              :         // Initialize the offsets to zero
    1148           12 :         nAlphaOffset = 0;
    1149           12 :         nNumericOffset = 0;
    1150              : 
    1151              :         DataLoopNode::ConnectionObjectType objType;
    1152              : 
    1153           12 :         if (HPWaterHeaterNum <= NumPumpedCondenser) {
    1154              :             // Pumped Condenser
    1155            7 :             state.dataIPShortCut->cCurrentModuleObject = cHPWHPumpedCondenser;
    1156            7 :             objType = DataLoopNode::ConnectionObjectType::WaterHeaterHeatPumpPumpedCondenser;
    1157            7 :             HPWH.HPWHType = DataPlant::PlantEquipmentType::HeatPumpWtrHeaterPumped;
    1158            7 :             nNumPossibleAlphaArgs = 29;
    1159            7 :             nNumPossibleNumericArgs = 9;
    1160              :             // Actual index of Pumped type
    1161            7 :             HPWaterHeaterNumOfSpecificType = HPWaterHeaterNum;
    1162              :         } else {
    1163              :             // Wrapped Condenser
    1164            5 :             state.dataIPShortCut->cCurrentModuleObject = cHPWHWrappedCondenser;
    1165            5 :             objType = DataLoopNode::ConnectionObjectType::WaterHeaterHeatPumpWrappedCondenser;
    1166            5 :             HPWH.HPWHType = DataPlant::PlantEquipmentType::HeatPumpWtrHeaterWrapped;
    1167            5 :             nNumPossibleAlphaArgs = 27;
    1168            5 :             nNumPossibleNumericArgs = 10;
    1169              :             // Actual index of Wrapped type
    1170            5 :             HPWaterHeaterNumOfSpecificType = HPWaterHeaterNum - NumPumpedCondenser;
    1171              :         }
    1172              : 
    1173              :         int NumAlphas;
    1174              :         int NumNums;
    1175              :         int IOStat;
    1176           24 :         state.dataInputProcessing->inputProcessor->getObjectItem(state,
    1177           12 :                                                                  state.dataIPShortCut->cCurrentModuleObject,
    1178              :                                                                  HPWaterHeaterNumOfSpecificType,
    1179           12 :                                                                  state.dataIPShortCut->cAlphaArgs,
    1180              :                                                                  NumAlphas,
    1181           12 :                                                                  state.dataIPShortCut->rNumericArgs,
    1182              :                                                                  NumNums,
    1183              :                                                                  IOStat,
    1184           12 :                                                                  state.dataIPShortCut->lNumericFieldBlanks,
    1185           12 :                                                                  state.dataIPShortCut->lAlphaFieldBlanks,
    1186           12 :                                                                  state.dataIPShortCut->cAlphaFieldNames,
    1187           12 :                                                                  state.dataIPShortCut->cNumericFieldNames);
    1188              : 
    1189           12 :         ErrorObjectHeader eoh{routineName, state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)};
    1190              : 
    1191              :         // Copy those lists into C++ std::maps // Why, no really why?  This is really dumb
    1192           12 :         std::map<int, std::string> hpwhAlpha;
    1193           12 :         std::map<int, Real64> hpwhNumeric;
    1194           12 :         std::map<int, bool> hpwhAlphaBlank;
    1195           12 :         std::map<int, bool> hpwhNumericBlank;
    1196           12 :         std::map<int, std::string> hpwhAlphaFieldNames;
    1197           12 :         std::map<int, std::string> hpwhNumericFieldNames;
    1198          116 :         for (int i = 1; i <= NumNums; ++i) {
    1199          104 :             hpwhNumeric[i] = state.dataIPShortCut->rNumericArgs(i);
    1200          104 :             hpwhNumericBlank[i] = state.dataIPShortCut->lNumericFieldBlanks(i);
    1201          104 :             hpwhNumericFieldNames[i] = state.dataIPShortCut->cNumericFieldNames(i);
    1202              :         }
    1203           26 :         for (int i = NumNums + 1; i <= nNumPossibleNumericArgs; ++i) {
    1204           14 :             hpwhNumericBlank[i] = true;
    1205              :         }
    1206          326 :         for (int i = 1; i <= NumAlphas; ++i) {
    1207          314 :             hpwhAlpha[i] = state.dataIPShortCut->cAlphaArgs(i);
    1208          314 :             hpwhAlphaBlank[i] = state.dataIPShortCut->lAlphaFieldBlanks(i);
    1209          314 :             hpwhAlphaFieldNames[i] = state.dataIPShortCut->cAlphaFieldNames(i);
    1210              :         }
    1211           36 :         for (int i = NumAlphas + 1; i <= nNumPossibleAlphaArgs; ++i) {
    1212           24 :             hpwhAlphaBlank[i] = true;
    1213              :         }
    1214           12 :         Util::IsNameEmpty(state, hpwhAlpha[1], state.dataIPShortCut->cCurrentModuleObject, ErrorsFound);
    1215              : 
    1216              :         // Name and type
    1217           12 :         HPWH.Name = hpwhAlpha[1];
    1218           12 :         HPWH.Type = state.dataIPShortCut->cCurrentModuleObject;
    1219              : 
    1220              :         // Availability Schedule
    1221              :         // convert schedule name to pointer
    1222           12 :         if (hpwhAlphaBlank[2]) {
    1223            6 :             HPWH.availSched = Sched::GetScheduleAlwaysOn(state);
    1224            6 :         } else if ((HPWH.availSched = Sched::GetSchedule(state, hpwhAlpha[2])) == nullptr) {
    1225            0 :             ShowSevereItemNotFound(state, eoh, hpwhAlphaFieldNames[2], hpwhAlpha[2]);
    1226            0 :             ErrorsFound = true;
    1227              :         }
    1228              : 
    1229              :         // Compressor Setpoint Temperature Schedule
    1230              :         // convert schedule name to pointer
    1231           12 :         if (hpwhAlphaBlank[3]) {
    1232            0 :             ShowSevereEmptyField(state, eoh, hpwhAlphaFieldNames[3]);
    1233            0 :             ErrorsFound = true;
    1234           12 :         } else if ((HPWH.setptTempSched = Sched::GetSchedule(state, hpwhAlpha[3])) == nullptr) {
    1235            0 :             ShowSevereItemNotFound(state, eoh, hpwhAlphaFieldNames[3], hpwhAlpha[3]);
    1236            0 :             ErrorsFound = true;
    1237              :         }
    1238              : 
    1239              :         // Dead Band Temperature Difference
    1240           12 :         HPWH.DeadBandTempDiff = hpwhNumeric[1 + nNumericOffset];
    1241           12 :         if (HPWH.DeadBandTempDiff <= 0.0 || HPWH.DeadBandTempDiff > 20.0) {
    1242            0 :             ShowSevereError(state, format("{}=\"{}\", ", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    1243            0 :             ShowContinueError(state,
    1244            0 :                               format("{}{}",
    1245            0 :                                      hpwhNumericFieldNames[1 + nNumericOffset],
    1246            0 :                                      format(" difference must be > 0 and <= 20. Dead band = {:.1T}", hpwhNumeric[1 + nNumericOffset])));
    1247            0 :             ErrorsFound = true;
    1248              :         }
    1249              : 
    1250           12 :         if (HPWH.HPWHType == DataPlant::PlantEquipmentType::HeatPumpWtrHeaterPumped) {
    1251              : 
    1252              :             // Condenser Inlet/Outlet Nodes
    1253            7 :             HPWH.CondWaterInletNode = NodeInputManager::GetOnlySingleNode(state,
    1254            7 :                                                                           hpwhAlpha[4],
    1255              :                                                                           ErrorsFound,
    1256              :                                                                           objType,
    1257            7 :                                                                           HPWH.Name,
    1258              :                                                                           DataLoopNode::NodeFluidType::Water,
    1259              :                                                                           DataLoopNode::ConnectionType::Inlet,
    1260              :                                                                           NodeInputManager::CompFluidStream::Secondary,
    1261              :                                                                           DataLoopNode::ObjectIsParent);
    1262            7 :             HPWH.InletNodeName1 = hpwhAlpha[4];
    1263            7 :             HPWH.CondWaterOutletNode = NodeInputManager::GetOnlySingleNode(state,
    1264            7 :                                                                            hpwhAlpha[5],
    1265              :                                                                            ErrorsFound,
    1266              :                                                                            objType,
    1267            7 :                                                                            HPWH.Name,
    1268              :                                                                            DataLoopNode::NodeFluidType::Water,
    1269              :                                                                            DataLoopNode::ConnectionType::Outlet,
    1270              :                                                                            NodeInputManager::CompFluidStream::Secondary,
    1271              :                                                                            DataLoopNode::ObjectIsParent);
    1272            7 :             HPWH.OutletNodeName1 = hpwhAlpha[5];
    1273              : 
    1274              :             // Condenser Water Flow Rate
    1275            7 :             HPWH.OperatingWaterFlowRate = hpwhNumeric[2];
    1276            7 :             if (HPWH.OperatingWaterFlowRate <= 0.0 && hpwhNumeric[2] != Constant::AutoCalculate) {
    1277            0 :                 ShowSevereError(state, format("{}=\"{}\", ", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    1278            0 :                 ShowContinueError(state,
    1279            0 :                                   format("{} must be greater than 0. Condenser water flow rate = {:.6T}", hpwhNumericFieldNames[2], hpwhNumeric[2]));
    1280            0 :                 ErrorsFound = true;
    1281              :             }
    1282              : 
    1283            5 :         } else if (HPWH.HPWHType == DataPlant::PlantEquipmentType::HeatPumpWtrHeaterWrapped) {
    1284              : 
    1285              :             // Wrapped Condenser Location
    1286            5 :             HPWH.WrappedCondenserBottomLocation = hpwhNumeric[2 + nNumericOffset];
    1287            5 :             HPWH.WrappedCondenserTopLocation = hpwhNumeric[3 + nNumericOffset];
    1288              : 
    1289            5 :             if (HPWH.WrappedCondenserBottomLocation < 0.0) {
    1290            0 :                 ShowSevereError(state, format("{}=\"{}\", ", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    1291            0 :                 ShowContinueError(state,
    1292            0 :                                   format("{} must be greater than 0. Condenser bottom location = {:.6T}",
    1293            0 :                                          hpwhNumericFieldNames[2],
    1294            0 :                                          HPWH.WrappedCondenserBottomLocation));
    1295            0 :                 ErrorsFound = true;
    1296              :             }
    1297              : 
    1298            5 :             if (HPWH.WrappedCondenserBottomLocation >= HPWH.WrappedCondenserTopLocation) {
    1299            0 :                 ShowSevereError(state, format("{}=\"{}\", ", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    1300            0 :                 ShowContinueError(state,
    1301            0 :                                   format("{} ({:.6T}) must be greater than {} ({:.6T}).",
    1302            0 :                                          HPWH.WrappedCondenserTopLocation,
    1303            0 :                                          hpwhNumericFieldNames[2],
    1304            0 :                                          hpwhNumericFieldNames[3],
    1305            0 :                                          HPWH.WrappedCondenserBottomLocation));
    1306            0 :                 ErrorsFound = true;
    1307              :             }
    1308              : 
    1309              :             // Reset the offset
    1310            5 :             nAlphaOffset = -2;
    1311            5 :             nNumericOffset = 1;
    1312              : 
    1313              :         } else {
    1314            0 :             assert(0);
    1315              :         }
    1316              : 
    1317              :         // Evaporator Air Flow Rate
    1318           12 :         HPWH.OperatingAirFlowRate = hpwhNumeric[3 + nNumericOffset];
    1319           12 :         if (HPWH.OperatingAirFlowRate <= 0.0 && hpwhNumeric[3 + nNumericOffset] != Constant::AutoCalculate) {
    1320            0 :             ShowSevereError(state, format("{}=\"{}\", ", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    1321            0 :             ShowContinueError(state,
    1322            0 :                               format("{}{}",
    1323            0 :                                      hpwhNumericFieldNames[3 + nNumericOffset],
    1324            0 :                                      format(" must be greater than 0. Evaporator air flow rate = {:.6T}", hpwhNumeric[3 + nNumericOffset])));
    1325            0 :             ErrorsFound = true;
    1326              :         }
    1327              : 
    1328              :         // Inlet Air Configuration
    1329           12 :         HPWH.InletAirConfiguration = static_cast<WTTAmbientTemp>(getEnumValue(HPWHAmbientTempNamesUC, Util::makeUPPER(hpwhAlpha[6 + nAlphaOffset])));
    1330           12 :         switch (HPWH.InletAirConfiguration) {
    1331            5 :         case WTTAmbientTemp::Schedule: {
    1332              : 
    1333              :             // Inlet Air Temperature Schedule
    1334            5 :             if (hpwhAlphaBlank[11 + nAlphaOffset]) {
    1335            0 :                 ShowSevereEmptyField(state, eoh, hpwhAlphaFieldNames[11 + nAlphaOffset]);
    1336            0 :                 ErrorsFound = true;
    1337            5 :             } else if ((HPWH.ambientTempSched = Sched::GetSchedule(state, hpwhAlpha[11 + nAlphaOffset])) == nullptr) {
    1338            0 :                 ShowSevereItemNotFound(state, eoh, hpwhAlphaFieldNames[11 + nAlphaOffset], hpwhAlpha[11 + nAlphaOffset]);
    1339            0 :                 ErrorsFound = true;
    1340              :             }
    1341              : 
    1342              :             // Inlet Air Humidity Schedule
    1343            5 :             if (hpwhAlphaBlank[12 + nAlphaOffset]) {
    1344            0 :                 ShowSevereEmptyField(state, eoh, hpwhAlphaFieldNames[12 + nAlphaOffset]);
    1345            0 :                 ErrorsFound = true;
    1346            5 :             } else if ((HPWH.ambientRHSched = Sched::GetSchedule(state, hpwhAlpha[12 + nAlphaOffset])) == nullptr) {
    1347            0 :                 ShowSevereItemNotFound(state, eoh, hpwhAlphaFieldNames[12 + nAlphaOffset], hpwhAlpha[12 + nAlphaOffset]);
    1348            0 :                 ErrorsFound = true;
    1349            5 :             } else if (!HPWH.ambientRHSched->checkMinMaxVals(state, Clusive::In, 0.0, Clusive::In, 1.0)) {
    1350            0 :                 Sched::ShowSevereBadMinMax(
    1351            0 :                     state, eoh, hpwhAlphaFieldNames[12 + nAlphaOffset], hpwhAlpha[12 + nAlphaOffset], Clusive::In, 0.0, Clusive::In, 1.0);
    1352            0 :                 ErrorsFound = true;
    1353              :             }
    1354            5 :         } break;
    1355              : 
    1356            4 :         case WTTAmbientTemp::ZoneAndOA:
    1357              :         case WTTAmbientTemp::TempZone: {
    1358              : 
    1359              :             // Inlet Air Zone
    1360            4 :             if (!hpwhAlphaBlank[13 + nAlphaOffset]) {
    1361            4 :                 HPWH.AmbientTempZone = Util::FindItemInList(hpwhAlpha[13 + nAlphaOffset], state.dataHeatBal->Zone);
    1362            4 :                 if (HPWH.AmbientTempZone == 0) {
    1363            2 :                     ShowSevereError(state, format("{}=\"{}\", not found", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    1364            2 :                     ShowContinueError(state, format("{}=\"{}\".", hpwhAlphaFieldNames[13 + nAlphaOffset], hpwhAlpha[13 + nAlphaOffset]));
    1365            2 :                     ErrorsFound = true;
    1366              :                 }
    1367              :             } else {
    1368            0 :                 ShowSevereError(state, format("{}=\"{}\", ", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    1369            0 :                 ShowContinueError(state, format("required {} is blank.", hpwhAlphaFieldNames[13 + nAlphaOffset]));
    1370            0 :                 ErrorsFound = true;
    1371              :             }
    1372            4 :             break;
    1373              :         }
    1374            3 :         default:
    1375              :         case WTTAmbientTemp::OutsideAir:
    1376            3 :             break;
    1377              :         }
    1378              : 
    1379              :         // Read air inlet nodes after mixer/splitter nodes have been read in (state.dataIPShortCut->cAlphaArgs 7-10),
    1380              :         // Node_ConnectionType differs for inlet node if mixer/splitter node exists
    1381              : 
    1382              :         // Tank Name
    1383              :         // We will verify this exists and is the right kind of tank later when the tanks are all loaded.
    1384           12 :         HPWH.TankName = hpwhAlpha[15 + nAlphaOffset];
    1385           12 :         HPWH.TankType = hpwhAlpha[14 + nAlphaOffset];
    1386              : 
    1387              :         // Use Side Inlet/Outlet
    1388              :         // Get the water heater tank use side inlet node names for HPWHs connected to a plant loop
    1389              :         // Save the name of the node for use with set up comp sets
    1390           12 :         HPWH.InletNodeName2 = hpwhAlpha[16 + nAlphaOffset];
    1391           12 :         HPWH.OutletNodeName2 = hpwhAlpha[17 + nAlphaOffset];
    1392              : 
    1393           12 :         if (!hpwhAlphaBlank[16 + nAlphaOffset] && !hpwhAlphaBlank[17 + nAlphaOffset]) {
    1394            7 :             HPWH.WHUseInletNode = NodeInputManager::GetOnlySingleNode(state,
    1395            7 :                                                                       HPWH.InletNodeName2,
    1396              :                                                                       ErrorsFound,
    1397              :                                                                       objType,
    1398            7 :                                                                       HPWH.Name,
    1399              :                                                                       DataLoopNode::NodeFluidType::Water,
    1400              :                                                                       DataLoopNode::ConnectionType::Inlet,
    1401              :                                                                       NodeInputManager::CompFluidStream::Primary,
    1402              :                                                                       DataLoopNode::ObjectIsParent);
    1403           14 :             HPWH.WHUseOutletNode = NodeInputManager::GetOnlySingleNode(state,
    1404            7 :                                                                        HPWH.OutletNodeName2,
    1405              :                                                                        ErrorsFound,
    1406              :                                                                        objType,
    1407            7 :                                                                        HPWH.Name,
    1408              :                                                                        DataLoopNode::NodeFluidType::Water,
    1409              :                                                                        DataLoopNode::ConnectionType::Outlet,
    1410              :                                                                        NodeInputManager::CompFluidStream::Primary,
    1411              :                                                                        DataLoopNode::ObjectIsParent);
    1412              :         }
    1413              : 
    1414              :         // DX Coil
    1415              :         // get Coil:DX:HeatPumpWaterHeater object
    1416           12 :         HPWH.DXCoilName = hpwhAlpha[19 + nAlphaOffset];
    1417           12 :         HPWH.DXCoilType = hpwhAlpha[18 + nAlphaOffset];
    1418              : 
    1419              :         // check that the DX Coil exists
    1420           12 :         bool DXCoilErrFlag = false;
    1421           12 :         bool bIsVScoil = false;
    1422           12 :         DXCoils::GetDXCoilIndex(state, HPWH.DXCoilName, HPWH.DXCoilNum, DXCoilErrFlag, state.dataIPShortCut->cCurrentModuleObject, true);
    1423           12 :         if (DXCoilErrFlag) {
    1424              :             // This could be a variable speed heat pump water heater
    1425            0 :             bool bVSCoilErrFlag = false;
    1426              : 
    1427            0 :             bool checkIHPFirst = IntegratedHeatPump::IHPInModel(state);
    1428            0 :             if (checkIHPFirst) {
    1429            0 :                 HPWH.DXCoilNum =
    1430            0 :                     IntegratedHeatPump::GetCoilIndexIHP(state, "COILSYSTEM:INTEGRATEDHEATPUMP:AIRSOURCE", HPWH.DXCoilName, bVSCoilErrFlag);
    1431              : 
    1432            0 :                 if (!bVSCoilErrFlag) {
    1433            0 :                     HPWH.bIsIHP = true;
    1434              :                 }
    1435              :             }
    1436              : 
    1437            0 :             if (bVSCoilErrFlag || !checkIHPFirst) {
    1438            0 :                 bVSCoilErrFlag = false;
    1439            0 :                 HPWH.DXCoilNum = VariableSpeedCoils::GetCoilIndexVariableSpeed(
    1440            0 :                     state, "Coil:WaterHeating:AirToWaterHeatPump:VariableSpeed", HPWH.DXCoilName, bVSCoilErrFlag);
    1441              : 
    1442            0 :                 if (bVSCoilErrFlag) {
    1443            0 :                     ShowContinueError(state, format("...occurs in {} ={}", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    1444            0 :                     ShowContinueError(state, format("...could not find either DXCoils::DXCoil or Variable Speed Coil {}", HPWH.DXCoilName));
    1445            0 :                     ErrorsFound = true;
    1446              :                 }
    1447              :             }
    1448              : 
    1449            0 :             bIsVScoil = true;
    1450            0 :             HPWH.DXCoilTypeNum = 0;
    1451            0 :             if (HPWH.bIsIHP) {
    1452            0 :                 HPWH.DXCoilType = "COILSYSTEM:INTEGRATEDHEATPUMP:AIRSOURCE";
    1453              :             } else {
    1454            0 :                 HPWH.DXCoilType = state.dataVariableSpeedCoils->VarSpeedCoil(HPWH.DXCoilNum).VarSpeedCoilType;
    1455              :             }
    1456              :         } else {
    1457              :             // this is a single speed coil
    1458           12 :             DXCoils::DXCoilData &Coil = state.dataDXCoils->DXCoil(HPWH.DXCoilNum);
    1459           12 :             if (!Util::SameString(HPWH.DXCoilType, Coil.DXCoilType)) {
    1460            0 :                 ShowSevereError(state, format("{}=\"{}\", ", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    1461            0 :                 ShowContinueError(state, format("specifies the coil {}=\"{}\".", HPWH.DXCoilType, HPWH.DXCoilName));
    1462            0 :                 ShowContinueError(state, format("However, {} is a coil of type {}.", HPWH.DXCoilName, Coil.DXCoilType));
    1463            0 :                 ErrorsFound = true;
    1464              :             }
    1465           12 :             HPWH.DXCoilTypeNum = Coil.DXCoilType_Num;
    1466              :         }
    1467              : 
    1468              :         // Make sure that the coil and tank are compatible.
    1469           12 :         if (bIsVScoil) {
    1470            0 :             if (HPWH.HPWHType != DataPlant::PlantEquipmentType::HeatPumpWtrHeaterPumped) {
    1471            0 :                 ShowSevereError(state, format("{}=\"{}\":", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    1472            0 :                 ShowContinueError(state,
    1473              :                                   "Coil:WaterHeating:AirToWaterHeatPump:VariableSpeed can only be used with a pumped condenser heat pump "
    1474              :                                   "water heater.");
    1475            0 :                 ErrorsFound = true;
    1476              :             }
    1477              :         } else {
    1478           12 :             if (!((HPWH.DXCoilTypeNum == HVAC::CoilDX_HeatPumpWaterHeaterPumped &&
    1479            7 :                    HPWH.HPWHType == DataPlant::PlantEquipmentType::HeatPumpWtrHeaterPumped) ||
    1480            5 :                   (HPWH.DXCoilTypeNum == HVAC::CoilDX_HeatPumpWaterHeaterWrapped &&
    1481            5 :                    HPWH.HPWHType == DataPlant::PlantEquipmentType::HeatPumpWtrHeaterWrapped))) {
    1482            0 :                 ShowSevereError(state, format("{}=\"{}\":", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    1483            0 :                 std::string ExpectedCoilType;
    1484            0 :                 if (HPWH.HPWHType == DataPlant::PlantEquipmentType::HeatPumpWtrHeaterPumped) {
    1485            0 :                     ExpectedCoilType = HVAC::cAllCoilTypes(HVAC::CoilDX_HeatPumpWaterHeaterPumped);
    1486            0 :                 } else if (HPWH.HPWHType == DataPlant::PlantEquipmentType::HeatPumpWtrHeaterWrapped) {
    1487            0 :                     ExpectedCoilType = HVAC::cAllCoilTypes(HVAC::CoilDX_HeatPumpWaterHeaterWrapped);
    1488              :                 } else {
    1489            0 :                     assert(0);
    1490              :                 }
    1491            0 :                 ShowContinueError(state, format("can only be used with {}", ExpectedCoilType));
    1492            0 :                 ErrorsFound = true;
    1493            0 :             }
    1494              :         }
    1495              : 
    1496              :         // Dummy condenser Inlet/Outlet Nodes for wrapped tanks
    1497           12 :         if (HPWH.DXCoilTypeNum == HVAC::CoilDX_HeatPumpWaterHeaterWrapped) {
    1498            5 :             DXCoils::DXCoilData &Coil = state.dataDXCoils->DXCoil(HPWH.DXCoilNum);
    1499              : 
    1500            5 :             HPWH.InletNodeName1 = "DUMMY CONDENSER INLET " + Coil.Name;
    1501            5 :             HPWH.CondWaterInletNode = NodeInputManager::GetOnlySingleNode(state,
    1502            5 :                                                                           HPWH.InletNodeName1,
    1503              :                                                                           ErrorsFound,
    1504              :                                                                           objType,
    1505            5 :                                                                           HPWH.Name,
    1506              :                                                                           DataLoopNode::NodeFluidType::Water,
    1507              :                                                                           DataLoopNode::ConnectionType::Inlet,
    1508              :                                                                           NodeInputManager::CompFluidStream::Secondary,
    1509              :                                                                           DataLoopNode::ObjectIsParent);
    1510            5 :             HPWH.OutletNodeName1 = "DUMMY CONDENSER OUTLET " + Coil.Name;
    1511           10 :             HPWH.CondWaterOutletNode = NodeInputManager::GetOnlySingleNode(state,
    1512            5 :                                                                            HPWH.OutletNodeName1,
    1513              :                                                                            ErrorsFound,
    1514              :                                                                            objType,
    1515            5 :                                                                            HPWH.Name,
    1516              :                                                                            DataLoopNode::NodeFluidType::Water,
    1517              :                                                                            DataLoopNode::ConnectionType::Outlet,
    1518              :                                                                            NodeInputManager::CompFluidStream::Secondary,
    1519              :                                                                            DataLoopNode::ObjectIsParent);
    1520              :         }
    1521              : 
    1522              :         // Minimum Inlet Air Temperature for Compressor Operation
    1523           12 :         HPWH.MinAirTempForHPOperation = hpwhNumeric[4 + nNumericOffset];
    1524              : 
    1525              :         // Maximum Inlet Air Temperature for Compressor Operation
    1526           12 :         HPWH.MaxAirTempForHPOperation = hpwhNumeric[5 + nNumericOffset];
    1527           12 :         if (HPWH.MaxAirTempForHPOperation <= HPWH.MinAirTempForHPOperation) {
    1528            0 :             ShowWarningError(state,
    1529            0 :                              format("{}=\"{}\": maximum inlet air temperature for heat pump compressor operation",
    1530            0 :                                     state.dataIPShortCut->cCurrentModuleObject,
    1531            0 :                                     HPWH.Name));
    1532            0 :             ShowContinueError(state, "must be greater than the minimum inlet air temperature for heat pump compressor operation.");
    1533            0 :             ShowContinueError(state, format("...Minimum inlet air temperature = {:.1T}", HPWH.MinAirTempForHPOperation));
    1534            0 :             ShowContinueError(state, format("...Maximum inlet air temperature = {:.1T}", HPWH.MaxAirTempForHPOperation));
    1535              :         }
    1536              : 
    1537              :         // Compressor Location
    1538           12 :         HPWH.CrankcaseTempIndicator =
    1539           12 :             static_cast<CrankcaseHeaterControlTemp>(getEnumValue(CrankcaseHeaterControlTempNamesUC, Util::makeUPPER(hpwhAlpha[20 + nAlphaOffset])));
    1540              : 
    1541           12 :         switch (HPWH.CrankcaseTempIndicator) {
    1542            3 :         case CrankcaseHeaterControlTemp::Schedule: {
    1543            3 :             if (hpwhAlphaBlank[21 + nAlphaOffset]) {
    1544            0 :                 ShowSevereEmptyField(state, eoh, hpwhAlphaFieldNames[21 + nAlphaOffset]);
    1545            0 :                 ErrorsFound = true;
    1546            3 :             } else if ((HPWH.crankcaseTempSched = Sched::GetSchedule(state, hpwhAlpha[21 + nAlphaOffset])) == nullptr) {
    1547            0 :                 ShowSevereItemNotFound(state, eoh, hpwhAlphaFieldNames[21 + nAlphaOffset], hpwhAlpha[21 + nAlphaOffset]);
    1548            0 :                 ErrorsFound = true;
    1549              :             }
    1550            3 :         } break;
    1551              : 
    1552            4 :         case CrankcaseHeaterControlTemp::Zone: {
    1553            4 :             if (HPWH.InletAirConfiguration == WTTAmbientTemp::OutsideAir || HPWH.InletAirConfiguration == WTTAmbientTemp::Schedule) {
    1554            0 :                 ShowSevereError(state,
    1555            0 :                                 format("{}=\"{}\":  Inlet Air Configuration must be Zone Air Only or Zone And",
    1556            0 :                                        state.dataIPShortCut->cCurrentModuleObject,
    1557            0 :                                        HPWH.Name));
    1558            0 :                 ShowContinueError(state, " Outdoor Air when compressor location equals ZONE.");
    1559            0 :                 ErrorsFound = true;
    1560              :             }
    1561              : 
    1562            4 :             if (!hpwhAlphaBlank[21 + nAlphaOffset]) {
    1563            0 :                 ShowWarningError(state,
    1564            0 :                                  format("{}=\"{}\"  {} was provided but will not be used based on compressor location input=\"{}\".",
    1565            0 :                                         state.dataIPShortCut->cCurrentModuleObject,
    1566            0 :                                         HPWH.Name,
    1567            0 :                                         hpwhAlphaFieldNames[21 + nAlphaOffset],
    1568            0 :                                         hpwhAlpha[20 + nAlphaOffset]));
    1569              :             }
    1570            4 :             break;
    1571              :         }
    1572            5 :         case CrankcaseHeaterControlTemp::Outdoors: {
    1573            5 :             if (!hpwhAlphaBlank[21 + nAlphaOffset]) {
    1574            0 :                 ShowWarningError(state,
    1575            0 :                                  format("{}=\"{}\"  {} was provided but will not be used based on {}=\"{}\".",
    1576            0 :                                         state.dataIPShortCut->cCurrentModuleObject,
    1577            0 :                                         HPWH.Name,
    1578            0 :                                         hpwhAlphaFieldNames[21 + nAlphaOffset],
    1579            0 :                                         hpwhAlphaFieldNames[21 + nAlphaOffset],
    1580            0 :                                         hpwhAlpha[20 + nAlphaOffset]));
    1581              :             }
    1582            5 :             break;
    1583              :         }
    1584            0 :         default:
    1585            0 :             break;
    1586              :         }
    1587              : 
    1588              :         // Fan Name
    1589           12 :         HPWH.FanName = hpwhAlpha[23 + nAlphaOffset];
    1590              : 
    1591           12 :         Real64 FanVolFlow = 0.0;
    1592           12 :         bool errFlag(false);
    1593              : 
    1594           12 :         HPWH.fanType = static_cast<HVAC::FanType>(getEnumValue(HVAC::fanTypeNamesUC, hpwhAlpha[22 + nAlphaOffset]));
    1595              : 
    1596           12 :         if ((HPWH.FanNum = Fans::GetFanIndex(state, HPWH.FanName)) == 0) {
    1597            0 :             ShowSevereItemNotFound(state, eoh, hpwhAlphaFieldNames[23 + nAlphaOffset], HPWH.FanName);
    1598            0 :             ErrorsFound = true;
    1599              :         } else {
    1600           12 :             assert(HPWH.fanType == state.dataFans->fans(HPWH.FanNum)->type);
    1601           12 :             FanVolFlow = state.dataFans->fans(HPWH.FanNum)->maxAirFlowRate;
    1602              :         }
    1603              :         // issue #5630, set fan info in coils.
    1604           12 :         if (bIsVScoil) {
    1605            0 :             VariableSpeedCoils::setVarSpeedHPWHFanType(state, HPWH.DXCoilNum, HPWH.fanType);
    1606            0 :             VariableSpeedCoils::setVarSpeedHPWHFanIndex(state, HPWH.DXCoilNum, HPWH.FanNum);
    1607              :         } else {
    1608              :             // LOL
    1609           12 :             DXCoils::SetDXCoolingCoilData(state, HPWH.DXCoilNum, errFlag, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, HPWH.FanName);
    1610           12 :             DXCoils::SetDXCoolingCoilData(state, HPWH.DXCoilNum, errFlag, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, HPWH.FanNum);
    1611           12 :             DXCoils::SetDXCoolingCoilData(
    1612           12 :                 state, HPWH.DXCoilNum, errFlag, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, HPWH.fanType);
    1613              :         }
    1614              : 
    1615           12 :         if (errFlag) {
    1616            0 :             ErrorsFound = true;
    1617           12 :         } else if (HPWH.fanType != HVAC::FanType::OnOff && HPWH.fanType != HVAC::FanType::SystemModel) {
    1618            0 :             ShowSevereError(state, format("{}=\"{}\": illegal fan type specified.", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    1619            0 :             ShowContinueError(
    1620              :                 state,
    1621            0 :                 format(" The fan object ({}) type must be Fan:SystemModel or Fan:OnOff when used with a heat pump water heater.", HPWH.FanName));
    1622            0 :             ErrorsFound = true;
    1623           12 :         } else if (HPWH.fanType != HVAC::FanType::OnOff && HPWH.fanType != HVAC::FanType::SystemModel) {
    1624            0 :             ShowSevereError(state, format("{}=\"{}\": illegal fan type specified.", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    1625            0 :             ShowContinueError(state, format(" The {} must specify that the fan object", state.dataIPShortCut->cCurrentModuleObject));
    1626            0 :             ShowContinueError(state,
    1627              :                               " is of type FanSystemModel or Fan:OnOff in addition to the fan actually being of that type and defined elsewhere.");
    1628              :         }
    1629              : 
    1630           12 :         if (FanVolFlow != DataSizing::AutoSize && !errFlag) {
    1631            7 :             if (FanVolFlow < HPWH.OperatingAirFlowRate) {
    1632            0 :                 ShowSevereError(state,
    1633            0 :                                 format("{} - air flow rate = {:.7T} in fan object {} is less than the  HPWHs evaporator air flow rate.",
    1634            0 :                                        state.dataIPShortCut->cCurrentModuleObject,
    1635              :                                        FanVolFlow,
    1636            0 :                                        HPWH.FanName));
    1637            0 :                 ShowContinueError(state, " The fan flow rate must be >= to the HPWHs evaporator volumetric air flow rate.");
    1638            0 :                 ShowContinueError(state, format(" Occurs in unit = {}", HPWH.Name));
    1639            0 :                 ErrorsFound = true;
    1640              :             }
    1641              :         }
    1642              : 
    1643              :         // Fan Placement
    1644           12 :         HPWH.fanPlace = static_cast<HVAC::FanPlace>(getEnumValue(HVAC::fanPlaceNamesUC, hpwhAlpha[24 + nAlphaOffset]));
    1645           12 :         if (HPWH.fanPlace == HVAC::FanPlace::Invalid) {
    1646            0 :             ShowSevereInvalidKey(state, eoh, hpwhAlphaFieldNames[24 + nAlphaOffset], hpwhAlpha[24 + nAlphaOffset]);
    1647            0 :             ErrorsFound = true;
    1648              :         }
    1649              : 
    1650           12 :         if (HPWH.DXCoilNum > 0 && !bIsVScoil) {
    1651              :             // get HPWH capacity, air inlet node, and PLF curve info from DX coil object
    1652           12 :             HPWH.Capacity = state.dataDXCoils->DXCoil(HPWH.DXCoilNum).RatedTotCap2;
    1653           12 :             HPWH.DXCoilAirInletNode = state.dataDXCoils->DXCoil(HPWH.DXCoilNum).AirInNode;
    1654           12 :             HPWH.DXCoilPLFFPLR = state.dataDXCoils->DXCoil(HPWH.DXCoilNum).PLFFPLR(1);
    1655              :             // check the range of condenser pump power to be <= 5 gpm/ton
    1656           12 :             if (state.dataDXCoils->DXCoil(HPWH.DXCoilNum).HPWHCondPumpElecNomPower / state.dataDXCoils->DXCoil(HPWH.DXCoilNum).RatedTotCap2 >
    1657              :                 0.1422) {
    1658            0 :                 ShowWarningError(
    1659              :                     state,
    1660            0 :                     format("{}= {}{}",
    1661            0 :                            state.dataDXCoils->DXCoil(HPWH.DXCoilNum).DXCoilType,
    1662            0 :                            state.dataDXCoils->DXCoil(HPWH.DXCoilNum).Name,
    1663            0 :                            format(": Rated condenser pump power per watt of rated heating capacity has exceeded the recommended maximum of 0.1422 "
    1664              :                                   "W/W (41.67 watt/MBH). Condenser pump power per watt = {:.4T}",
    1665            0 :                                   (state.dataDXCoils->DXCoil(HPWH.DXCoilNum).HPWHCondPumpElecNomPower /
    1666            0 :                                    state.dataDXCoils->DXCoil(HPWH.DXCoilNum).RatedTotCap2))));
    1667              :             }
    1668            0 :         } else if ((HPWH.DXCoilNum > 0) && (bIsVScoil)) {
    1669              : 
    1670            0 :             if (HPWH.bIsIHP) {
    1671            0 :                 HPWH.Capacity =
    1672            0 :                     GetDWHCoilCapacityIHP(state, HPWH.DXCoilType, HPWH.DXCoilName, IntegratedHeatPump::IHPOperationMode::SCWHMatchWH, DXCoilErrFlag);
    1673            0 :                 HPWH.DXCoilAirInletNode = IntegratedHeatPump::GetCoilInletNodeIHP(state, HPWH.DXCoilType, HPWH.DXCoilName, DXCoilErrFlag);
    1674            0 :                 HPWH.DXCoilPLFFPLR =
    1675            0 :                     GetIHPDWHCoilPLFFPLR(state, HPWH.DXCoilType, HPWH.DXCoilName, IntegratedHeatPump::IHPOperationMode::SCWHMatchWH, DXCoilErrFlag);
    1676              :             } else {
    1677            0 :                 HPWH.Capacity = VariableSpeedCoils::GetCoilCapacityVariableSpeed(state, HPWH.DXCoilType, HPWH.DXCoilName, DXCoilErrFlag);
    1678            0 :                 HPWH.DXCoilAirInletNode = VariableSpeedCoils::GetCoilInletNodeVariableSpeed(state, HPWH.DXCoilType, HPWH.DXCoilName, DXCoilErrFlag);
    1679            0 :                 HPWH.DXCoilPLFFPLR = VariableSpeedCoils::GetVSCoilPLFFPLR(state, HPWH.DXCoilType, HPWH.DXCoilName, DXCoilErrFlag);
    1680              :             }
    1681              :             //         check the range of condenser pump power to be <= 5 gpm/ton, will be checked in the coil object
    1682              :         }
    1683              : 
    1684           12 :         if (HPWH.OperatingWaterFlowRate == Constant::AutoCalculate) {
    1685            7 :             HPWH.OperatingWaterFlowRate = 0.00000004487 * HPWH.Capacity;
    1686            7 :             HPWH.WaterFlowRateAutoSized = true;
    1687              :         }
    1688              : 
    1689           12 :         if (HPWH.OperatingAirFlowRate == Constant::AutoCalculate) {
    1690            7 :             HPWH.OperatingAirFlowRate = 0.00005035 * HPWH.Capacity;
    1691            7 :             HPWH.AirFlowRateAutoSized = true;
    1692              :         }
    1693              : 
    1694              :         // On Cycle Parasitic Electric Load
    1695           12 :         HPWH.OnCycParaLoad = hpwhNumeric[6 + nNumericOffset];
    1696           12 :         if (HPWH.OnCycParaLoad < 0.0) {
    1697            0 :             ShowSevereError(state, format("{}=\"{}\",", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    1698            0 :             ShowContinueError(state,
    1699            0 :                               format("{} must be >= 0. {}{}",
    1700            0 :                                      hpwhNumericFieldNames[6 + nNumericOffset],
    1701            0 :                                      hpwhNumericFieldNames[6 + nNumericOffset],
    1702            0 :                                      format(" = {:.2T}", hpwhNumeric[6 + nNumericOffset])));
    1703            0 :             ErrorsFound = true;
    1704              :         }
    1705              : 
    1706              :         // Off Cycle Parasitic Electric Load
    1707           12 :         HPWH.OffCycParaLoad = hpwhNumeric[7 + nNumericOffset];
    1708           12 :         if (HPWH.OffCycParaLoad < 0.0) {
    1709            0 :             ShowSevereError(state, format("{}=\"{}\",", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    1710            0 :             ShowContinueError(state,
    1711            0 :                               format("{} must be >= 0. {}{}",
    1712            0 :                                      hpwhNumericFieldNames[7 + nNumericOffset],
    1713            0 :                                      hpwhNumericFieldNames[2 + nNumericOffset],
    1714            0 :                                      format(" = {:.2T}", hpwhNumeric[7 + nNumericOffset])));
    1715            0 :             ErrorsFound = true;
    1716              :         }
    1717              : 
    1718              :         // Parasitic Heat Rejection Location
    1719           12 :         if (Util::SameString(hpwhAlpha[25 + nAlphaOffset], "Zone")) {
    1720            2 :             HPWH.ParasiticTempIndicator = WTTAmbientTemp::TempZone;
    1721            2 :             if (HPWH.InletAirConfiguration == WTTAmbientTemp::OutsideAir || HPWH.InletAirConfiguration == WTTAmbientTemp::Schedule) {
    1722            0 :                 ShowSevereError(state, format("{}=\"{}\",", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    1723            0 :                 ShowContinueError(state, format("{} must be ZoneAirOnly or ZoneAndOutdoorAir", hpwhAlphaFieldNames[25 + nAlphaOffset]));
    1724            0 :                 ShowContinueError(state, " when parasitic heat rejection location equals Zone.");
    1725            0 :                 ErrorsFound = true;
    1726              :             }
    1727           10 :         } else if (Util::SameString(hpwhAlpha[25 + nAlphaOffset], "Outdoors")) {
    1728           10 :             HPWH.ParasiticTempIndicator = WTTAmbientTemp::OutsideAir;
    1729              :         } else {
    1730            0 :             ShowSevereError(state, format("{}=\"{}\":", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    1731            0 :             ShowContinueError(state, " parasitic heat rejection location must be either Zone or Outdoors.");
    1732            0 :             ErrorsFound = true;
    1733              :         }
    1734              : 
    1735              :         // Inlet Air Mixer Node
    1736              :         // get mixer/splitter nodes only when Inlet Air Configuration is ZoneAndOutdoorAir
    1737           12 :         if (!hpwhAlphaBlank[26 + nAlphaOffset]) {
    1738              :             // For the inlet air mixer node, NodeConnectionType is outlet from the HPWH inlet air node
    1739            0 :             if (HPWH.InletAirConfiguration == WTTAmbientTemp::ZoneAndOA) {
    1740            0 :                 HPWH.InletAirMixerNode = NodeInputManager::GetOnlySingleNode(state,
    1741            0 :                                                                              hpwhAlpha[26 + nAlphaOffset],
    1742              :                                                                              ErrorsFound,
    1743              :                                                                              objType,
    1744            0 :                                                                              HPWH.Name + "-INLET AIR MIXER",
    1745              :                                                                              DataLoopNode::NodeFluidType::Air,
    1746              :                                                                              DataLoopNode::ConnectionType::Outlet,
    1747              :                                                                              NodeInputManager::CompFluidStream::Primary,
    1748              :                                                                              DataLoopNode::ObjectIsNotParent);
    1749              :             } else {
    1750            0 :                 ShowWarningError(state, format("{}=\"{}\":", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    1751            0 :                 ShowContinueError(state,
    1752              :                                   "Inlet air mixer node name specified but only required when Inlet Air Configuration is selected as "
    1753              :                                   "Zone and OutdoorAir. Node name disregarded and simulation continues.");
    1754              :             }
    1755           12 :         } else if (hpwhAlphaBlank[26 + nAlphaOffset] && HPWH.InletAirConfiguration == WTTAmbientTemp::ZoneAndOA) {
    1756            0 :             ShowSevereError(state, format("{}=\"{}\":", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    1757            0 :             ShowContinueError(state, "Inlet air mixer node name required when Inlet Air Configuration is selected as ZoneAndOutdoorAir.");
    1758            0 :             ErrorsFound = true;
    1759              :         }
    1760              : 
    1761              :         // Outlet Air Splitter Node
    1762           12 :         if (!hpwhAlphaBlank[27 + nAlphaOffset]) {
    1763              :             //  For the outlet air splitter node, NodeConnectionType is inlet to the HPWH outlet air node
    1764            0 :             if (HPWH.InletAirConfiguration == WTTAmbientTemp::ZoneAndOA) {
    1765            0 :                 HPWH.OutletAirSplitterNode = NodeInputManager::GetOnlySingleNode(state,
    1766            0 :                                                                                  hpwhAlpha[27 + nAlphaOffset],
    1767              :                                                                                  ErrorsFound,
    1768              :                                                                                  objType,
    1769            0 :                                                                                  HPWH.Name + "-OUTLET AIR SPLITTER",
    1770              :                                                                                  DataLoopNode::NodeFluidType::Air,
    1771              :                                                                                  DataLoopNode::ConnectionType::Inlet,
    1772              :                                                                                  NodeInputManager::CompFluidStream::Primary,
    1773              :                                                                                  DataLoopNode::ObjectIsNotParent);
    1774              :             } else {
    1775            0 :                 ShowWarningError(state, format("{}=\"{}\":", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    1776            0 :                 ShowContinueError(state,
    1777              :                                   "Outlet air splitter node name specified but only required when Inlet Air Configuration is selected as "
    1778              :                                   "ZoneAndOutdoorAir. Node name disregarded and simulation continues.");
    1779              :             }
    1780           12 :         } else if (hpwhAlphaBlank[27 + nAlphaOffset] && HPWH.InletAirConfiguration == WTTAmbientTemp::ZoneAndOA) {
    1781            0 :             ShowSevereError(state, format("{}=\"{}\":", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    1782            0 :             ShowContinueError(state, "Outlet air splitter node name required when Inlet Air Configuration is selected as ZoneAndOutdoorAir.");
    1783            0 :             ErrorsFound = true;
    1784              :         }
    1785              : 
    1786              :         // get node data for HPWH
    1787           12 :         if (HPWH.InletAirMixerNode != 0) {
    1788              :             // when mixer/splitter nodes are used the HPWH's inlet/outlet node are set up as DataLoopNode::ObjectIsNotParent
    1789              : 
    1790            0 :             HPWH.HeatPumpAirInletNode = NodeInputManager::GetOnlySingleNode(state,
    1791            0 :                                                                             hpwhAlpha[7 + nAlphaOffset],
    1792              :                                                                             ErrorsFound,
    1793              :                                                                             objType,
    1794            0 :                                                                             HPWH.Name + "-INLET AIR MIXER",
    1795              :                                                                             DataLoopNode::NodeFluidType::Air,
    1796              :                                                                             DataLoopNode::ConnectionType::Inlet,
    1797              :                                                                             NodeInputManager::CompFluidStream::Primary,
    1798              :                                                                             DataLoopNode::ObjectIsNotParent);
    1799              : 
    1800            0 :             HPWH.HeatPumpAirOutletNode = NodeInputManager::GetOnlySingleNode(state,
    1801            0 :                                                                              hpwhAlpha[8 + nAlphaOffset],
    1802              :                                                                              ErrorsFound,
    1803              :                                                                              objType,
    1804            0 :                                                                              HPWH.Name + "-OUTLET AIR SPLITTER",
    1805              :                                                                              DataLoopNode::NodeFluidType::Air,
    1806              :                                                                              DataLoopNode::ConnectionType::Outlet,
    1807              :                                                                              NodeInputManager::CompFluidStream::Primary,
    1808              :                                                                              DataLoopNode::ObjectIsNotParent);
    1809              : 
    1810            0 :             HPWH.OutsideAirNode = NodeInputManager::GetOnlySingleNode(state,
    1811            0 :                                                                       hpwhAlpha[9 + nAlphaOffset],
    1812              :                                                                       ErrorsFound,
    1813              :                                                                       objType,
    1814            0 :                                                                       HPWH.Name,
    1815              :                                                                       DataLoopNode::NodeFluidType::Air,
    1816              :                                                                       DataLoopNode::ConnectionType::OutsideAirReference,
    1817              :                                                                       NodeInputManager::CompFluidStream::Primary,
    1818              :                                                                       DataLoopNode::ObjectIsParent);
    1819            0 :             if (!hpwhAlpha[9 + nAlphaOffset].empty()) {
    1820              :                 bool Okay;
    1821            0 :                 OutAirNodeManager::CheckAndAddAirNodeNumber(state, HPWH.OutsideAirNode, Okay);
    1822            0 :                 if (!Okay) {
    1823            0 :                     ShowWarningError(state,
    1824            0 :                                      format("{}=\"{}\": Adding outdoor air node={}",
    1825            0 :                                             state.dataIPShortCut->cCurrentModuleObject,
    1826            0 :                                             HPWH.Name,
    1827            0 :                                             hpwhAlpha[9 + nAlphaOffset]));
    1828              :                 }
    1829              :             }
    1830              : 
    1831            0 :             HPWH.ExhaustAirNode = NodeInputManager::GetOnlySingleNode(state,
    1832            0 :                                                                       hpwhAlpha[10 + nAlphaOffset],
    1833              :                                                                       ErrorsFound,
    1834              :                                                                       objType,
    1835            0 :                                                                       HPWH.Name,
    1836              :                                                                       DataLoopNode::NodeFluidType::Air,
    1837              :                                                                       DataLoopNode::ConnectionType::ReliefAir,
    1838              :                                                                       NodeInputManager::CompFluidStream::Primary,
    1839              :                                                                       DataLoopNode::ObjectIsParent);
    1840              : 
    1841              :         } else {
    1842              :             // when mixer/splitter nodes are NOT used the HPWH's inlet/outlet nodes are set up as DataLoopNode::ObjectIsParent
    1843           12 :             if (HPWH.InletAirConfiguration == WTTAmbientTemp::Schedule) {
    1844              :                 // for scheduled HPWH's the inlet node is not on any branch or parent object, make it an outlet node
    1845              :                 // to avoid node connection errors
    1846            5 :                 HPWH.HeatPumpAirInletNode = NodeInputManager::GetOnlySingleNode(state,
    1847            5 :                                                                                 hpwhAlpha[7 + nAlphaOffset],
    1848              :                                                                                 ErrorsFound,
    1849              :                                                                                 objType,
    1850            5 :                                                                                 HPWH.Name,
    1851              :                                                                                 DataLoopNode::NodeFluidType::Air,
    1852              :                                                                                 DataLoopNode::ConnectionType::Outlet,
    1853              :                                                                                 NodeInputManager::CompFluidStream::Primary,
    1854              :                                                                                 DataLoopNode::ObjectIsParent);
    1855              : 
    1856            5 :                 HPWH.HeatPumpAirOutletNode = NodeInputManager::GetOnlySingleNode(state,
    1857            5 :                                                                                  hpwhAlpha[8 + nAlphaOffset],
    1858              :                                                                                  ErrorsFound,
    1859              :                                                                                  objType,
    1860            5 :                                                                                  HPWH.Name,
    1861              :                                                                                  DataLoopNode::NodeFluidType::Air,
    1862              :                                                                                  DataLoopNode::ConnectionType::Outlet,
    1863              :                                                                                  NodeInputManager::CompFluidStream::Primary,
    1864              :                                                                                  DataLoopNode::ObjectIsParent);
    1865              : 
    1866              :             } else { // HPWH is connected to a zone with no mixer/splitter nodes
    1867            7 :                 if (HPWH.InletAirConfiguration == WTTAmbientTemp::TempZone) {
    1868            4 :                     HPWH.HeatPumpAirInletNode = NodeInputManager::GetOnlySingleNode(state,
    1869            4 :                                                                                     hpwhAlpha[7 + nAlphaOffset],
    1870              :                                                                                     ErrorsFound,
    1871              :                                                                                     objType,
    1872            4 :                                                                                     HPWH.Name,
    1873              :                                                                                     DataLoopNode::NodeFluidType::Air,
    1874              :                                                                                     DataLoopNode::ConnectionType::Inlet,
    1875              :                                                                                     NodeInputManager::CompFluidStream::Primary,
    1876              :                                                                                     DataLoopNode::ObjectIsParent);
    1877              : 
    1878            4 :                     HPWH.HeatPumpAirOutletNode = NodeInputManager::GetOnlySingleNode(state,
    1879            4 :                                                                                      hpwhAlpha[8 + nAlphaOffset],
    1880              :                                                                                      ErrorsFound,
    1881              :                                                                                      objType,
    1882            4 :                                                                                      HPWH.Name,
    1883              :                                                                                      DataLoopNode::NodeFluidType::Air,
    1884              :                                                                                      DataLoopNode::ConnectionType::Outlet,
    1885              :                                                                                      NodeInputManager::CompFluidStream::Primary,
    1886              :                                                                                      DataLoopNode::ObjectIsParent);
    1887              :                 } else { // HPWH is located outdoors
    1888            3 :                     HPWH.OutsideAirNode = NodeInputManager::GetOnlySingleNode(state,
    1889            3 :                                                                               hpwhAlpha[9 + nAlphaOffset],
    1890              :                                                                               ErrorsFound,
    1891              :                                                                               objType,
    1892            3 :                                                                               HPWH.Name,
    1893              :                                                                               DataLoopNode::NodeFluidType::Air,
    1894              :                                                                               DataLoopNode::ConnectionType::OutsideAirReference,
    1895              :                                                                               NodeInputManager::CompFluidStream::Primary,
    1896              :                                                                               DataLoopNode::ObjectIsParent);
    1897            3 :                     if (!hpwhAlphaBlank[9 + nAlphaOffset]) {
    1898              :                         bool Okay;
    1899            2 :                         OutAirNodeManager::CheckAndAddAirNodeNumber(state, HPWH.OutsideAirNode, Okay);
    1900            2 :                         if (!Okay) {
    1901            4 :                             ShowWarningError(state,
    1902            4 :                                              format("{}=\"{}\": Adding outdoor air node ={}",
    1903            2 :                                                     state.dataIPShortCut->cCurrentModuleObject,
    1904            2 :                                                     HPWH.Name,
    1905            4 :                                                     hpwhAlpha[9 + nAlphaOffset]));
    1906              :                         }
    1907              :                     }
    1908              : 
    1909            3 :                     HPWH.ExhaustAirNode = NodeInputManager::GetOnlySingleNode(state,
    1910            3 :                                                                               hpwhAlpha[10 + nAlphaOffset],
    1911              :                                                                               ErrorsFound,
    1912              :                                                                               objType,
    1913            3 :                                                                               HPWH.Name,
    1914              :                                                                               DataLoopNode::NodeFluidType::Air,
    1915              :                                                                               DataLoopNode::ConnectionType::ReliefAir,
    1916              :                                                                               NodeInputManager::CompFluidStream::Primary,
    1917              :                                                                               DataLoopNode::ObjectIsParent);
    1918              :                 }
    1919              :             }
    1920              :         }
    1921              :         // check that required node names are present
    1922           12 :         if (HPWH.InletAirConfiguration == WTTAmbientTemp::Schedule || HPWH.InletAirConfiguration == WTTAmbientTemp::TempZone) {
    1923            9 :             if (HPWH.HeatPumpAirInletNode == 0 || HPWH.HeatPumpAirOutletNode == 0) {
    1924            0 :                 ShowSevereError(state, format("{}=\"{}\":", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    1925            0 :                 ShowContinueError(state, format("When {}=\"{}\".", hpwhAlphaFieldNames[6 + nAlphaOffset], hpwhAlpha[6 + nAlphaOffset]));
    1926            0 :                 ShowContinueError(
    1927            0 :                     state, format("{} and {} must be specified.", hpwhAlphaFieldNames[7 + nAlphaOffset], hpwhAlphaFieldNames[8 + nAlphaOffset]));
    1928            0 :                 ErrorsFound = true;
    1929              :             }
    1930            3 :         } else if (HPWH.InletAirConfiguration == WTTAmbientTemp::OutsideAir) {
    1931            3 :             if (HPWH.OutsideAirNode == 0 || HPWH.ExhaustAirNode == 0) {
    1932            1 :                 ShowSevereError(state, format("{}=\"{}\":", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    1933            1 :                 ShowContinueError(state, format("When {}=\"{}\".", hpwhAlphaFieldNames[6 + nAlphaOffset], hpwhAlpha[6 + nAlphaOffset]));
    1934            2 :                 ShowContinueError(
    1935            2 :                     state, format("{} and {} must be specified.", hpwhAlphaFieldNames[9 + nAlphaOffset], hpwhAlphaFieldNames[10 + nAlphaOffset]));
    1936            1 :                 ErrorsFound = true;
    1937              :             }
    1938            0 :         } else if (HPWH.InletAirMixerNode > 0 && HPWH.OutletAirSplitterNode > 0 && HPWH.InletAirConfiguration == WTTAmbientTemp::ZoneAndOA) {
    1939            0 :             if (HPWH.HeatPumpAirInletNode == 0 || HPWH.HeatPumpAirOutletNode == 0 || HPWH.OutsideAirNode == 0 || HPWH.ExhaustAirNode == 0) {
    1940            0 :                 ShowSevereError(state, format("{}=\"{}\":", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    1941            0 :                 ShowContinueError(state, format("When {}=\"{}\".", hpwhAlphaFieldNames[6 + nAlphaOffset], hpwhAlpha[6 + nAlphaOffset]));
    1942            0 :                 if (HPWH.HeatPumpAirInletNode == 0 || HPWH.HeatPumpAirOutletNode == 0) {
    1943            0 :                     ShowContinueError(
    1944            0 :                         state, format("{} and {} must be specified.", hpwhAlphaFieldNames[7 + nAlphaOffset], hpwhAlphaFieldNames[8 + nAlphaOffset]));
    1945              :                 }
    1946            0 :                 if (HPWH.OutsideAirNode == 0 || HPWH.ExhaustAirNode == 0) {
    1947            0 :                     ShowContinueError(
    1948            0 :                         state, format("{} and {} must be specified.", hpwhAlphaFieldNames[9 + nAlphaOffset], hpwhAlphaFieldNames[10 + nAlphaOffset]));
    1949              :                 }
    1950            0 :                 ErrorsFound = true;
    1951              :             }
    1952              :         }
    1953              : 
    1954              :         // check that the HPWH inlet and outlet nodes are in the same zone (ZoneHVAC:EquipmentConnections) when
    1955              :         // Inlet Air Configuration is Zone Air Only or Zone and Outdoor Air
    1956           12 :         if ((HPWH.InletAirConfiguration == WTTAmbientTemp::TempZone || HPWH.InletAirConfiguration == WTTAmbientTemp::ZoneAndOA) &&
    1957            4 :             HPWH.AmbientTempZone > 0) {
    1958            2 :             if (allocated(state.dataZoneEquip->ZoneEquipConfig)) {
    1959            1 :                 bool FoundInletNode = false;
    1960            1 :                 bool FoundOutletNode = false;
    1961            1 :                 int ZoneNum = HPWH.AmbientTempZone;
    1962            1 :                 if (ZoneNum <= state.dataGlobal->NumOfZones) {
    1963            4 :                     for (int SupAirIn = 1; SupAirIn <= state.dataZoneEquip->ZoneEquipConfig(ZoneNum).NumInletNodes; ++SupAirIn) {
    1964            3 :                         if (HPWH.HeatPumpAirOutletNode != state.dataZoneEquip->ZoneEquipConfig(ZoneNum).InletNode(SupAirIn)) continue;
    1965            1 :                         FoundOutletNode = true;
    1966              :                     }
    1967            3 :                     for (int ExhAirOut = 1; ExhAirOut <= state.dataZoneEquip->ZoneEquipConfig(ZoneNum).NumExhaustNodes; ++ExhAirOut) {
    1968            2 :                         if (HPWH.HeatPumpAirInletNode != state.dataZoneEquip->ZoneEquipConfig(ZoneNum).ExhaustNode(ExhAirOut)) continue;
    1969            1 :                         FoundInletNode = true;
    1970              :                     }
    1971            1 :                     if (!FoundInletNode) {
    1972            0 :                         ShowSevereError(state, format("{}=\"{}\":", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    1973            0 :                         ShowContinueError(state,
    1974            0 :                                           format("The HPWH's air inlet node name = {} was not properly specified ", hpwhAlpha[7 + nAlphaOffset]));
    1975            0 :                         ShowContinueError(
    1976              :                             state,
    1977            0 :                             format("as an exhaust air node for zone = {} in a ZoneHVAC:EquipmentConnections object.", hpwhAlpha[13 + nAlphaOffset]));
    1978            0 :                         ErrorsFound = true;
    1979              :                     }
    1980            1 :                     if (!FoundOutletNode) {
    1981            0 :                         ShowSevereError(state, format("{}=\"{}\":", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    1982            0 :                         ShowContinueError(state,
    1983            0 :                                           format("The HPWH's air outlet node name = {} was not properly specified ", hpwhAlpha[8 + nAlphaOffset]));
    1984            0 :                         ShowContinueError(
    1985              :                             state,
    1986            0 :                             format("as an inlet air node for zone = {} in a ZoneHVAC:EquipmentConnections object.", hpwhAlpha[13 + nAlphaOffset]));
    1987            0 :                         ErrorsFound = true;
    1988              :                     }
    1989              :                 }
    1990              :             } else {
    1991            1 :                 ShowSevereError(state, format("{}=\"{}\":", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    1992            2 :                 ShowContinueError(state,
    1993              :                                   "Heat pump water heater air inlet node name and air outlet node name must be listed in a "
    1994              :                                   "ZoneHVAC:EquipmentConnections object when Inlet Air Configuration is equal to ZoneAirOnly or "
    1995              :                                   "ZoneAndOutdoorAir.");
    1996            1 :                 ErrorsFound = true;
    1997              :             }
    1998              :         }
    1999              : 
    2000              :         // only get the inlet air mixer schedule if the inlet air configuration is zone and outdoor air
    2001           12 :         if (HPWH.InletAirConfiguration == WTTAmbientTemp::ZoneAndOA) {
    2002            0 :             if (hpwhAlphaBlank[28 + nAlphaOffset]) {
    2003            0 :                 ShowSevereEmptyField(state, eoh, hpwhAlphaFieldNames[28 + nAlphaOffset]);
    2004            0 :                 ErrorsFound = true;
    2005              :                 //           set outlet air splitter schedule index equal to inlet air mixer schedule index
    2006              :                 //           (place holder for when zone pressurization/depressurization is allowed and different schedules can be used)
    2007            0 :             } else if ((HPWH.inletAirMixerSched = HPWH.outletAirSplitterSched = Sched::GetSchedule(state, hpwhAlpha[28 + nAlphaOffset])) == nullptr) {
    2008            0 :                 ShowSevereItemNotFound(state, eoh, hpwhAlphaFieldNames[28 + nAlphaOffset], hpwhAlpha[28 + nAlphaOffset]);
    2009            0 :                 ErrorsFound = true;
    2010            0 :             } else if (!HPWH.inletAirMixerSched->checkMinMaxVals(state, Clusive::In, 0.0, Clusive::In, 1.0)) {
    2011            0 :                 Sched::ShowSevereBadMinMax(
    2012            0 :                     state, eoh, hpwhAlphaFieldNames[28 + nAlphaOffset], hpwhAlpha[28 + nAlphaOffset], Clusive::In, 0.0, Clusive::In, 1.0);
    2013            0 :                 ErrorsFound = true;
    2014              :             }
    2015              :         }
    2016              : 
    2017              :         // set fan outlet node variable for use in setting Node(FanOutletNode)%MassFlowRateMax for fan object
    2018           12 :         if (HPWH.fanPlace == HVAC::FanPlace::DrawThru) {
    2019           12 :             if (HPWH.OutletAirSplitterNode != 0) {
    2020            0 :                 HPWH.FanOutletNode = HPWH.OutletAirSplitterNode;
    2021           12 :             } else if (HPWH.InletAirConfiguration == WTTAmbientTemp::OutsideAir) {
    2022            3 :                 HPWH.FanOutletNode = HPWH.ExhaustAirNode;
    2023              :             } else {
    2024            9 :                 HPWH.FanOutletNode = HPWH.HeatPumpAirOutletNode;
    2025              :             }
    2026            0 :         } else if (HPWH.fanPlace == HVAC::FanPlace::BlowThru) {
    2027              :             // set fan outlet node variable for use in setting Node(FanOutletNode)%MassFlowRateMax for fan object
    2028            0 :             if (bIsVScoil) {
    2029            0 :                 if (HPWH.bIsIHP) {
    2030            0 :                     HPWH.FanOutletNode = IntegratedHeatPump::GetDWHCoilInletNodeIHP(state, HPWH.DXCoilType, HPWH.DXCoilName, DXCoilErrFlag);
    2031              :                 } else {
    2032            0 :                     HPWH.FanOutletNode = VariableSpeedCoils::GetCoilInletNodeVariableSpeed(state, HPWH.DXCoilType, HPWH.DXCoilName, DXCoilErrFlag);
    2033              :                 }
    2034              :             } else {
    2035            0 :                 HPWH.FanOutletNode = state.dataDXCoils->DXCoil(HPWH.DXCoilNum).AirInNode;
    2036              :             }
    2037              :         }
    2038              : 
    2039              :         // check that fan outlet node is indeed correct
    2040           12 :         int FanOutletNodeNum = state.dataFans->fans(HPWH.FanNum)->outletNodeNum;
    2041              : 
    2042           12 :         if (FanOutletNodeNum != HPWH.FanOutletNode) {
    2043            1 :             ShowSevereError(state, format("{}=\"{}\":", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    2044            2 :             ShowContinueError(state, "Heat pump water heater fan outlet node name does not match next connected component.");
    2045            1 :             if (FanOutletNodeNum != 0) {
    2046            1 :                 ShowContinueError(state, format("Fan outlet node name = {}", state.dataLoopNodes->NodeID(FanOutletNodeNum)));
    2047              :             }
    2048            1 :             if (HPWH.FanOutletNode != 0) {
    2049            0 :                 ShowContinueError(state, format("Expected fan outlet node name = {}", state.dataLoopNodes->NodeID(HPWH.FanOutletNode)));
    2050              :             }
    2051            1 :             ErrorsFound = true;
    2052              :         }
    2053           12 :         int FanInletNodeNum = state.dataFans->fans(HPWH.FanNum)->inletNodeNum;
    2054              : 
    2055           12 :         int HPWHFanInletNodeNum(0);
    2056           12 :         if (HPWH.InletAirMixerNode != 0) {
    2057            0 :             HPWHFanInletNodeNum = HPWH.InletAirMixerNode;
    2058              :         } else {
    2059           12 :             if (HPWH.InletAirConfiguration == WTTAmbientTemp::OutsideAir) {
    2060            3 :                 HPWHFanInletNodeNum = HPWH.OutsideAirNode;
    2061              :             } else {
    2062            9 :                 HPWHFanInletNodeNum = HPWH.HeatPumpAirInletNode;
    2063              :             }
    2064              :         }
    2065           12 :         if (HPWH.fanPlace == HVAC::FanPlace::BlowThru) {
    2066            0 :             if (FanInletNodeNum != HPWHFanInletNodeNum) {
    2067            0 :                 ShowSevereError(state, format("{}=\"{}\":", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    2068            0 :                 ShowContinueError(state, "Heat pump water heater fan inlet node name does not match previous connected component.");
    2069            0 :                 if (FanOutletNodeNum != 0) {
    2070            0 :                     ShowContinueError(state, format("Fan inlet node name = {}", state.dataLoopNodes->NodeID(FanInletNodeNum)));
    2071              :                 }
    2072            0 :                 if (HPWH.FanOutletNode != 0) {
    2073            0 :                     ShowContinueError(state, format("Expected fan inlet node name = {}", state.dataLoopNodes->NodeID(HPWHFanInletNodeNum)));
    2074              :                 }
    2075            0 :                 ErrorsFound = true;
    2076              :             }
    2077              :         }
    2078              : 
    2079           12 :         int DXCoilAirOutletNodeNum(0);
    2080           12 :         if ((HPWH.DXCoilNum > 0) && (bIsVScoil)) {
    2081            0 :             if (HPWH.bIsIHP) {
    2082            0 :                 DXCoilAirOutletNodeNum = IntegratedHeatPump::GetDWHCoilOutletNodeIHP(state, HPWH.DXCoilType, HPWH.DXCoilName, DXCoilErrFlag);
    2083              :             } else {
    2084            0 :                 DXCoilAirOutletNodeNum = VariableSpeedCoils::GetCoilOutletNodeVariableSpeed(state, HPWH.DXCoilType, HPWH.DXCoilName, DXCoilErrFlag);
    2085              :             }
    2086              : 
    2087           12 :         } else if (HPWH.DXCoilNum > 0) {
    2088           12 :             DXCoilAirOutletNodeNum = state.dataDXCoils->DXCoil(HPWH.DXCoilNum).AirOutNode;
    2089              :         }
    2090           12 :         if (HPWH.fanPlace == HVAC::FanPlace::DrawThru) {
    2091           12 :             if (FanInletNodeNum != DXCoilAirOutletNodeNum) {
    2092            0 :                 ShowSevereError(state, format("{}=\"{}\":", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    2093            0 :                 ShowContinueError(state, "Heat pump water heater fan inlet node name does not match previous connected component.");
    2094            0 :                 if (FanInletNodeNum != 0) {
    2095            0 :                     ShowContinueError(state, format("Fan inlet node name = {}", state.dataLoopNodes->NodeID(FanInletNodeNum)));
    2096              :                 }
    2097            0 :                 if (DXCoilAirOutletNodeNum != 0) {
    2098            0 :                     ShowContinueError(state, format("Expected fan inlet node name = {}", state.dataLoopNodes->NodeID(DXCoilAirOutletNodeNum)));
    2099              :                 }
    2100            0 :                 ErrorsFound = true;
    2101              :             }
    2102            0 :         } else if (HPWH.fanPlace == HVAC::FanPlace::BlowThru) {
    2103            0 :             int HPWHCoilOutletNodeNum(0);
    2104            0 :             if (HPWH.OutletAirSplitterNode != 0) {
    2105            0 :                 HPWHCoilOutletNodeNum = HPWH.OutletAirSplitterNode;
    2106              :             } else {
    2107            0 :                 if (HPWH.InletAirConfiguration == WTTAmbientTemp::OutsideAir) {
    2108            0 :                     HPWHCoilOutletNodeNum = HPWH.ExhaustAirNode;
    2109              :                 } else {
    2110            0 :                     HPWHCoilOutletNodeNum = HPWH.HeatPumpAirOutletNode;
    2111              :                 }
    2112              :             }
    2113            0 :             if (DXCoilAirOutletNodeNum != HPWHCoilOutletNodeNum) {
    2114            0 :                 ShowSevereError(state, format("{}=\"{}\":", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    2115            0 :                 ShowContinueError(state, "Heat pump water heater coil outlet node name does not match next connected component.");
    2116            0 :                 if (DXCoilAirOutletNodeNum != 0) {
    2117            0 :                     ShowContinueError(state, format("Coil outlet node name = {}", state.dataLoopNodes->NodeID(DXCoilAirOutletNodeNum)));
    2118              :                 }
    2119            0 :                 if (HPWHCoilOutletNodeNum != 0) {
    2120            0 :                     ShowContinueError(state, format("Expected coil outlet node name = {}", state.dataLoopNodes->NodeID(HPWHCoilOutletNodeNum)));
    2121              :                 }
    2122            0 :                 ErrorsFound = true;
    2123              :             }
    2124              :         }
    2125              : 
    2126              :         // set the max mass flow rate for outdoor fans
    2127           12 :         if (HPWH.FanOutletNode > 0)
    2128           11 :             state.dataLoopNodes->Node(HPWH.FanOutletNode).MassFlowRateMax =
    2129           22 :                 HPWH.OperatingAirFlowRate * Psychrometrics::PsyRhoAirFnPbTdbW(state, state.dataEnvrn->OutBaroPress, 20.0, 0.0);
    2130              : 
    2131           12 :         if (HPWH.fanPlace == HVAC::FanPlace::BlowThru) {
    2132            0 :             if (HPWH.InletAirMixerNode > 0) {
    2133            0 :                 HPWH.FanInletNode_str = hpwhAlpha[26 + nAlphaOffset];
    2134            0 :                 HPWH.FanOutletNode_str = "UNDEFINED";
    2135              :             } else {
    2136            0 :                 if (HPWH.OutsideAirNode == 0) {
    2137            0 :                     HPWH.FanInletNode_str = hpwhAlpha[7 + nAlphaOffset];
    2138            0 :                     HPWH.FanOutletNode_str = "UNDEFINED";
    2139              :                 } else {
    2140            0 :                     HPWH.FanInletNode_str = hpwhAlpha[9 + nAlphaOffset];
    2141            0 :                     HPWH.FanOutletNode_str = "UNDEFINED";
    2142              :                 }
    2143              :             }
    2144            0 :             if (HPWH.OutletAirSplitterNode > 0) {
    2145            0 :                 HPWH.CoilInletNode_str = "UNDEFINED";
    2146            0 :                 HPWH.CoilOutletNode_str = hpwhAlpha[27 + nAlphaOffset];
    2147              :             } else {
    2148            0 :                 if (HPWH.OutsideAirNode == 0) {
    2149            0 :                     HPWH.CoilInletNode_str = "UNDEFINED";
    2150            0 :                     HPWH.CoilOutletNode_str = hpwhAlpha[8 + nAlphaOffset];
    2151              :                 } else {
    2152            0 :                     HPWH.CoilInletNode_str = "UNDEFINED";
    2153            0 :                     HPWH.CoilOutletNode_str = hpwhAlpha[10 + nAlphaOffset];
    2154              :                 }
    2155              :             }
    2156              :         } else {
    2157           12 :             if (HPWH.InletAirMixerNode > 0) {
    2158            0 :                 HPWH.CoilInletNode_str = hpwhAlpha[26 + nAlphaOffset];
    2159            0 :                 HPWH.CoilOutletNode_str = "UNDEFINED";
    2160              :             } else {
    2161           12 :                 if (HPWH.OutsideAirNode == 0) {
    2162           10 :                     HPWH.CoilInletNode_str = hpwhAlpha[7 + nAlphaOffset];
    2163           10 :                     HPWH.CoilOutletNode_str = "UNDEFINED";
    2164              :                 } else {
    2165            2 :                     HPWH.CoilInletNode_str = hpwhAlpha[9 + nAlphaOffset];
    2166            2 :                     HPWH.CoilOutletNode_str = "UNDEFINED";
    2167              :                 }
    2168              :             }
    2169           12 :             if (HPWH.OutletAirSplitterNode > 0) {
    2170            0 :                 HPWH.FanInletNode_str = "UNDEFINED";
    2171            0 :                 HPWH.FanOutletNode_str = hpwhAlpha[27 + nAlphaOffset];
    2172              :             } else {
    2173           12 :                 if (HPWH.OutsideAirNode == 0) {
    2174           10 :                     HPWH.FanInletNode_str = "UNDEFINED";
    2175           10 :                     HPWH.FanOutletNode_str = hpwhAlpha[8 + nAlphaOffset];
    2176              :                 } else {
    2177            2 :                     HPWH.FanInletNode_str = "UNDEFINED";
    2178            2 :                     HPWH.FanOutletNode_str = hpwhAlpha[10 + nAlphaOffset];
    2179              :                 }
    2180              :             }
    2181              :         }
    2182              : 
    2183              :         // set up comp set for air side nodes (can be blow thru or draw thru, may or may not have damper nodes)
    2184           12 :         if (HPWH.bIsIHP) {
    2185            0 :             BranchNodeConnections::SetUpCompSets(
    2186            0 :                 state, HPWH.Type, HPWH.Name, HPWH.DXCoilType, HPWH.DXCoilName + " Outdoor Coil", HPWH.CoilInletNode_str, HPWH.CoilOutletNode_str);
    2187              :         } else {
    2188           12 :             BranchNodeConnections::SetUpCompSets(
    2189              :                 state, HPWH.Type, HPWH.Name, HPWH.DXCoilType, HPWH.DXCoilName, HPWH.CoilInletNode_str, HPWH.CoilOutletNode_str);
    2190              :         }
    2191              : 
    2192           24 :         BranchNodeConnections::SetUpCompSets(
    2193           12 :             state, HPWH.Type, HPWH.Name, HVAC::fanTypeNames[(int)HPWH.fanType], HPWH.FanName, HPWH.FanInletNode_str, HPWH.FanOutletNode_str);
    2194              : 
    2195              :         // Control Logic Flag
    2196           19 :         std::string CtrlLogicFlag = hpwhAlphaBlank[29 + nAlphaOffset] ? "SIMULTANEOUS" : hpwhAlpha[29 + nAlphaOffset];
    2197           12 :         if (Util::SameString(CtrlLogicFlag, "SIMULTANEOUS")) {
    2198            7 :             HPWH.AllowHeatingElementAndHeatPumpToRunAtSameTime = true;
    2199            5 :         } else if (Util::SameString(CtrlLogicFlag, "MUTUALLYEXCLUSIVE")) {
    2200            5 :             HPWH.AllowHeatingElementAndHeatPumpToRunAtSameTime = false;
    2201              :         } else {
    2202            0 :             ShowSevereError(state, format("{}=\"{}\":", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    2203            0 :             ShowContinueError(state, format("{} is not a valid value for field Tank Element Control Logic.", CtrlLogicFlag));
    2204            0 :             ErrorsFound = true;
    2205              :         }
    2206              : 
    2207              :         // Control Sensor 1 Location In Stratified Tank
    2208           12 :         if (!hpwhNumericBlank[8 + nNumericOffset]) {
    2209            5 :             HPWH.ControlSensor1Height = hpwhNumeric[8 + nNumericOffset];
    2210              :         } else {
    2211              :             // use heater1 location, which we don't know right now
    2212            7 :             HPWH.ControlSensor1Height = -1.0;
    2213              :         }
    2214              : 
    2215              :         // Control Sensor 1 Weight
    2216           12 :         HPWH.ControlSensor1Weight = hpwhNumericBlank[9 + nNumericOffset] ? 1.0 : hpwhNumeric[9 + nNumericOffset];
    2217              : 
    2218              :         // Control Sensor 2 Location In Stratified Tank
    2219           12 :         if (!hpwhNumericBlank[10 + nNumericOffset]) {
    2220           12 :             HPWH.ControlSensor2Height = hpwhNumeric[10 + nNumericOffset];
    2221              :         } else {
    2222            0 :             HPWH.ControlSensor2Height = -1.0;
    2223              :         }
    2224              : 
    2225              :         // Control Sensor 2 Weight
    2226           12 :         HPWH.ControlSensor2Weight = 1.0 - HPWH.ControlSensor1Weight;
    2227           12 :     }
    2228              : 
    2229           10 :     return ErrorsFound;
    2230              : }
    2231              : 
    2232           16 : bool getWaterHeaterMixedInputs(EnergyPlusData &state)
    2233              : {
    2234           16 :     bool ErrorsFound = false;
    2235           16 :     state.dataIPShortCut->cCurrentModuleObject = cMixedWHModuleObj;
    2236              :     static constexpr std::string_view routineName = "getWaterHeaterMixedInputs";
    2237              : 
    2238           34 :     for (int WaterThermalTankNum = 1; WaterThermalTankNum <= state.dataWaterThermalTanks->numWaterHeaterMixed; ++WaterThermalTankNum) {
    2239              :         int NumAlphas;
    2240              :         int NumNums;
    2241              :         int IOStat;
    2242           36 :         state.dataInputProcessing->inputProcessor->getObjectItem(state,
    2243           18 :                                                                  state.dataIPShortCut->cCurrentModuleObject,
    2244              :                                                                  WaterThermalTankNum,
    2245           18 :                                                                  state.dataIPShortCut->cAlphaArgs,
    2246              :                                                                  NumAlphas,
    2247           18 :                                                                  state.dataIPShortCut->rNumericArgs,
    2248              :                                                                  NumNums,
    2249              :                                                                  IOStat,
    2250           18 :                                                                  state.dataIPShortCut->lNumericFieldBlanks,
    2251           18 :                                                                  state.dataIPShortCut->lAlphaFieldBlanks,
    2252           18 :                                                                  state.dataIPShortCut->cAlphaFieldNames,
    2253           18 :                                                                  state.dataIPShortCut->cNumericFieldNames);
    2254              : 
    2255           18 :         ErrorObjectHeader eoh{routineName, state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)};
    2256           18 :         GlobalNames::VerifyUniqueInterObjectName(state,
    2257           18 :                                                  state.dataWaterThermalTanks->UniqueWaterThermalTankNames,
    2258           18 :                                                  state.dataIPShortCut->cAlphaArgs(1),
    2259           18 :                                                  state.dataIPShortCut->cCurrentModuleObject,
    2260           18 :                                                  state.dataIPShortCut->cAlphaFieldNames(1),
    2261              :                                                  ErrorsFound);
    2262              : 
    2263           18 :         auto &Tank = state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum);
    2264              : 
    2265           18 :         Tank.Name = state.dataIPShortCut->cAlphaArgs(1);
    2266           18 :         Tank.Type = state.dataIPShortCut->cCurrentModuleObject;
    2267           18 :         Tank.WaterThermalTankType = DataPlant::PlantEquipmentType::WtrHeaterMixed;
    2268              : 
    2269           18 :         if ((Tank.water = Fluid::GetWater(state)) == nullptr) {
    2270            0 :             ShowSevereError(state, "Fluid properties for WATER not found");
    2271            0 :             ErrorsFound = true;
    2272              :         }
    2273              : 
    2274              :         // default to always on
    2275           18 :         Tank.sourceSideAvailSched = Sched::GetScheduleAlwaysOn(state);
    2276           18 :         Tank.useSideAvailSched = Sched::GetScheduleAlwaysOn(state);
    2277              : 
    2278              :         // A user field will be added in a later release
    2279           18 :         Tank.EndUseSubcategoryName = "Water Heater";
    2280              : 
    2281           18 :         Tank.Volume = state.dataIPShortCut->rNumericArgs(1);
    2282           18 :         if (Tank.Volume == DataSizing::AutoSize) {
    2283            1 :             Tank.VolumeWasAutoSized = true;
    2284              :         }
    2285           18 :         if (state.dataIPShortCut->rNumericArgs(1) == 0.0) {
    2286              :             // Set volume to a really small number to simulate a tankless/instantaneous water heater
    2287            0 :             Tank.Volume = 0.000001; // = 1 cm3
    2288              :         }
    2289              : 
    2290           18 :         if (state.dataIPShortCut->lAlphaFieldBlanks(2)) {
    2291            0 :             ShowSevereEmptyField(state, eoh, state.dataIPShortCut->cAlphaFieldNames(2));
    2292            0 :             ErrorsFound = true;
    2293           18 :         } else if ((Tank.setptTempSched = Sched::GetSchedule(state, state.dataIPShortCut->cAlphaArgs(2))) == nullptr) {
    2294            0 :             ShowSevereItemNotFound(state, eoh, state.dataIPShortCut->cAlphaFieldNames(2), state.dataIPShortCut->cAlphaArgs(2));
    2295            0 :             ErrorsFound = true;
    2296              :         }
    2297              : 
    2298           18 :         if (state.dataIPShortCut->rNumericArgs(2) > 0.0001) {
    2299           18 :             Tank.DeadBandDeltaTemp = state.dataIPShortCut->rNumericArgs(2);
    2300              :         } else {
    2301              :             // Default to very small number (however it can't be TINY or it will break the algorithm)
    2302            0 :             Tank.DeadBandDeltaTemp = 0.5;
    2303              :         }
    2304              : 
    2305           18 :         if (state.dataIPShortCut->rNumericArgs(3) > 0.0) {
    2306           18 :             Tank.TankTempLimit = state.dataIPShortCut->rNumericArgs(3);
    2307              :         } else {
    2308              :             // Default to very large number
    2309              :             // BG comment why a large number here why not boilng point of water?
    2310            0 :             Tank.TankTempLimit = 100.0; // 1.0E9
    2311              :         }
    2312              : 
    2313           18 :         Tank.MaxCapacity = state.dataIPShortCut->rNumericArgs(4);
    2314           18 :         if (Tank.MaxCapacity == DataSizing::AutoSize) {
    2315            0 :             Tank.MaxCapacityWasAutoSized = true;
    2316              :         }
    2317              : 
    2318           18 :         if ((state.dataIPShortCut->rNumericArgs(5) > Tank.MaxCapacity) && (!Tank.MaxCapacityWasAutoSized)) {
    2319            0 :             ShowSevereError(state,
    2320            0 :                             format("{} = {}:  Heater Minimum Capacity cannot be greater than Heater Maximum Capacity",
    2321            0 :                                    state.dataIPShortCut->cCurrentModuleObject,
    2322            0 :                                    state.dataIPShortCut->cAlphaArgs(1)));
    2323            0 :             ErrorsFound = true;
    2324              :         } else {
    2325           18 :             Tank.MinCapacity = state.dataIPShortCut->rNumericArgs(5);
    2326              :         }
    2327              : 
    2328              :         // Validate Heater Control Type
    2329           18 :         Tank.ControlType =
    2330           18 :             static_cast<HeaterControlMode>(getEnumValue(HeaterControlModeNamesUC, Util::makeUPPER(state.dataIPShortCut->cAlphaArgs(3))));
    2331           18 :         switch (Tank.ControlType) {
    2332           18 :         case HeaterControlMode::Cycle: {
    2333           18 :             Tank.MinCapacity = Tank.MaxCapacity;
    2334           18 :             break;
    2335              :         }
    2336            0 :         case HeaterControlMode::Modulate: {
    2337              : 
    2338              :             // CASE ('MODULATE WITH OVERHEAT')  ! Not yet implemented
    2339              : 
    2340              :             // CASE ('MODULATE WITH UNDERHEAT')  ! Not yet implemented
    2341              : 
    2342            0 :             break;
    2343              :         }
    2344            0 :         default: {
    2345            0 :             ShowSevereError(state,
    2346            0 :                             format("{} = {}:  Invalid Control Type entered={}",
    2347            0 :                                    state.dataIPShortCut->cCurrentModuleObject,
    2348            0 :                                    state.dataIPShortCut->cAlphaArgs(1),
    2349            0 :                                    state.dataIPShortCut->cAlphaArgs(3)));
    2350            0 :             ErrorsFound = true;
    2351            0 :             break;
    2352              :         }
    2353              :         }
    2354              : 
    2355           18 :         Tank.VolFlowRateMin = state.dataIPShortCut->rNumericArgs(6);
    2356           18 :         Tank.VolFlowRateMin = max(0.0, Tank.VolFlowRateMin);
    2357           18 :         Tank.IgnitionDelay = state.dataIPShortCut->rNumericArgs(7); // Not yet implemented
    2358              : 
    2359              :         // Validate Heater Fuel Type
    2360           18 :         Tank.FuelType = static_cast<Constant::eFuel>(getEnumValue(Constant::eFuelNamesUC, state.dataIPShortCut->cAlphaArgs(4)));
    2361           18 :         switch (Tank.FuelType) {
    2362            0 :         case Constant::eFuel::Invalid: {
    2363            0 :             ShowSevereError(state,
    2364            0 :                             format("{} = {}:  Invalid Heater Fuel Type entered={}",
    2365            0 :                                    state.dataIPShortCut->cCurrentModuleObject,
    2366            0 :                                    state.dataIPShortCut->cAlphaArgs(1),
    2367            0 :                                    state.dataIPShortCut->cAlphaArgs(4)));
    2368              :             // Set to Electric to avoid errors when setting up output variables
    2369            0 :             Tank.FuelType = Constant::eFuel::Electricity;
    2370            0 :             ErrorsFound = true;
    2371            0 :             break;
    2372              :         }
    2373           18 :         default:
    2374           18 :             break;
    2375              :         }
    2376              : 
    2377           18 :         if (state.dataIPShortCut->rNumericArgs(8) > 0.0) {
    2378           18 :             Tank.Efficiency = state.dataIPShortCut->rNumericArgs(8);
    2379           18 :             if (state.dataIPShortCut->rNumericArgs(8) > 1.0) {
    2380            0 :                 ShowWarningError(state,
    2381            0 :                                  fmt::format("{} = {}: {}={} should not typically be greater than 1.",
    2382            0 :                                              state.dataIPShortCut->cCurrentModuleObject,
    2383            0 :                                              state.dataIPShortCut->cAlphaArgs(1),
    2384            0 :                                              state.dataIPShortCut->cNumericFieldNames(8),
    2385            0 :                                              state.dataIPShortCut->rNumericArgs(8)));
    2386              :             }
    2387              :         } else {
    2388            0 :             ShowSevereError(state,
    2389            0 :                             format("{} = {}:  Heater Thermal Efficiency must be greater than zero",
    2390            0 :                                    state.dataIPShortCut->cCurrentModuleObject,
    2391            0 :                                    state.dataIPShortCut->cAlphaArgs(1)));
    2392            0 :             ErrorsFound = true;
    2393              :         }
    2394              : 
    2395           18 :         if (!state.dataIPShortCut->cAlphaArgs(5).empty()) {
    2396            0 :             Tank.PLFCurve = Curve::GetCurveIndex(state, state.dataIPShortCut->cAlphaArgs(5));
    2397            0 :             if (Tank.PLFCurve == 0) {
    2398            0 :                 ShowSevereError(state,
    2399            0 :                                 format("{} = {}:  Part Load Factor curve not found = {}",
    2400            0 :                                        state.dataIPShortCut->cCurrentModuleObject,
    2401            0 :                                        state.dataIPShortCut->cAlphaArgs(1),
    2402            0 :                                        state.dataIPShortCut->cAlphaArgs(5)));
    2403            0 :                 ErrorsFound = true;
    2404              :             } else {
    2405              :                 bool IsValid;
    2406            0 :                 EnergyPlus::WaterThermalTanks::WaterThermalTankData::ValidatePLFCurve(state, Tank.PLFCurve, IsValid);
    2407              : 
    2408            0 :                 if (!IsValid) {
    2409            0 :                     ShowSevereError(
    2410              :                         state,
    2411            0 :                         format("{} = {}:  Part Load Factor curve failed to evaluate to greater than zero for all numbers in the domain of 0 to 1",
    2412            0 :                                state.dataIPShortCut->cCurrentModuleObject,
    2413            0 :                                state.dataIPShortCut->cAlphaArgs(1)));
    2414            0 :                     ErrorsFound = true;
    2415              :                 }
    2416              : 
    2417            0 :                 ErrorsFound |= Curve::CheckCurveDims(state,
    2418              :                                                      Tank.PLFCurve,                              // Curve index
    2419              :                                                      {1},                                        // Valid dimensions
    2420              :                                                      routineName,                                // Routine name
    2421            0 :                                                      state.dataIPShortCut->cCurrentModuleObject, // Object Type
    2422              :                                                      Tank.Name,                                  // Object Name
    2423            0 :                                                      state.dataIPShortCut->cAlphaFieldNames(5)); // Field Name
    2424              :             }
    2425              :         }
    2426              : 
    2427           18 :         Tank.OffCycParaLoad = state.dataIPShortCut->rNumericArgs(9);
    2428              : 
    2429              :         // Validate Off-Cycle Parasitic Fuel Type
    2430           18 :         Tank.OffCycParaFuelType = static_cast<Constant::eFuel>(getEnumValue(Constant::eFuelNamesUC, state.dataIPShortCut->cAlphaArgs(6)));
    2431           18 :         switch (Tank.OffCycParaFuelType) {
    2432            1 :         case Constant::eFuel::Invalid:
    2433            1 :             if (state.dataIPShortCut->cAlphaArgs(6).empty()) { // If blank, default to Fuel Type for heater
    2434            1 :                 Tank.OffCycParaFuelType = Tank.FuelType;
    2435              :             } else { // could have been an unsupported value
    2436            0 :                 ShowSevereError(state,
    2437            0 :                                 format("{} = {}:  Invalid Off-Cycle Parasitic Fuel Type entered={}",
    2438            0 :                                        state.dataIPShortCut->cCurrentModuleObject,
    2439            0 :                                        state.dataIPShortCut->cAlphaArgs(1),
    2440            0 :                                        state.dataIPShortCut->cAlphaArgs(6)));
    2441              :                 // Set to Electric to avoid errors when setting up output variables
    2442            0 :                 Tank.OffCycParaFuelType = Constant::eFuel::Electricity;
    2443            0 :                 ErrorsFound = true;
    2444              :             }
    2445            1 :             break;
    2446           17 :         default:
    2447           17 :             break;
    2448              :         }
    2449              : 
    2450           18 :         Tank.OffCycParaFracToTank = state.dataIPShortCut->rNumericArgs(10);
    2451              : 
    2452           18 :         Tank.OnCycParaLoad = state.dataIPShortCut->rNumericArgs(11);
    2453              : 
    2454              :         // Validate On-Cycle Parasitic Fuel Type
    2455           18 :         Tank.OnCycParaFuelType = static_cast<Constant::eFuel>(getEnumValue(Constant::eFuelNamesUC, state.dataIPShortCut->cAlphaArgs(7)));
    2456           18 :         switch (Tank.OnCycParaFuelType) {
    2457            1 :         case Constant::eFuel::Invalid:
    2458            1 :             if (state.dataIPShortCut->cAlphaArgs(7).empty()) { // If blank, default to Fuel Type for heater
    2459            1 :                 Tank.OnCycParaFuelType = Tank.FuelType;
    2460              :             } else { // could have been an unsupported value
    2461            0 :                 ShowSevereError(state,
    2462            0 :                                 format("{} = {}:  Invalid On-Cycle Parasitic Fuel Type entered={}",
    2463            0 :                                        state.dataIPShortCut->cCurrentModuleObject,
    2464            0 :                                        state.dataIPShortCut->cAlphaArgs(1),
    2465            0 :                                        state.dataIPShortCut->cAlphaArgs(7)));
    2466              :                 // Set to Electric to avoid errors when setting up output variables
    2467            0 :                 Tank.OnCycParaFuelType = Constant::eFuel::Electricity;
    2468            0 :                 ErrorsFound = true;
    2469              :             }
    2470            1 :             break;
    2471           17 :         default:
    2472           17 :             break;
    2473              :         }
    2474              : 
    2475           18 :         Tank.OnCycParaFracToTank = state.dataIPShortCut->rNumericArgs(12);
    2476              : 
    2477           18 :         Tank.AmbientTempIndicator =
    2478           18 :             static_cast<WTTAmbientTemp>(getEnumValue(TankAmbientTempNamesUC, Util::makeUPPER(state.dataIPShortCut->cAlphaArgs(8))));
    2479           18 :         switch (Tank.AmbientTempIndicator) {
    2480              : 
    2481           14 :         case WTTAmbientTemp::Schedule: {
    2482           14 :             if (state.dataIPShortCut->lAlphaFieldBlanks(9)) {
    2483            0 :                 ShowSevereEmptyField(state, eoh, state.dataIPShortCut->cAlphaFieldNames(9));
    2484            0 :                 ErrorsFound = true;
    2485           14 :             } else if ((Tank.ambientTempSched = Sched::GetSchedule(state, state.dataIPShortCut->cAlphaArgs(9))) == nullptr) {
    2486            0 :                 ShowSevereItemNotFound(state, eoh, state.dataIPShortCut->cAlphaFieldNames(9), state.dataIPShortCut->cAlphaArgs(9));
    2487            0 :                 ErrorsFound = true;
    2488              :             }
    2489           14 :         } break;
    2490              : 
    2491            4 :         case WTTAmbientTemp::TempZone: {
    2492            4 :             Tank.AmbientTempZone = Util::FindItemInList(state.dataIPShortCut->cAlphaArgs(10), state.dataHeatBal->Zone);
    2493            4 :             if (Tank.AmbientTempZone == 0) {
    2494            4 :                 ShowSevereError(state,
    2495            8 :                                 format("{} = {}:  Ambient Temperature Zone not found = {}",
    2496            2 :                                        state.dataIPShortCut->cCurrentModuleObject,
    2497            2 :                                        state.dataIPShortCut->cAlphaArgs(1),
    2498            2 :                                        state.dataIPShortCut->cAlphaArgs(10)));
    2499            2 :                 ErrorsFound = true;
    2500              :             }
    2501            4 :         } break;
    2502              : 
    2503            0 :         case WTTAmbientTemp::OutsideAir: {
    2504            0 :             Tank.AmbientTempOutsideAirNode = NodeInputManager::GetOnlySingleNode(state,
    2505            0 :                                                                                  state.dataIPShortCut->cAlphaArgs(11),
    2506              :                                                                                  ErrorsFound,
    2507              :                                                                                  DataLoopNode::ConnectionObjectType::WaterHeaterMixed,
    2508            0 :                                                                                  state.dataIPShortCut->cAlphaArgs(1),
    2509              :                                                                                  DataLoopNode::NodeFluidType::Air,
    2510              :                                                                                  DataLoopNode::ConnectionType::OutsideAirReference,
    2511              :                                                                                  NodeInputManager::CompFluidStream::Primary,
    2512              :                                                                                  DataLoopNode::ObjectIsNotParent);
    2513            0 :             if (!state.dataIPShortCut->cAlphaArgs(11).empty()) {
    2514            0 :                 if (!OutAirNodeManager::CheckOutAirNodeNumber(state, Tank.AmbientTempOutsideAirNode)) {
    2515            0 :                     ShowSevereError(state,
    2516            0 :                                     format("{} = {}: Outdoor Air Node not on OutdoorAir:NodeList or OutdoorAir:Node",
    2517            0 :                                            state.dataIPShortCut->cCurrentModuleObject,
    2518            0 :                                            state.dataIPShortCut->cAlphaArgs(1)));
    2519            0 :                     ShowContinueError(state, format("...Referenced Node Name={}", state.dataIPShortCut->cAlphaArgs(11)));
    2520            0 :                     ErrorsFound = true;
    2521              :                 }
    2522              :             } else {
    2523            0 :                 ShowSevereError(state, format("{} = {}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
    2524            0 :                 ShowContinueError(state, "An Ambient Outdoor Air Node name must be used when the Ambient Temperature Indicator is Outdoors.");
    2525            0 :                 ErrorsFound = true;
    2526              :             }
    2527              : 
    2528            0 :             break;
    2529              :         }
    2530            0 :         default: {
    2531            0 :             ShowSevereError(state,
    2532            0 :                             format("{} = {}:  Invalid Ambient Temperature Indicator entered={}",
    2533            0 :                                    state.dataIPShortCut->cCurrentModuleObject,
    2534            0 :                                    state.dataIPShortCut->cAlphaArgs(1),
    2535            0 :                                    state.dataIPShortCut->cAlphaArgs(8)));
    2536            0 :             ShowContinueError(state, " Valid entries are SCHEDULE, ZONE, and OUTDOORS.");
    2537            0 :             ErrorsFound = true;
    2538            0 :             break;
    2539              :         }
    2540              :         }
    2541              : 
    2542           18 :         Tank.OffCycLossCoeff = state.dataIPShortCut->rNumericArgs(13);
    2543           18 :         Tank.OffCycLossFracToZone = state.dataIPShortCut->rNumericArgs(14);
    2544              : 
    2545           18 :         Tank.OnCycLossCoeff = state.dataIPShortCut->rNumericArgs(15);
    2546           18 :         Tank.OnCycLossFracToZone = state.dataIPShortCut->rNumericArgs(16);
    2547           18 :         Real64 rho = Tank.water->getDensity(state, Constant::InitConvTemp, routineName);
    2548              : 
    2549           18 :         Tank.MassFlowRateMax = state.dataIPShortCut->rNumericArgs(17) * rho;
    2550              : 
    2551           18 :         if ((state.dataIPShortCut->cAlphaArgs(14).empty()) && (state.dataIPShortCut->cAlphaArgs(15).empty())) {
    2552           12 :             if (state.dataIPShortCut->lAlphaFieldBlanks(12)) {
    2553            9 :             } else if ((Tank.flowRateSched = Sched::GetSchedule(state, state.dataIPShortCut->cAlphaArgs(12))) == nullptr) {
    2554            0 :                 ShowSevereItemNotFound(state, eoh, state.dataIPShortCut->cAlphaFieldNames(12), state.dataIPShortCut->cAlphaArgs(12));
    2555            0 :                 ErrorsFound = true;
    2556              :             }
    2557              :         }
    2558              : 
    2559           18 :         if (state.dataIPShortCut->lAlphaFieldBlanks(13)) {
    2560            0 :         } else if ((Tank.useInletTempSched = Sched::GetSchedule(state, state.dataIPShortCut->cAlphaArgs(13))) == nullptr) {
    2561            0 :             ShowSevereItemNotFound(state, eoh, state.dataIPShortCut->cAlphaFieldNames(13), state.dataIPShortCut->cAlphaArgs(13));
    2562            0 :             ErrorsFound = true;
    2563              :         }
    2564              : 
    2565           18 :         if (NumNums > 17) {
    2566           18 :             if ((state.dataIPShortCut->rNumericArgs(18) > 1) || (state.dataIPShortCut->rNumericArgs(18) < 0)) {
    2567            0 :                 ShowSevereError(state,
    2568            0 :                                 format("{} = {}:  Use Side Effectiveness is out of bounds (0 to 1)",
    2569            0 :                                        state.dataIPShortCut->cCurrentModuleObject,
    2570            0 :                                        state.dataIPShortCut->cAlphaArgs(1)));
    2571            0 :                 ErrorsFound = true;
    2572              :             }
    2573           18 :             Tank.UseEffectiveness = state.dataIPShortCut->rNumericArgs(18);
    2574              :         } else {
    2575            0 :             Tank.UseEffectiveness = 1.0; // Default for stand-alone mode
    2576              :         }
    2577              : 
    2578           18 :         if (NumNums > 18) {
    2579           18 :             if ((state.dataIPShortCut->rNumericArgs(19) > 1) || (state.dataIPShortCut->rNumericArgs(19) <= 0)) {
    2580            0 :                 ShowSevereError(state,
    2581            0 :                                 format("{} = {}:  Source Side Effectiveness is out of bounds (>0 to 1)",
    2582            0 :                                        state.dataIPShortCut->cCurrentModuleObject,
    2583            0 :                                        state.dataIPShortCut->cAlphaArgs(1)));
    2584            0 :                 ErrorsFound = true;
    2585              :             }
    2586           18 :             Tank.SourceEffectiveness = state.dataIPShortCut->rNumericArgs(19);
    2587              :         } else {
    2588            0 :             Tank.SourceEffectiveness = 1.0;
    2589              :         }
    2590              : 
    2591              :         // If no plant nodes are connected, simulate in stand-alone mode.
    2592           42 :         if (state.dataIPShortCut->cAlphaArgs(14).empty() && state.dataIPShortCut->cAlphaArgs(15).empty() &&
    2593           42 :             state.dataIPShortCut->cAlphaArgs(16).empty() && state.dataIPShortCut->cAlphaArgs(17).empty()) {
    2594            2 :             Tank.StandAlone = true;
    2595              :         }
    2596              : 
    2597           18 :         if (!state.dataIPShortCut->lNumericFieldBlanks(20)) {
    2598           11 :             Tank.UseDesignVolFlowRate = state.dataIPShortCut->rNumericArgs(20);
    2599           11 :             if (Tank.UseDesignVolFlowRate == DataSizing::AutoSize) {
    2600            5 :                 Tank.UseDesignVolFlowRateWasAutoSized = true;
    2601              :             }
    2602              :         } else {
    2603            7 :             Tank.UseDesignVolFlowRate = 0.0;
    2604              :         }
    2605           18 :         Tank.UseSidePlantLoc.loopSideNum = DataPlant::LoopSideLocation::Invalid;
    2606              : 
    2607           18 :         if (!state.dataIPShortCut->lNumericFieldBlanks(21)) {
    2608            6 :             Tank.SourceDesignVolFlowRate = state.dataIPShortCut->rNumericArgs(21);
    2609            6 :             if (Tank.SourceDesignVolFlowRate == DataSizing::AutoSize) {
    2610            4 :                 Tank.SourceDesignVolFlowRateWasAutoSized = true;
    2611              :             }
    2612              :         } else {
    2613           12 :             Tank.SourceDesignVolFlowRate = 0.0;
    2614              :         }
    2615           18 :         Tank.SrcSidePlantLoc.loopSideNum = DataPlant::LoopSideLocation::Invalid;
    2616              : 
    2617           18 :         if (!state.dataIPShortCut->lNumericFieldBlanks(22)) {
    2618           11 :             Tank.SizingRecoveryTime = state.dataIPShortCut->rNumericArgs(22);
    2619              :         } else {
    2620            7 :             Tank.SizingRecoveryTime = 1.5;
    2621              :         }
    2622              : 
    2623           18 :         if ((!state.dataIPShortCut->cAlphaArgs(14).empty()) || (!state.dataIPShortCut->cAlphaArgs(15).empty())) {
    2624            6 :             Tank.UseInletNode = NodeInputManager::GetOnlySingleNode(state,
    2625            6 :                                                                     state.dataIPShortCut->cAlphaArgs(14),
    2626              :                                                                     ErrorsFound,
    2627              :                                                                     DataLoopNode::ConnectionObjectType::WaterHeaterMixed,
    2628            6 :                                                                     state.dataIPShortCut->cAlphaArgs(1),
    2629              :                                                                     DataLoopNode::NodeFluidType::Water,
    2630              :                                                                     DataLoopNode::ConnectionType::Inlet,
    2631              :                                                                     NodeInputManager::CompFluidStream::Primary,
    2632              :                                                                     DataLoopNode::ObjectIsNotParent);
    2633            6 :             Tank.InletNodeName1 = state.dataIPShortCut->cAlphaArgs(14);
    2634            6 :             Tank.UseOutletNode = NodeInputManager::GetOnlySingleNode(state,
    2635            6 :                                                                      state.dataIPShortCut->cAlphaArgs(15),
    2636              :                                                                      ErrorsFound,
    2637              :                                                                      DataLoopNode::ConnectionObjectType::WaterHeaterMixed,
    2638            6 :                                                                      state.dataIPShortCut->cAlphaArgs(1),
    2639              :                                                                      DataLoopNode::NodeFluidType::Water,
    2640              :                                                                      DataLoopNode::ConnectionType::Outlet,
    2641              :                                                                      NodeInputManager::CompFluidStream::Primary,
    2642              :                                                                      DataLoopNode::ObjectIsNotParent);
    2643            6 :             Tank.OutletNodeName1 = state.dataIPShortCut->cAlphaArgs(15);
    2644              : 
    2645            6 :             if (state.dataIPShortCut->rNumericArgs(17) > 0) {
    2646            8 :                 ShowWarningError(state,
    2647           12 :                                  format("{} = {}:  Use side nodes are specified; Peak Volumetric Use Flow Rate will not be used",
    2648            4 :                                         state.dataIPShortCut->cCurrentModuleObject,
    2649            4 :                                         state.dataIPShortCut->cAlphaArgs(1)));
    2650              :             }
    2651              : 
    2652            6 :             if (Tank.flowRateSched != nullptr) {
    2653            0 :                 ShowWarningError(state,
    2654            0 :                                  format("{} = {}:  Use side nodes are specified; Use Flow Rate Fraction Schedule will not be used",
    2655            0 :                                         state.dataIPShortCut->cCurrentModuleObject,
    2656            0 :                                         state.dataIPShortCut->cAlphaArgs(1)));
    2657              :             }
    2658              : 
    2659            6 :             if (Tank.useInletTempSched != nullptr) {
    2660            0 :                 ShowWarningError(state,
    2661            0 :                                  format("{} = {}:  Use side nodes are specified; Cold Water Supply Temperature Schedule will not be used",
    2662            0 :                                         state.dataIPShortCut->cCurrentModuleObject,
    2663            0 :                                         state.dataIPShortCut->cAlphaArgs(1)));
    2664              :             }
    2665              :         }
    2666              : 
    2667           18 :         if ((!state.dataIPShortCut->cAlphaArgs(16).empty()) || (!state.dataIPShortCut->cAlphaArgs(17).empty())) {
    2668           16 :             Tank.SourceInletNode = NodeInputManager::GetOnlySingleNode(state,
    2669           16 :                                                                        state.dataIPShortCut->cAlphaArgs(16),
    2670              :                                                                        ErrorsFound,
    2671              :                                                                        DataLoopNode::ConnectionObjectType::WaterHeaterMixed,
    2672           16 :                                                                        state.dataIPShortCut->cAlphaArgs(1),
    2673              :                                                                        DataLoopNode::NodeFluidType::Water,
    2674              :                                                                        DataLoopNode::ConnectionType::Inlet,
    2675              :                                                                        NodeInputManager::CompFluidStream::Secondary,
    2676              :                                                                        DataLoopNode::ObjectIsNotParent);
    2677           16 :             Tank.InletNodeName2 = state.dataIPShortCut->cAlphaArgs(16);
    2678           16 :             Tank.SourceOutletNode = NodeInputManager::GetOnlySingleNode(state,
    2679           16 :                                                                         state.dataIPShortCut->cAlphaArgs(17),
    2680              :                                                                         ErrorsFound,
    2681              :                                                                         DataLoopNode::ConnectionObjectType::WaterHeaterMixed,
    2682           16 :                                                                         state.dataIPShortCut->cAlphaArgs(1),
    2683              :                                                                         DataLoopNode::NodeFluidType::Water,
    2684              :                                                                         DataLoopNode::ConnectionType::Outlet,
    2685              :                                                                         NodeInputManager::CompFluidStream::Secondary,
    2686              :                                                                         DataLoopNode::ObjectIsNotParent);
    2687           16 :             Tank.OutletNodeName2 = state.dataIPShortCut->cAlphaArgs(17);
    2688              :         }
    2689              : 
    2690           18 :         if (!state.dataIPShortCut->lAlphaFieldBlanks(18)) {
    2691            9 :             Tank.SourceSideControlMode =
    2692            9 :                 static_cast<SourceSideControl>(getEnumValue(SourceSideControlNamesUC, Util::makeUPPER(state.dataIPShortCut->cAlphaArgs(18))));
    2693            9 :             if (Tank.SourceSideControlMode == SourceSideControl::Invalid) {
    2694            0 :                 ShowSevereError(state,
    2695            0 :                                 format("{} = {}:  Invalid Control Mode entered={}",
    2696            0 :                                        state.dataIPShortCut->cCurrentModuleObject,
    2697            0 :                                        state.dataIPShortCut->cAlphaArgs(1),
    2698            0 :                                        state.dataIPShortCut->cAlphaArgs(18)));
    2699            0 :                 ErrorsFound = true;
    2700              :             }
    2701              :         } else {
    2702            9 :             Tank.SourceSideControlMode = SourceSideControl::IndirectHeatPrimarySetpoint;
    2703              :         }
    2704              : 
    2705           18 :         if (state.dataIPShortCut->lAlphaFieldBlanks(19)) {
    2706            2 :         } else if ((Tank.sourceSideAltSetpointSched = Sched::GetSchedule(state, state.dataIPShortCut->cAlphaArgs(19))) == nullptr) {
    2707            0 :             ShowSevereItemNotFound(state, eoh, state.dataIPShortCut->cAlphaFieldNames(19), state.dataIPShortCut->cAlphaArgs(19));
    2708            0 :             ErrorsFound = true;
    2709              :         }
    2710              : 
    2711           18 :         if (NumAlphas > 19) {
    2712            8 :             Tank.EndUseSubcategoryName = state.dataIPShortCut->cAlphaArgs(20);
    2713              :         }
    2714              : 
    2715              :     } // WaterThermalTankNum
    2716              : 
    2717           16 :     return ErrorsFound;
    2718              : }
    2719              : 
    2720           14 : bool getWaterHeaterStratifiedInput(EnergyPlusData &state)
    2721              : {
    2722           14 :     bool ErrorsFound = false;
    2723              :     static constexpr std::string_view routineName = "getWaterHeaterStratifiedInput";
    2724              : 
    2725           14 :     state.dataIPShortCut->cCurrentModuleObject = cStratifiedWHModuleObj; //'WaterHeater:Stratified'
    2726              : 
    2727           29 :     for (int WaterThermalTankNum = state.dataWaterThermalTanks->numWaterHeaterMixed + 1;
    2728           29 :          WaterThermalTankNum <= state.dataWaterThermalTanks->numWaterHeaterMixed + state.dataWaterThermalTanks->numWaterHeaterStratified;
    2729              :          ++WaterThermalTankNum) {
    2730              :         int NumAlphas;
    2731              :         int NumNums;
    2732              :         int IOStat;
    2733           30 :         state.dataInputProcessing->inputProcessor->getObjectItem(state,
    2734           15 :                                                                  state.dataIPShortCut->cCurrentModuleObject,
    2735           15 :                                                                  WaterThermalTankNum - state.dataWaterThermalTanks->numWaterHeaterMixed,
    2736           15 :                                                                  state.dataIPShortCut->cAlphaArgs,
    2737              :                                                                  NumAlphas,
    2738           15 :                                                                  state.dataIPShortCut->rNumericArgs,
    2739              :                                                                  NumNums,
    2740              :                                                                  IOStat,
    2741           15 :                                                                  state.dataIPShortCut->lNumericFieldBlanks,
    2742           15 :                                                                  state.dataIPShortCut->lAlphaFieldBlanks,
    2743           15 :                                                                  state.dataIPShortCut->cAlphaFieldNames,
    2744           15 :                                                                  state.dataIPShortCut->cNumericFieldNames);
    2745              : 
    2746           15 :         ErrorObjectHeader eoh{routineName, state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)};
    2747              : 
    2748           15 :         GlobalNames::VerifyUniqueInterObjectName(state,
    2749           15 :                                                  state.dataWaterThermalTanks->UniqueWaterThermalTankNames,
    2750           15 :                                                  state.dataIPShortCut->cAlphaArgs(1),
    2751           15 :                                                  state.dataIPShortCut->cCurrentModuleObject,
    2752           15 :                                                  state.dataIPShortCut->cAlphaFieldNames(1),
    2753              :                                                  ErrorsFound);
    2754              : 
    2755           15 :         auto &Tank = state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum);
    2756              : 
    2757           15 :         Tank.Name = state.dataIPShortCut->cAlphaArgs(1);
    2758           15 :         Tank.Type = state.dataIPShortCut->cCurrentModuleObject;
    2759           15 :         Tank.WaterThermalTankType = DataPlant::PlantEquipmentType::WtrHeaterStratified;
    2760              : 
    2761           15 :         if ((Tank.water = Fluid::GetWater(state)) == nullptr) {
    2762            0 :             ShowSevereError(state, "Fluid Properties for WATER not found.");
    2763            0 :             ErrorsFound = true;
    2764              :         }
    2765              : 
    2766              :         // default to always on
    2767           15 :         Tank.sourceSideAvailSched = Sched::GetScheduleAlwaysOn(state);
    2768           15 :         Tank.useSideAvailSched = Sched::GetScheduleAlwaysOn(state);
    2769              : 
    2770           15 :         Tank.EndUseSubcategoryName = state.dataIPShortCut->cAlphaArgs(2);
    2771              : 
    2772           15 :         Tank.Volume = state.dataIPShortCut->rNumericArgs(1);
    2773           15 :         if (Tank.Volume == DataSizing::AutoSize) {
    2774            0 :             Tank.VolumeWasAutoSized = true;
    2775              :         }
    2776           15 :         Real64 rho = Tank.water->getDensity(state, Constant::InitConvTemp, routineName);
    2777           15 :         Tank.Mass = Tank.Volume * rho;
    2778           15 :         Tank.Height = state.dataIPShortCut->rNumericArgs(2);
    2779           15 :         if (Tank.Height == DataSizing::AutoSize) {
    2780            0 :             Tank.HeightWasAutoSized = true;
    2781              :         }
    2782              : 
    2783           15 :         Tank.Shape = static_cast<TankShape>(getEnumValue(TankShapeNamesUC, Util::makeUPPER(state.dataIPShortCut->cAlphaArgs(3))));
    2784           15 :         switch (Tank.Shape) {
    2785           15 :         case TankShape::HorizCylinder:
    2786              :         case TankShape::VertCylinder: {
    2787           15 :             break;
    2788              :         }
    2789            0 :         case TankShape::Other: {
    2790            0 :             if (state.dataIPShortCut->rNumericArgs(3) > 0.0) {
    2791            0 :                 Tank.Perimeter = state.dataIPShortCut->rNumericArgs(3);
    2792              :             } else {
    2793            0 :                 ShowSevereError(state,
    2794            0 :                                 format("{} = {}:  Tank Perimeter must be greater than zero for Tank Shape=OTHER",
    2795            0 :                                        state.dataIPShortCut->cCurrentModuleObject,
    2796            0 :                                        state.dataIPShortCut->cAlphaArgs(1)));
    2797            0 :                 ErrorsFound = true;
    2798              :             }
    2799              : 
    2800            0 :             break;
    2801              :         }
    2802            0 :         default: {
    2803            0 :             ShowSevereError(state,
    2804            0 :                             format("{} = {}:  Invalid Tank Shape entered={}",
    2805            0 :                                    state.dataIPShortCut->cCurrentModuleObject,
    2806            0 :                                    state.dataIPShortCut->cAlphaArgs(1),
    2807            0 :                                    state.dataIPShortCut->cAlphaArgs(3)));
    2808            0 :             Tank.Shape = TankShape::VertCylinder;
    2809            0 :             ErrorsFound = true;
    2810            0 :             break;
    2811              :         }
    2812              :         }
    2813              : 
    2814           15 :         if (state.dataIPShortCut->rNumericArgs(4) > 0.0) {
    2815           13 :             Tank.TankTempLimit = state.dataIPShortCut->rNumericArgs(4);
    2816              :         } else {
    2817              :             // Default to very large number
    2818            2 :             Tank.TankTempLimit = 1.0e9;
    2819              :         }
    2820              : 
    2821              :         // Validate Heater Priority Control
    2822           15 :         Tank.StratifiedControlMode =
    2823           15 :             static_cast<PriorityControlMode>(getEnumValue(PriorityControlModeNamesUC, Util::makeUPPER(state.dataIPShortCut->cAlphaArgs(4))));
    2824           15 :         if (Tank.StratifiedControlMode == PriorityControlMode::Invalid) {
    2825            0 :             ShowSevereError(state,
    2826            0 :                             format("{} = {}:  Invalid Heater Priority Control entered={}",
    2827            0 :                                    state.dataIPShortCut->cCurrentModuleObject,
    2828            0 :                                    state.dataIPShortCut->cAlphaArgs(1),
    2829            0 :                                    state.dataIPShortCut->cAlphaArgs(4)));
    2830            0 :             ErrorsFound = true;
    2831              :         }
    2832              : 
    2833           15 :         if (state.dataIPShortCut->lAlphaFieldBlanks(5)) {
    2834            0 :             ShowSevereEmptyField(state, eoh, state.dataIPShortCut->cAlphaFieldNames(5));
    2835            0 :             ErrorsFound = true;
    2836           15 :         } else if ((Tank.setptTempSched = Sched::GetSchedule(state, state.dataIPShortCut->cAlphaArgs(5))) == nullptr) {
    2837            0 :             ShowSevereItemNotFound(state, eoh, state.dataIPShortCut->cAlphaFieldNames(5), state.dataIPShortCut->cAlphaArgs(5));
    2838            0 :             ErrorsFound = true;
    2839              :         }
    2840              : 
    2841           15 :         if (state.dataIPShortCut->rNumericArgs(5) > 0.0) {
    2842           15 :             Tank.DeadBandDeltaTemp = state.dataIPShortCut->rNumericArgs(5);
    2843              :         } else {
    2844              :             // Default to very small number (however it can't be TINY or it will break the algorithm)
    2845            0 :             Tank.DeadBandDeltaTemp = 0.0001;
    2846              :         }
    2847              : 
    2848           15 :         Tank.MaxCapacity = state.dataIPShortCut->rNumericArgs(6);
    2849           15 :         if (Tank.MaxCapacity == DataSizing::AutoSize) {
    2850            0 :             Tank.MaxCapacityWasAutoSized = true;
    2851              :         }
    2852              : 
    2853           15 :         Tank.HeaterHeight1 = state.dataIPShortCut->rNumericArgs(7);
    2854              : 
    2855              :         // adjust tank height used in these calculations for testing heater height
    2856              :         Real64 tankHeightForTesting;
    2857           15 :         if (Tank.Shape == TankShape::HorizCylinder) {
    2858            0 :             tankHeightForTesting = 2.0 * sqrt((Tank.Volume / Tank.Height) / Constant::Pi);
    2859              :         } else {
    2860           15 :             tankHeightForTesting = Tank.Height;
    2861              :         }
    2862              : 
    2863              :         // Test if Heater height is within range
    2864           15 :         if ((!Tank.HeightWasAutoSized) && (Tank.HeaterHeight1 > tankHeightForTesting)) {
    2865            0 :             ShowSevereError(state,
    2866            0 :                             format("{} = {}: Heater 1 is located higher than overall tank height.",
    2867            0 :                                    state.dataIPShortCut->cCurrentModuleObject,
    2868            0 :                                    state.dataIPShortCut->cAlphaArgs(1)));
    2869            0 :             ShowContinueError(state, format("{} = {:.4R}", state.dataIPShortCut->cNumericFieldNames(2), state.dataIPShortCut->rNumericArgs(2)));
    2870            0 :             ShowContinueError(state, format("{} = {:.4R}", state.dataIPShortCut->cNumericFieldNames(7), state.dataIPShortCut->rNumericArgs(7)));
    2871            0 :             ErrorsFound = true;
    2872              :         }
    2873              : 
    2874           15 :         if (state.dataIPShortCut->lAlphaFieldBlanks(6)) {
    2875            0 :             ShowSevereEmptyField(state, eoh, state.dataIPShortCut->cAlphaFieldNames(6));
    2876            0 :             ErrorsFound = true;
    2877           15 :         } else if ((Tank.setptTemp2Sched = Sched::GetSchedule(state, state.dataIPShortCut->cAlphaArgs(6))) == nullptr) {
    2878            0 :             ShowSevereItemNotFound(state, eoh, state.dataIPShortCut->cAlphaFieldNames(6), state.dataIPShortCut->cAlphaArgs(6));
    2879            0 :             ErrorsFound = true;
    2880              :         }
    2881              : 
    2882           15 :         if (state.dataIPShortCut->rNumericArgs(5) > 0.0) {
    2883           15 :             Tank.DeadBandDeltaTemp2 = state.dataIPShortCut->rNumericArgs(8);
    2884              :         } else {
    2885              :             // Default to very small number (however it can't be TINY or it will break the algorithm)
    2886            0 :             Tank.DeadBandDeltaTemp2 = 0.0001;
    2887              :         }
    2888              : 
    2889           15 :         Tank.MaxCapacity2 = state.dataIPShortCut->rNumericArgs(9);
    2890           15 :         Tank.HeaterHeight2 = state.dataIPShortCut->rNumericArgs(10);
    2891              : 
    2892              :         // Test if Heater height is within range
    2893           15 :         if ((!Tank.HeightWasAutoSized) && (Tank.HeaterHeight2 > tankHeightForTesting)) {
    2894            0 :             ShowSevereError(state,
    2895            0 :                             format("{} = {}: Heater 2 is located higher than overall tank height.",
    2896            0 :                                    state.dataIPShortCut->cCurrentModuleObject,
    2897            0 :                                    state.dataIPShortCut->cAlphaArgs(1)));
    2898            0 :             ShowContinueError(state, format("{} = {:.4R}", state.dataIPShortCut->cNumericFieldNames(2), state.dataIPShortCut->rNumericArgs(2)));
    2899            0 :             ShowContinueError(state, format("{} = {:.4R}", state.dataIPShortCut->cNumericFieldNames(10), state.dataIPShortCut->rNumericArgs(10)));
    2900            0 :             ErrorsFound = true;
    2901              :         }
    2902              : 
    2903              :         // Validate Heater Fuel Type
    2904           15 :         Tank.FuelType = static_cast<Constant::eFuel>(
    2905           15 :             getEnumValue(Constant::eFuelNamesUC,
    2906           15 :                          state.dataIPShortCut->cAlphaArgs(
    2907              :                              7))); // returns all kinds of fuels including district heat and cool + steam, returns unassigned if unsupported
    2908           15 :         if (Tank.FuelType == Constant::eFuel::Invalid) {
    2909            0 :             ShowSevereError(state,
    2910            0 :                             format("{} = {}:  Invalid Heater Fuel Type entered={}",
    2911            0 :                                    state.dataIPShortCut->cCurrentModuleObject,
    2912            0 :                                    state.dataIPShortCut->cAlphaArgs(1),
    2913            0 :                                    state.dataIPShortCut->cAlphaArgs(7)));
    2914              :             // Set to Electric to avoid errors when setting up output variables
    2915            0 :             Tank.FuelType = Constant::eFuel::Electricity;
    2916            0 :             ErrorsFound = true;
    2917              :         }
    2918              : 
    2919           15 :         if (state.dataIPShortCut->rNumericArgs(11) > 0.0) {
    2920           15 :             Tank.Efficiency = state.dataIPShortCut->rNumericArgs(11);
    2921           15 :             if (state.dataIPShortCut->rNumericArgs(11) > 1.0) {
    2922            0 :                 ShowWarningError(state,
    2923            0 :                                  fmt::format("{} = {}: {}={} should not typically be greater than 1.",
    2924            0 :                                              state.dataIPShortCut->cCurrentModuleObject,
    2925            0 :                                              state.dataIPShortCut->cAlphaArgs(1),
    2926            0 :                                              state.dataIPShortCut->cNumericFieldNames(11),
    2927            0 :                                              state.dataIPShortCut->rNumericArgs(11)));
    2928              :             }
    2929              :         } else {
    2930            0 :             ShowSevereError(state,
    2931            0 :                             format("{} = {}:  Heater Thermal Efficiency must be greater than zero",
    2932            0 :                                    state.dataIPShortCut->cCurrentModuleObject,
    2933            0 :                                    state.dataIPShortCut->cAlphaArgs(1)));
    2934            0 :             ErrorsFound = true;
    2935              :         }
    2936              : 
    2937           15 :         Tank.OffCycParaLoad = state.dataIPShortCut->rNumericArgs(12);
    2938              : 
    2939              :         // Validate Off-Cycle Parasitic Fuel Type
    2940           15 :         Tank.OffCycParaFuelType = static_cast<Constant::eFuel>(
    2941           15 :             getEnumValue(Constant::eFuelNamesUC,
    2942           15 :                          state.dataIPShortCut->cAlphaArgs(
    2943              :                              8))); // returns all kinds of fuels including district heat and cool + steam, returns unassigned if unsupported
    2944           15 :         if (Tank.OffCycParaFuelType == Constant::eFuel::Invalid) {
    2945            0 :             if (state.dataIPShortCut->cAlphaArgs(8).empty()) {
    2946            0 :                 Tank.OffCycParaFuelType = Tank.FuelType;
    2947              :             } else {
    2948            0 :                 ShowSevereError(state,
    2949            0 :                                 format("{} = {}:  Invalid Off-Cycle Parasitic Fuel Type entered={}",
    2950            0 :                                        state.dataIPShortCut->cCurrentModuleObject,
    2951            0 :                                        state.dataIPShortCut->cAlphaArgs(1),
    2952            0 :                                        state.dataIPShortCut->cAlphaArgs(8)));
    2953              :                 // Set to Electric to avoid errors when setting up output variables
    2954            0 :                 Tank.OffCycParaFuelType = Constant::eFuel::Electricity;
    2955            0 :                 ErrorsFound = true;
    2956              :             }
    2957              :         }
    2958              : 
    2959           15 :         Tank.OffCycParaFracToTank = state.dataIPShortCut->rNumericArgs(13);
    2960           15 :         Tank.OffCycParaHeight = state.dataIPShortCut->rNumericArgs(14);
    2961              : 
    2962           15 :         Tank.OnCycParaLoad = state.dataIPShortCut->rNumericArgs(15);
    2963              : 
    2964              :         // Validate On-Cycle Parasitic Fuel Type
    2965           15 :         Tank.OnCycParaFuelType = static_cast<Constant::eFuel>(
    2966           15 :             getEnumValue(Constant::eFuelNamesUC,
    2967           15 :                          state.dataIPShortCut->cAlphaArgs(
    2968              :                              9))); // returns all kinds of fuels including district heat and cool + steam, returns unassigned if unsupported/empty
    2969           15 :         if (Tank.OnCycParaFuelType == Constant::eFuel::Invalid) {
    2970            0 :             if (state.dataIPShortCut->cAlphaArgs(9).empty()) {
    2971            0 :                 Tank.OnCycParaFuelType = Tank.FuelType;
    2972              :             } else {
    2973            0 :                 ShowSevereError(state,
    2974            0 :                                 format("{} = {}:  Invalid On-Cycle Parasitic Fuel Type entered={}",
    2975            0 :                                        state.dataIPShortCut->cCurrentModuleObject,
    2976            0 :                                        state.dataIPShortCut->cAlphaArgs(1),
    2977            0 :                                        state.dataIPShortCut->cAlphaArgs(9)));
    2978              :                 // Set to Electric to avoid errors when setting up output variables
    2979            0 :                 Tank.OnCycParaFuelType = Constant::eFuel::Electricity;
    2980            0 :                 ErrorsFound = true;
    2981              :             }
    2982              :         }
    2983              : 
    2984           15 :         Tank.OnCycParaFracToTank = state.dataIPShortCut->rNumericArgs(16);
    2985           15 :         Tank.OnCycParaHeight = state.dataIPShortCut->rNumericArgs(17);
    2986              : 
    2987           15 :         Tank.AmbientTempIndicator =
    2988           15 :             static_cast<WTTAmbientTemp>(getEnumValue(TankAmbientTempNamesUC, Util::makeUPPER(state.dataIPShortCut->cAlphaArgs(10))));
    2989           15 :         switch (Tank.AmbientTempIndicator) {
    2990              : 
    2991           14 :         case WTTAmbientTemp::Schedule: {
    2992           14 :             if (state.dataIPShortCut->lAlphaFieldBlanks(11)) {
    2993            0 :                 ShowSevereEmptyField(state, eoh, state.dataIPShortCut->cAlphaFieldNames(11));
    2994            0 :                 ErrorsFound = true;
    2995           14 :             } else if ((Tank.ambientTempSched = Sched::GetSchedule(state, state.dataIPShortCut->cAlphaArgs(11))) == nullptr) {
    2996            0 :                 ShowSevereItemNotFound(state, eoh, state.dataIPShortCut->cAlphaFieldNames(11), state.dataIPShortCut->cAlphaArgs(11));
    2997            0 :                 ErrorsFound = true;
    2998              :             }
    2999           14 :         } break;
    3000              : 
    3001            1 :         case WTTAmbientTemp::TempZone: {
    3002            1 :             Tank.AmbientTempZone = Util::FindItemInList(state.dataIPShortCut->cAlphaArgs(12), state.dataHeatBal->Zone);
    3003            1 :             if (Tank.AmbientTempZone == 0) {
    3004            2 :                 ShowSevereError(state,
    3005            4 :                                 format("{} = {}:  Ambient Temperature Zone not found = {}",
    3006            1 :                                        state.dataIPShortCut->cCurrentModuleObject,
    3007            1 :                                        state.dataIPShortCut->cAlphaArgs(1),
    3008            1 :                                        state.dataIPShortCut->cAlphaArgs(12)));
    3009            1 :                 ErrorsFound = true;
    3010              :             }
    3011              : 
    3012            1 :             break;
    3013              :         }
    3014            0 :         case WTTAmbientTemp::OutsideAir: {
    3015            0 :             Tank.AmbientTempOutsideAirNode = NodeInputManager::GetOnlySingleNode(state,
    3016            0 :                                                                                  state.dataIPShortCut->cAlphaArgs(13),
    3017              :                                                                                  ErrorsFound,
    3018              :                                                                                  DataLoopNode::ConnectionObjectType::WaterHeaterStratified,
    3019            0 :                                                                                  state.dataIPShortCut->cAlphaArgs(1),
    3020              :                                                                                  DataLoopNode::NodeFluidType::Air,
    3021              :                                                                                  DataLoopNode::ConnectionType::Inlet,
    3022              :                                                                                  NodeInputManager::CompFluidStream::Primary,
    3023              :                                                                                  DataLoopNode::ObjectIsNotParent);
    3024            0 :             if (!state.dataIPShortCut->cAlphaArgs(13).empty()) {
    3025            0 :                 if (!OutAirNodeManager::CheckOutAirNodeNumber(state, Tank.AmbientTempOutsideAirNode)) {
    3026            0 :                     ShowSevereError(state,
    3027            0 :                                     format("{} = {}: Outdoor Air Node not on OutdoorAir:NodeList or OutdoorAir:Node",
    3028            0 :                                            state.dataIPShortCut->cCurrentModuleObject,
    3029            0 :                                            state.dataIPShortCut->cAlphaArgs(1)));
    3030            0 :                     ShowContinueError(state, format("...Referenced Node Name={}", state.dataIPShortCut->cAlphaArgs(13)));
    3031            0 :                     ErrorsFound = true;
    3032              :                 }
    3033              :             } else {
    3034            0 :                 ShowSevereError(state, format("{} = {}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
    3035            0 :                 ShowContinueError(state, "An Ambient Outdoor Air Node name must be used when the Ambient Temperature Indicator is Outdoors.");
    3036            0 :                 ErrorsFound = true;
    3037              :             }
    3038              : 
    3039            0 :             break;
    3040              :         }
    3041            0 :         default: {
    3042            0 :             ShowSevereError(state,
    3043            0 :                             format("{} = {}:  Invalid Ambient Temperature Indicator entered={}",
    3044            0 :                                    state.dataIPShortCut->cCurrentModuleObject,
    3045            0 :                                    state.dataIPShortCut->cAlphaArgs(1),
    3046            0 :                                    state.dataIPShortCut->cAlphaArgs(10)));
    3047            0 :             ShowContinueError(state, " Valid entries are Schedule, Zone, and Outdoors.");
    3048            0 :             ErrorsFound = true;
    3049            0 :             break;
    3050              :         }
    3051              :         }
    3052              : 
    3053           15 :         Tank.SkinLossCoeff = state.dataIPShortCut->rNumericArgs(18);
    3054           15 :         Tank.SkinLossFracToZone = state.dataIPShortCut->rNumericArgs(19);
    3055           15 :         Tank.OffCycFlueLossCoeff = state.dataIPShortCut->rNumericArgs(20);
    3056           15 :         Tank.OffCycFlueLossFracToZone = state.dataIPShortCut->rNumericArgs(21);
    3057              : 
    3058              :         // this is temporary until we know fluid type
    3059           15 :         rho = Tank.water->getDensity(state, Constant::InitConvTemp, routineName);
    3060              : 
    3061           15 :         Tank.MassFlowRateMax = state.dataIPShortCut->rNumericArgs(22) * rho;
    3062              : 
    3063           15 :         if ((state.dataIPShortCut->cAlphaArgs(16).empty()) && (state.dataIPShortCut->cAlphaArgs(17).empty())) {
    3064           10 :             if (state.dataIPShortCut->lAlphaFieldBlanks(14)) {
    3065            9 :             } else if ((Tank.flowRateSched = Sched::GetSchedule(state, state.dataIPShortCut->cAlphaArgs(14))) == nullptr) {
    3066            0 :                 ShowSevereItemNotFound(state, eoh, state.dataIPShortCut->cAlphaFieldNames(14), state.dataIPShortCut->cAlphaArgs(14));
    3067            0 :                 ErrorsFound = true;
    3068              :             }
    3069              :         }
    3070              : 
    3071           15 :         if (state.dataIPShortCut->lAlphaFieldBlanks(15)) {
    3072            5 :         } else if ((Tank.useInletTempSched = Sched::GetSchedule(state, state.dataIPShortCut->cAlphaArgs(15))) == nullptr) {
    3073            0 :             ShowSevereItemNotFound(state, eoh, state.dataIPShortCut->cAlphaFieldNames(15), state.dataIPShortCut->cAlphaArgs(15));
    3074            0 :             ErrorsFound = true;
    3075              :         }
    3076              : 
    3077           15 :         if (NumNums > 22) {
    3078           15 :             Tank.UseEffectiveness = state.dataIPShortCut->rNumericArgs(23);
    3079              :         } else {
    3080            0 :             Tank.UseEffectiveness = 1.0; // Default for stand-alone mode
    3081              :         }
    3082              : 
    3083           15 :         if (NumNums > 23) {
    3084           15 :             Tank.UseInletHeight = state.dataIPShortCut->rNumericArgs(24);
    3085              :         } else {
    3086              :             // Defaults to bottom of tank
    3087            0 :             Tank.UseInletHeight = 0.0;
    3088              :         }
    3089           15 :         if ((!Tank.HeightWasAutoSized) && (Tank.UseInletHeight > Tank.Height)) {
    3090            0 :             ShowSevereError(state,
    3091            0 :                             format("{} = {}: Use inlet is located higher than overall tank height.",
    3092            0 :                                    state.dataIPShortCut->cCurrentModuleObject,
    3093            0 :                                    state.dataIPShortCut->cAlphaArgs(1)));
    3094            0 :             ShowContinueError(state, format("{} = {:.4R}", state.dataIPShortCut->cNumericFieldNames(2), state.dataIPShortCut->rNumericArgs(2)));
    3095            0 :             ShowContinueError(state, format("{} = {:.4R}", state.dataIPShortCut->cNumericFieldNames(24), state.dataIPShortCut->rNumericArgs(24)));
    3096            0 :             ErrorsFound = true;
    3097              :         }
    3098              : 
    3099           15 :         if ((NumNums > 24) && (state.dataIPShortCut->rNumericArgs(25) != Constant::AutoCalculate)) {
    3100            2 :             Tank.UseOutletHeight = state.dataIPShortCut->rNumericArgs(25);
    3101              :         } else {
    3102              :             // Defaults to top of tank
    3103           13 :             Tank.UseOutletHeight = Tank.Height;
    3104              :         }
    3105           15 :         if (Tank.UseOutletHeight == DataSizing::AutoSize) {
    3106            0 :             Tank.UseOutletHeightWasAutoSized = true;
    3107              :         }
    3108           15 :         if ((!Tank.HeightWasAutoSized) && (Tank.UseOutletHeight > Tank.Height)) {
    3109            0 :             ShowSevereError(state,
    3110            0 :                             format("{} = {}: Use outlet is located higher than overall tank height.",
    3111            0 :                                    state.dataIPShortCut->cCurrentModuleObject,
    3112            0 :                                    state.dataIPShortCut->cAlphaArgs(1)));
    3113            0 :             ShowContinueError(state, format("{} = {:.4R}", state.dataIPShortCut->cNumericFieldNames(2), state.dataIPShortCut->rNumericArgs(2)));
    3114            0 :             ShowContinueError(state, format("{} = {:.4R}", state.dataIPShortCut->cNumericFieldNames(25), state.dataIPShortCut->rNumericArgs(25)));
    3115            0 :             ErrorsFound = true;
    3116              :         }
    3117              : 
    3118           15 :         if (NumNums > 25) {
    3119           15 :             if ((state.dataIPShortCut->rNumericArgs(26) > 1) || (state.dataIPShortCut->rNumericArgs(26) <= 0)) {
    3120            0 :                 ShowSevereError(state,
    3121            0 :                                 format("{} = {}:  Source Side Effectiveness is out of bounds (>0 to 1)",
    3122            0 :                                        state.dataIPShortCut->cCurrentModuleObject,
    3123            0 :                                        state.dataIPShortCut->cAlphaArgs(1)));
    3124            0 :                 ErrorsFound = true;
    3125              :             }
    3126           15 :             Tank.SourceEffectiveness = state.dataIPShortCut->rNumericArgs(26);
    3127              :         } else {
    3128            0 :             Tank.SourceEffectiveness = 1.0;
    3129              :         }
    3130              : 
    3131           15 :         if ((NumNums > 26) && (state.dataIPShortCut->rNumericArgs(27) != Constant::AutoCalculate)) {
    3132            5 :             Tank.SourceInletHeight = state.dataIPShortCut->rNumericArgs(27);
    3133              :         } else {
    3134              :             // Defaults to top of tank
    3135           10 :             Tank.SourceInletHeight = Tank.Height;
    3136              :         }
    3137           15 :         if (Tank.SourceInletHeight == DataSizing::AutoSize) {
    3138            0 :             Tank.SourceInletHeightWasAutoSized = true;
    3139              :         }
    3140           15 :         if ((!Tank.HeightWasAutoSized) && (Tank.SourceInletHeight > Tank.Height)) {
    3141            0 :             ShowSevereError(state,
    3142            0 :                             format("{} = {}: Source inlet is located higher than overall tank height.",
    3143            0 :                                    state.dataIPShortCut->cCurrentModuleObject,
    3144            0 :                                    state.dataIPShortCut->cAlphaArgs(1)));
    3145            0 :             ShowContinueError(state, format("{} = {:.4R}", state.dataIPShortCut->cNumericFieldNames(2), state.dataIPShortCut->rNumericArgs(2)));
    3146            0 :             ShowContinueError(state, format("{} = {:.4R}", state.dataIPShortCut->cNumericFieldNames(27), state.dataIPShortCut->rNumericArgs(27)));
    3147            0 :             ErrorsFound = true;
    3148              :         }
    3149              : 
    3150           15 :         if ((NumNums > 27) && (state.dataIPShortCut->rNumericArgs(28) != Constant::AutoCalculate)) {
    3151           15 :             Tank.SourceOutletHeight = state.dataIPShortCut->rNumericArgs(28);
    3152              :         } else {
    3153              :             // Defaults to bottom of tank
    3154            0 :             Tank.SourceOutletHeight = 0.0;
    3155              :         }
    3156           15 :         if ((!Tank.HeightWasAutoSized) && (Tank.SourceOutletHeight > Tank.Height)) {
    3157            0 :             ShowSevereError(state,
    3158            0 :                             format("{} = {}: Source outlet is located higher than overall tank height.",
    3159            0 :                                    state.dataIPShortCut->cCurrentModuleObject,
    3160            0 :                                    state.dataIPShortCut->cAlphaArgs(1)));
    3161            0 :             ShowContinueError(state, format("{} = {:.4R}", state.dataIPShortCut->cNumericFieldNames(2), state.dataIPShortCut->rNumericArgs(2)));
    3162            0 :             ShowContinueError(state, format("{} = {:.4R}", state.dataIPShortCut->cNumericFieldNames(28), state.dataIPShortCut->rNumericArgs(28)));
    3163            0 :             ErrorsFound = true;
    3164              :         }
    3165              : 
    3166              :         // If no plant nodes are connected, simulate in stand-alone mode.
    3167           35 :         if (state.dataIPShortCut->cAlphaArgs(16).empty() && state.dataIPShortCut->cAlphaArgs(17).empty() &&
    3168           35 :             state.dataIPShortCut->cAlphaArgs(18).empty() && state.dataIPShortCut->cAlphaArgs(19).empty())
    3169            9 :             Tank.StandAlone = true;
    3170              : 
    3171           15 :         if (!state.dataIPShortCut->lNumericFieldBlanks(29)) {
    3172            8 :             Tank.UseDesignVolFlowRate = state.dataIPShortCut->rNumericArgs(29);
    3173            8 :             if (Tank.UseDesignVolFlowRate == DataSizing::AutoSize) {
    3174            7 :                 Tank.UseDesignVolFlowRateWasAutoSized = true;
    3175              :             }
    3176              :         } else {
    3177            7 :             Tank.UseDesignVolFlowRate = 0.0;
    3178              :         }
    3179              : 
    3180           15 :         Tank.UseSidePlantLoc.loopSideNum = DataPlant::LoopSideLocation::Invalid;
    3181              : 
    3182           15 :         if (!state.dataIPShortCut->lNumericFieldBlanks(30)) {
    3183            8 :             Tank.SourceDesignVolFlowRate = state.dataIPShortCut->rNumericArgs(30);
    3184            8 :             if (Tank.SourceDesignVolFlowRate == DataSizing::AutoSize) {
    3185            7 :                 Tank.SourceDesignVolFlowRateWasAutoSized = true;
    3186              :             }
    3187              :         } else {
    3188            7 :             Tank.SourceDesignVolFlowRate = 0.0;
    3189              :         }
    3190              : 
    3191           15 :         if (NumNums > 30) {
    3192           15 :             Tank.SizingRecoveryTime = state.dataIPShortCut->rNumericArgs(31);
    3193              :         } else {
    3194            0 :             Tank.SizingRecoveryTime = 1.5;
    3195              :         }
    3196              : 
    3197           15 :         Tank.SrcSidePlantLoc.loopSideNum = DataPlant::LoopSideLocation::Invalid;
    3198              : 
    3199           15 :         if ((!state.dataIPShortCut->cAlphaArgs(16).empty()) || (!state.dataIPShortCut->cAlphaArgs(17).empty())) {
    3200            5 :             Tank.UseInletNode = NodeInputManager::GetOnlySingleNode(state,
    3201            5 :                                                                     state.dataIPShortCut->cAlphaArgs(16),
    3202              :                                                                     ErrorsFound,
    3203              :                                                                     DataLoopNode::ConnectionObjectType::WaterHeaterStratified,
    3204            5 :                                                                     state.dataIPShortCut->cAlphaArgs(1),
    3205              :                                                                     DataLoopNode::NodeFluidType::Water,
    3206              :                                                                     DataLoopNode::ConnectionType::Inlet,
    3207              :                                                                     NodeInputManager::CompFluidStream::Primary,
    3208              :                                                                     DataLoopNode::ObjectIsNotParent);
    3209            5 :             Tank.InletNodeName1 = state.dataIPShortCut->cAlphaArgs(16);
    3210            5 :             Tank.UseOutletNode = NodeInputManager::GetOnlySingleNode(state,
    3211            5 :                                                                      state.dataIPShortCut->cAlphaArgs(17),
    3212              :                                                                      ErrorsFound,
    3213              :                                                                      DataLoopNode::ConnectionObjectType::WaterHeaterStratified,
    3214            5 :                                                                      state.dataIPShortCut->cAlphaArgs(1),
    3215              :                                                                      DataLoopNode::NodeFluidType::Water,
    3216              :                                                                      DataLoopNode::ConnectionType::Outlet,
    3217              :                                                                      NodeInputManager::CompFluidStream::Primary,
    3218              :                                                                      DataLoopNode::ObjectIsNotParent);
    3219            5 :             Tank.OutletNodeName1 = state.dataIPShortCut->cAlphaArgs(17);
    3220              : 
    3221            5 :             if (state.dataIPShortCut->rNumericArgs(22) > 0) {
    3222            4 :                 ShowWarningError(state,
    3223            6 :                                  format("{} = {}:  Use side nodes are specified; Peak Volumetric Use Flow Rate will not be used",
    3224            2 :                                         state.dataIPShortCut->cCurrentModuleObject,
    3225            2 :                                         state.dataIPShortCut->cAlphaArgs(1)));
    3226              :             }
    3227              : 
    3228            5 :             if (Tank.flowRateSched != nullptr) {
    3229            0 :                 ShowWarningError(state,
    3230            0 :                                  format("{} = {}:  Use side nodes are specified; Use Flow Rate Fraction Schedule will not be used",
    3231            0 :                                         state.dataIPShortCut->cCurrentModuleObject,
    3232            0 :                                         state.dataIPShortCut->cAlphaArgs(1)));
    3233              :             }
    3234              : 
    3235            5 :             if (Tank.useInletTempSched != nullptr) {
    3236            4 :                 ShowWarningError(state,
    3237            6 :                                  format("{} = {}:  Use side nodes are specified; Cold Water Supply Temperature Schedule will not be used",
    3238            2 :                                         state.dataIPShortCut->cCurrentModuleObject,
    3239            2 :                                         state.dataIPShortCut->cAlphaArgs(1)));
    3240              :             }
    3241              :         }
    3242              : 
    3243           15 :         if ((!state.dataIPShortCut->cAlphaArgs(18).empty()) || (!state.dataIPShortCut->cAlphaArgs(19).empty())) {
    3244            2 :             Tank.SourceInletNode = NodeInputManager::GetOnlySingleNode(state,
    3245            2 :                                                                        state.dataIPShortCut->cAlphaArgs(18),
    3246              :                                                                        ErrorsFound,
    3247              :                                                                        DataLoopNode::ConnectionObjectType::WaterHeaterStratified,
    3248            2 :                                                                        state.dataIPShortCut->cAlphaArgs(1),
    3249              :                                                                        DataLoopNode::NodeFluidType::Water,
    3250              :                                                                        DataLoopNode::ConnectionType::Inlet,
    3251              :                                                                        NodeInputManager::CompFluidStream::Secondary,
    3252              :                                                                        DataLoopNode::ObjectIsNotParent);
    3253            2 :             Tank.InletNodeName2 = state.dataIPShortCut->cAlphaArgs(18);
    3254            2 :             Tank.SourceOutletNode = NodeInputManager::GetOnlySingleNode(state,
    3255            2 :                                                                         state.dataIPShortCut->cAlphaArgs(19),
    3256              :                                                                         ErrorsFound,
    3257              :                                                                         DataLoopNode::ConnectionObjectType::WaterHeaterStratified,
    3258            2 :                                                                         state.dataIPShortCut->cAlphaArgs(1),
    3259              :                                                                         DataLoopNode::NodeFluidType::Water,
    3260              :                                                                         DataLoopNode::ConnectionType::Outlet,
    3261              :                                                                         NodeInputManager::CompFluidStream::Secondary,
    3262              :                                                                         DataLoopNode::ObjectIsNotParent);
    3263            2 :             Tank.OutletNodeName2 = state.dataIPShortCut->cAlphaArgs(19);
    3264              :         }
    3265              : 
    3266              :         // Validate inlet mode
    3267           15 :         Tank.InletMode =
    3268           15 :             static_cast<InletPositionMode>(getEnumValue(InletPositionModeNamesUC, Util::makeUPPER(state.dataIPShortCut->cAlphaArgs(20))));
    3269              : 
    3270           15 :         Tank.Nodes = state.dataIPShortCut->rNumericArgs(32);
    3271           15 :         int specifiedNodes = 0;
    3272           15 :         Tank.AdditionalCond = state.dataIPShortCut->rNumericArgs(33);
    3273              : 
    3274           15 :         Tank.AdditionalLossCoeff.allocate(Tank.Nodes);
    3275           15 :         Tank.AdditionalLossCoeff = 0.0;
    3276          103 :         for (int NodeNum = 1; NodeNum <= 12; ++NodeNum) {
    3277           99 :             int index = 33 + NodeNum;
    3278           99 :             if (NumNums >= index) {
    3279           88 :                 if (NodeNum <= Tank.Nodes) {
    3280           68 :                     ++specifiedNodes;
    3281           68 :                     Tank.AdditionalLossCoeff(NodeNum) = state.dataIPShortCut->rNumericArgs(index);
    3282           20 :                 } else if (!state.dataIPShortCut->lNumericFieldBlanks(index) && (state.dataIPShortCut->rNumericArgs(index) != 0)) {
    3283              :                     // If either blank, or zero (default), then do not warn
    3284            1 :                     ++specifiedNodes;
    3285              :                 }
    3286              :             } else {
    3287           11 :                 break;
    3288              :             }
    3289              :         }
    3290              : 
    3291           15 :         if (specifiedNodes > Tank.Nodes) {
    3292            2 :             ShowWarningError(
    3293              :                 state,
    3294            3 :                 format("{} = {}:  More Additional Loss Coefficients were entered than the number of nodes; extra coefficients will not be used",
    3295            1 :                        state.dataIPShortCut->cCurrentModuleObject,
    3296            1 :                        state.dataIPShortCut->cAlphaArgs(1)));
    3297              :         }
    3298              : 
    3299           15 :         Tank.SetupStratifiedNodes(state);
    3300              : 
    3301           15 :         if (!state.dataIPShortCut->lAlphaFieldBlanks(21)) {
    3302            4 :             Tank.SourceSideControlMode =
    3303            4 :                 static_cast<SourceSideControl>(getEnumValue(SourceSideControlNamesUC, Util::makeUPPER(state.dataIPShortCut->cAlphaArgs(21))));
    3304            4 :             if (Tank.SourceSideControlMode == SourceSideControl::Invalid) {
    3305            0 :                 ShowSevereError(state,
    3306            0 :                                 format("{} = {}:  Invalid Control Mode entered={}",
    3307            0 :                                        state.dataIPShortCut->cCurrentModuleObject,
    3308            0 :                                        state.dataIPShortCut->cAlphaArgs(1),
    3309            0 :                                        state.dataIPShortCut->cAlphaArgs(21)));
    3310            0 :                 ErrorsFound = true;
    3311              :             }
    3312              :         } else {
    3313           11 :             Tank.SourceSideControlMode = SourceSideControl::IndirectHeatPrimarySetpoint;
    3314              :         }
    3315              : 
    3316           15 :         if (state.dataIPShortCut->lAlphaFieldBlanks(22)) {
    3317            0 :         } else if ((Tank.sourceSideAltSetpointSched = Sched::GetSchedule(state, state.dataIPShortCut->cAlphaArgs(22))) == nullptr) {
    3318            0 :             ShowSevereItemNotFound(state, eoh, state.dataIPShortCut->cAlphaFieldNames(22), state.dataIPShortCut->cAlphaArgs(22));
    3319            0 :             ErrorsFound = true;
    3320              :         }
    3321              :     }
    3322              : 
    3323           14 :     return ErrorsFound;
    3324              : }
    3325              : 
    3326            0 : bool getWaterTankMixedInput(EnergyPlusData &state)
    3327              : {
    3328              :     static constexpr std::string_view routineName = "getWaterTankMixedInput";
    3329            0 :     bool ErrorsFound = false;
    3330              : 
    3331            0 :     state.dataIPShortCut->cCurrentModuleObject = cMixedCWTankModuleObj; // 'ThermalStorage:ChilledWater:Mixed'
    3332            0 :     for (int WaterThermalTankNum = state.dataWaterThermalTanks->numWaterHeaterMixed + state.dataWaterThermalTanks->numWaterHeaterStratified + 1;
    3333            0 :          WaterThermalTankNum <= state.dataWaterThermalTanks->numWaterHeaterMixed + state.dataWaterThermalTanks->numWaterHeaterStratified +
    3334            0 :                                     state.dataWaterThermalTanks->numChilledWaterMixed;
    3335              :          ++WaterThermalTankNum) {
    3336              :         int NumAlphas;
    3337              :         int NumNums;
    3338              :         int IOStat;
    3339            0 :         state.dataInputProcessing->inputProcessor->getObjectItem(
    3340              :             state,
    3341            0 :             state.dataIPShortCut->cCurrentModuleObject,
    3342            0 :             WaterThermalTankNum - (state.dataWaterThermalTanks->numWaterHeaterMixed + state.dataWaterThermalTanks->numWaterHeaterStratified),
    3343            0 :             state.dataIPShortCut->cAlphaArgs,
    3344              :             NumAlphas,
    3345            0 :             state.dataIPShortCut->rNumericArgs,
    3346              :             NumNums,
    3347              :             IOStat,
    3348            0 :             state.dataIPShortCut->lNumericFieldBlanks,
    3349            0 :             state.dataIPShortCut->lAlphaFieldBlanks,
    3350            0 :             state.dataIPShortCut->cAlphaFieldNames,
    3351            0 :             state.dataIPShortCut->cNumericFieldNames);
    3352              : 
    3353            0 :         ErrorObjectHeader eoh{routineName, state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)};
    3354              : 
    3355            0 :         GlobalNames::VerifyUniqueInterObjectName(state,
    3356            0 :                                                  state.dataWaterThermalTanks->UniqueWaterThermalTankNames,
    3357            0 :                                                  state.dataIPShortCut->cAlphaArgs(1),
    3358            0 :                                                  state.dataIPShortCut->cCurrentModuleObject,
    3359            0 :                                                  state.dataIPShortCut->cAlphaFieldNames(1),
    3360              :                                                  ErrorsFound);
    3361              : 
    3362            0 :         auto &Tank = state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum);
    3363              : 
    3364            0 :         Tank.Name = state.dataIPShortCut->cAlphaArgs(1);
    3365            0 :         Tank.Type = state.dataIPShortCut->cCurrentModuleObject;
    3366            0 :         Tank.WaterThermalTankType = DataPlant::PlantEquipmentType::ChilledWaterTankMixed;
    3367              : 
    3368            0 :         if ((Tank.water = Fluid::GetWater(state)) == nullptr) {
    3369            0 :             ShowSevereError(state, "Fluid Properties for WATER not found");
    3370            0 :             ErrorsFound = true;
    3371              :         }
    3372              : 
    3373            0 :         Tank.IsChilledWaterTank = true;
    3374            0 :         Tank.EndUseSubcategoryName = "Chilled Water Storage";
    3375              : 
    3376            0 :         Tank.Volume = state.dataIPShortCut->rNumericArgs(1);
    3377            0 :         if (Tank.Volume == DataSizing::AutoSize) {
    3378            0 :             Tank.VolumeWasAutoSized = true;
    3379              :         }
    3380              : 
    3381            0 :         if (state.dataIPShortCut->rNumericArgs(1) == 0.0) {
    3382              :             // Set volume to a really small number to continue simulation
    3383            0 :             Tank.Volume = 0.000001; // = 1 cm3
    3384              :         }
    3385              : 
    3386            0 :         if (state.dataIPShortCut->lAlphaFieldBlanks(2)) {
    3387            0 :             ShowSevereEmptyField(state, eoh, state.dataIPShortCut->cAlphaFieldNames(2));
    3388            0 :         } else if ((Tank.setptTempSched = Sched::GetSchedule(state, state.dataIPShortCut->cAlphaArgs(2))) == nullptr) {
    3389            0 :             ShowSevereItemNotFound(state, eoh, state.dataIPShortCut->cAlphaFieldNames(2), state.dataIPShortCut->cAlphaArgs(2));
    3390            0 :             ErrorsFound = true;
    3391              :         }
    3392              : 
    3393            0 :         if (state.dataIPShortCut->rNumericArgs(2) > 0.0001) {
    3394            0 :             Tank.DeadBandDeltaTemp = state.dataIPShortCut->rNumericArgs(2);
    3395              :         } else {
    3396              :             // Default to very small number (however it can't be TINY or it will break the algorithm)
    3397            0 :             Tank.DeadBandDeltaTemp = 0.5;
    3398              :         }
    3399              : 
    3400            0 :         if (state.dataIPShortCut->rNumericArgs(3) > 0.0) {
    3401            0 :             Tank.TankTempLimit = state.dataIPShortCut->rNumericArgs(3);
    3402              :         } else {
    3403              :             // default to just above freezing
    3404            0 :             Tank.TankTempLimit = 1.0;
    3405              :         }
    3406              : 
    3407            0 :         Tank.MaxCapacity = state.dataIPShortCut->rNumericArgs(4);
    3408            0 :         if (Tank.MaxCapacity == DataSizing::AutoSize) {
    3409            0 :             Tank.MaxCapacityWasAutoSized = true;
    3410              :         }
    3411              : 
    3412            0 :         Tank.MinCapacity = 0.0;
    3413            0 :         Tank.ControlType = HeaterControlMode::Cycle;
    3414              : 
    3415            0 :         Tank.MassFlowRateMin = 0.0;
    3416            0 :         Tank.IgnitionDelay = 0.0;
    3417            0 :         Tank.FuelType = Constant::eFuel::Electricity;
    3418            0 :         Tank.Efficiency = 1.0;
    3419            0 :         Tank.PLFCurve = 0;
    3420            0 :         Tank.OffCycParaLoad = 0.0;
    3421            0 :         Tank.OffCycParaFuelType = Constant::eFuel::Electricity;
    3422            0 :         Tank.OffCycParaFracToTank = 0.0;
    3423            0 :         Tank.OnCycParaLoad = 0.0;
    3424            0 :         Tank.OnCycParaFuelType = Constant::eFuel::Electricity;
    3425            0 :         Tank.OnCycParaFracToTank = 0.0;
    3426              : 
    3427            0 :         Tank.AmbientTempIndicator =
    3428            0 :             static_cast<WTTAmbientTemp>(getEnumValue(TankAmbientTempNamesUC, Util::makeUPPER(state.dataIPShortCut->cAlphaArgs(3))));
    3429            0 :         switch (Tank.AmbientTempIndicator) {
    3430              : 
    3431            0 :         case WTTAmbientTemp::Schedule: {
    3432            0 :             if (state.dataIPShortCut->lAlphaFieldBlanks(4)) {
    3433            0 :                 ShowSevereEmptyField(state, eoh, state.dataIPShortCut->cAlphaFieldNames(4));
    3434            0 :             } else if ((Tank.ambientTempSched = Sched::GetSchedule(state, state.dataIPShortCut->cAlphaArgs(4))) == nullptr) {
    3435            0 :                 ShowSevereItemNotFound(state, eoh, state.dataIPShortCut->cAlphaFieldNames(4), state.dataIPShortCut->cAlphaArgs(4));
    3436            0 :                 ErrorsFound = true;
    3437              :             }
    3438            0 :         } break;
    3439              : 
    3440            0 :         case WTTAmbientTemp::TempZone: {
    3441            0 :             Tank.AmbientTempZone = Util::FindItemInList(state.dataIPShortCut->cAlphaArgs(5), state.dataHeatBal->Zone);
    3442            0 :             if (Tank.AmbientTempZone == 0) {
    3443            0 :                 ShowSevereError(state, format("Invalid, {} = {}", state.dataIPShortCut->cAlphaFieldNames(5), state.dataIPShortCut->cAlphaArgs(5)));
    3444            0 :                 ShowContinueError(state,
    3445            0 :                                   format("Entered in {} = {}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
    3446            0 :                 ShowContinueError(state, "Zone was not found.");
    3447            0 :                 ErrorsFound = true;
    3448              :             }
    3449              : 
    3450            0 :             break;
    3451              :         }
    3452            0 :         case WTTAmbientTemp::OutsideAir: {
    3453            0 :             Tank.AmbientTempOutsideAirNode = NodeInputManager::GetOnlySingleNode(state,
    3454            0 :                                                                                  state.dataIPShortCut->cAlphaArgs(6),
    3455              :                                                                                  ErrorsFound,
    3456              :                                                                                  DataLoopNode::ConnectionObjectType::ThermalStorageChilledWaterMixed,
    3457            0 :                                                                                  state.dataIPShortCut->cAlphaArgs(1),
    3458              :                                                                                  DataLoopNode::NodeFluidType::Air,
    3459              :                                                                                  DataLoopNode::ConnectionType::OutsideAirReference,
    3460              :                                                                                  NodeInputManager::CompFluidStream::Primary,
    3461              :                                                                                  DataLoopNode::ObjectIsNotParent);
    3462            0 :             if (!state.dataIPShortCut->lAlphaFieldBlanks(6)) {
    3463            0 :                 if (!OutAirNodeManager::CheckOutAirNodeNumber(state, Tank.AmbientTempOutsideAirNode)) {
    3464            0 :                     ShowSevereError(state,
    3465            0 :                                     format("Invalid, {} = {}", state.dataIPShortCut->cAlphaFieldNames(6), state.dataIPShortCut->cAlphaArgs(6)));
    3466            0 :                     ShowContinueError(state,
    3467            0 :                                       format("Entered in {} = {}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
    3468            0 :                     ShowContinueError(state, "Outdoor Air Node not on OutdoorAir:NodeList or OutdoorAir:Node");
    3469            0 :                     ErrorsFound = true;
    3470              :                 }
    3471              :             } else {
    3472            0 :                 ShowSevereError(state, format("{} = {}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
    3473            0 :                 ShowContinueError(state, "An Ambient Outdoor Air Node name must be used when the Ambient Temperature Indicator is Outdoors.");
    3474            0 :                 ErrorsFound = true;
    3475              :             }
    3476              : 
    3477            0 :             break;
    3478              :         }
    3479            0 :         default: {
    3480            0 :             ShowSevereError(state,
    3481            0 :                             format("{} = {}:  Invalid Ambient Temperature Indicator entered={}",
    3482            0 :                                    state.dataIPShortCut->cCurrentModuleObject,
    3483            0 :                                    state.dataIPShortCut->cAlphaArgs(1),
    3484            0 :                                    state.dataIPShortCut->cAlphaArgs(3)));
    3485            0 :             ShowContinueError(state, " Valid entries are Schedule, Zone, and Outdoors.");
    3486            0 :             ErrorsFound = true;
    3487            0 :             break;
    3488              :         }
    3489              :         }
    3490              : 
    3491            0 :         Tank.OffCycLossCoeff = state.dataIPShortCut->rNumericArgs(5);
    3492            0 :         Tank.OffCycLossFracToZone = 1.0;
    3493              : 
    3494            0 :         Tank.OnCycLossCoeff = state.dataIPShortCut->rNumericArgs(5);
    3495            0 :         Tank.OnCycLossFracToZone = 1.0;
    3496              : 
    3497            0 :         Tank.MassFlowRateMax = 0.0;
    3498            0 :         Tank.flowRateSched = nullptr;
    3499            0 :         Tank.useInletTempSched = nullptr;
    3500              : 
    3501              :         // default to always on
    3502            0 :         Tank.sourceSideAvailSched = Sched::GetScheduleAlwaysOn(state);
    3503            0 :         Tank.useSideAvailSched = Sched::GetScheduleAlwaysOn(state);
    3504              : 
    3505            0 :         if ((state.dataIPShortCut->rNumericArgs(6) > 1) || (state.dataIPShortCut->rNumericArgs(6) < 0)) {
    3506            0 :             ShowSevereError(state,
    3507            0 :                             format("{} = {}:  Use Side Effectiveness is out of bounds (0 to 1)",
    3508            0 :                                    state.dataIPShortCut->cCurrentModuleObject,
    3509            0 :                                    state.dataIPShortCut->cAlphaArgs(1)));
    3510            0 :             ErrorsFound = true;
    3511              :         }
    3512            0 :         Tank.UseEffectiveness = state.dataIPShortCut->rNumericArgs(6);
    3513              : 
    3514            0 :         if ((state.dataIPShortCut->rNumericArgs(8) > 1) || (state.dataIPShortCut->rNumericArgs(8) <= 0)) {
    3515            0 :             ShowSevereError(state,
    3516            0 :                             format("{} = {}:  Source Side Effectiveness is out of bounds (>0 to 1)",
    3517            0 :                                    state.dataIPShortCut->cCurrentModuleObject,
    3518            0 :                                    state.dataIPShortCut->cAlphaArgs(1)));
    3519            0 :             ErrorsFound = true;
    3520              :         }
    3521            0 :         Tank.SourceEffectiveness = state.dataIPShortCut->rNumericArgs(8);
    3522              : 
    3523            0 :         if (state.dataIPShortCut->lNumericFieldBlanks(7)) {
    3524            0 :             Tank.UseDesignVolFlowRate = 0.0;
    3525              :         } else {
    3526            0 :             Tank.UseDesignVolFlowRate = state.dataIPShortCut->rNumericArgs(7);
    3527            0 :             if (Tank.UseDesignVolFlowRate) {
    3528            0 :                 Tank.UseDesignVolFlowRateWasAutoSized = true;
    3529              :             }
    3530              :         }
    3531              : 
    3532            0 :         Tank.UseSidePlantLoc.loopSideNum = DataPlant::LoopSideLocation::Invalid;
    3533              : 
    3534            0 :         if (state.dataIPShortCut->lAlphaFieldBlanks(9)) {
    3535            0 :             Tank.useSideAvailSched = Sched::GetScheduleAlwaysOn(state);
    3536            0 :         } else if ((Tank.useSideAvailSched = Sched::GetSchedule(state, state.dataIPShortCut->cAlphaArgs(9))) == nullptr) {
    3537            0 :             ShowSevereItemNotFound(state, eoh, state.dataIPShortCut->cAlphaFieldNames(9), state.dataIPShortCut->cAlphaArgs(9));
    3538            0 :             ErrorsFound = true;
    3539              :         }
    3540              : 
    3541            0 :         Tank.SrcSidePlantLoc.loopSideNum = DataPlant::LoopSideLocation::Invalid;
    3542              : 
    3543            0 :         if (state.dataIPShortCut->lNumericFieldBlanks(9)) {
    3544            0 :             Tank.SourceDesignVolFlowRate = 0.0;
    3545              :         } else {
    3546            0 :             Tank.SourceDesignVolFlowRate = state.dataIPShortCut->rNumericArgs(9);
    3547            0 :             if (Tank.SourceDesignVolFlowRate == DataSizing::AutoSize) {
    3548            0 :                 Tank.SourceDesignVolFlowRateWasAutoSized = true;
    3549              :             }
    3550              :         }
    3551              : 
    3552            0 :         if (state.dataIPShortCut->lAlphaFieldBlanks(12)) {
    3553            0 :             Tank.sourceSideAvailSched = Sched::GetScheduleAlwaysOn(state);
    3554            0 :         } else if ((Tank.sourceSideAvailSched = Sched::GetSchedule(state, state.dataIPShortCut->cAlphaArgs(12))) == nullptr) {
    3555            0 :             ShowSevereItemNotFound(state, eoh, state.dataIPShortCut->cAlphaFieldNames(12), state.dataIPShortCut->cAlphaArgs(12));
    3556            0 :             ErrorsFound = true;
    3557              :         }
    3558              : 
    3559            0 :         if (state.dataIPShortCut->lNumericFieldBlanks(10)) {
    3560            0 :             Tank.SizingRecoveryTime = 4.0;
    3561              :         } else {
    3562            0 :             Tank.SizingRecoveryTime = state.dataIPShortCut->rNumericArgs(10);
    3563              :         }
    3564              : 
    3565            0 :         if ((!state.dataIPShortCut->lAlphaFieldBlanks(7)) || (!state.dataIPShortCut->lAlphaFieldBlanks(8))) {
    3566            0 :             Tank.UseInletNode = NodeInputManager::GetOnlySingleNode(state,
    3567            0 :                                                                     state.dataIPShortCut->cAlphaArgs(7),
    3568              :                                                                     ErrorsFound,
    3569              :                                                                     DataLoopNode::ConnectionObjectType::ThermalStorageChilledWaterMixed,
    3570            0 :                                                                     state.dataIPShortCut->cAlphaArgs(1),
    3571              :                                                                     DataLoopNode::NodeFluidType::Water,
    3572              :                                                                     DataLoopNode::ConnectionType::Inlet,
    3573              :                                                                     NodeInputManager::CompFluidStream::Primary,
    3574              :                                                                     DataLoopNode::ObjectIsNotParent);
    3575            0 :             Tank.InletNodeName1 = state.dataIPShortCut->cAlphaArgs(7);
    3576            0 :             Tank.UseOutletNode = NodeInputManager::GetOnlySingleNode(state,
    3577            0 :                                                                      state.dataIPShortCut->cAlphaArgs(8),
    3578              :                                                                      ErrorsFound,
    3579              :                                                                      DataLoopNode::ConnectionObjectType::ThermalStorageChilledWaterMixed,
    3580            0 :                                                                      state.dataIPShortCut->cAlphaArgs(1),
    3581              :                                                                      DataLoopNode::NodeFluidType::Water,
    3582              :                                                                      DataLoopNode::ConnectionType::Outlet,
    3583              :                                                                      NodeInputManager::CompFluidStream::Primary,
    3584              :                                                                      DataLoopNode::ObjectIsNotParent);
    3585            0 :             Tank.OutletNodeName1 = state.dataIPShortCut->cAlphaArgs(8);
    3586              :         }
    3587              : 
    3588            0 :         if ((!state.dataIPShortCut->lAlphaFieldBlanks(10)) || (!state.dataIPShortCut->lAlphaFieldBlanks(11))) {
    3589            0 :             Tank.SourceInletNode = NodeInputManager::GetOnlySingleNode(state,
    3590            0 :                                                                        state.dataIPShortCut->cAlphaArgs(10),
    3591              :                                                                        ErrorsFound,
    3592              :                                                                        DataLoopNode::ConnectionObjectType::ThermalStorageChilledWaterMixed,
    3593            0 :                                                                        state.dataIPShortCut->cAlphaArgs(1),
    3594              :                                                                        DataLoopNode::NodeFluidType::Water,
    3595              :                                                                        DataLoopNode::ConnectionType::Inlet,
    3596              :                                                                        NodeInputManager::CompFluidStream::Secondary,
    3597              :                                                                        DataLoopNode::ObjectIsNotParent);
    3598            0 :             Tank.InletNodeName2 = state.dataIPShortCut->cAlphaArgs(10);
    3599            0 :             Tank.SourceOutletNode = NodeInputManager::GetOnlySingleNode(state,
    3600            0 :                                                                         state.dataIPShortCut->cAlphaArgs(11),
    3601              :                                                                         ErrorsFound,
    3602              :                                                                         DataLoopNode::ConnectionObjectType::ThermalStorageChilledWaterMixed,
    3603            0 :                                                                         state.dataIPShortCut->cAlphaArgs(1),
    3604              :                                                                         DataLoopNode::NodeFluidType::Water,
    3605              :                                                                         DataLoopNode::ConnectionType::Outlet,
    3606              :                                                                         NodeInputManager::CompFluidStream::Secondary,
    3607              :                                                                         DataLoopNode::ObjectIsNotParent);
    3608            0 :             Tank.OutletNodeName2 = state.dataIPShortCut->cAlphaArgs(11);
    3609              :         }
    3610              : 
    3611            0 :         if (Tank.UseSidePlantLoc.loopSideNum == DataPlant::LoopSideLocation::Demand && Tank.SourceInletNode != 0) {
    3612            0 :             PlantUtilities::RegisterPlantCompDesignFlow(state, Tank.SourceInletNode, Tank.SourceDesignVolFlowRate);
    3613              :         }
    3614              : 
    3615              :     } // WaterThermalTankNum
    3616              : 
    3617            0 :     return ErrorsFound;
    3618              : }
    3619              : 
    3620            1 : bool getWaterTankStratifiedInput(EnergyPlusData &state)
    3621              : {
    3622            1 :     bool ErrorsFound = false;
    3623              :     static constexpr std::string_view routineName = "getWaterTankStratifiedInput";
    3624              : 
    3625            1 :     state.dataIPShortCut->cCurrentModuleObject = cStratifiedCWTankModuleObj; // 'ThermalStorage:ChilledWater:Stratified'
    3626              : 
    3627            2 :     for (int WaterThermalTankNum = state.dataWaterThermalTanks->numWaterHeaterMixed + state.dataWaterThermalTanks->numWaterHeaterStratified +
    3628            1 :                                    state.dataWaterThermalTanks->numChilledWaterMixed + 1;
    3629            2 :          WaterThermalTankNum <= state.dataWaterThermalTanks->numWaterHeaterMixed + state.dataWaterThermalTanks->numWaterHeaterStratified +
    3630            2 :                                     state.dataWaterThermalTanks->numChilledWaterMixed + state.dataWaterThermalTanks->numChilledWaterStratified;
    3631              :          ++WaterThermalTankNum) {
    3632              :         int NumNums;
    3633              :         int NumAlphas;
    3634              :         int IOStat;
    3635            2 :         state.dataInputProcessing->inputProcessor->getObjectItem(state,
    3636            1 :                                                                  state.dataIPShortCut->cCurrentModuleObject,
    3637            1 :                                                                  WaterThermalTankNum - (state.dataWaterThermalTanks->numWaterHeaterMixed +
    3638            1 :                                                                                         state.dataWaterThermalTanks->numWaterHeaterStratified +
    3639            1 :                                                                                         state.dataWaterThermalTanks->numChilledWaterMixed),
    3640            1 :                                                                  state.dataIPShortCut->cAlphaArgs,
    3641              :                                                                  NumAlphas,
    3642            1 :                                                                  state.dataIPShortCut->rNumericArgs,
    3643              :                                                                  NumNums,
    3644              :                                                                  IOStat,
    3645            1 :                                                                  state.dataIPShortCut->lNumericFieldBlanks,
    3646            1 :                                                                  state.dataIPShortCut->lAlphaFieldBlanks,
    3647            1 :                                                                  state.dataIPShortCut->cAlphaFieldNames,
    3648            1 :                                                                  state.dataIPShortCut->cNumericFieldNames);
    3649              : 
    3650            1 :         ErrorObjectHeader eoh{routineName, state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)};
    3651              : 
    3652            1 :         GlobalNames::VerifyUniqueInterObjectName(state,
    3653            1 :                                                  state.dataWaterThermalTanks->UniqueWaterThermalTankNames,
    3654            1 :                                                  state.dataIPShortCut->cAlphaArgs(1),
    3655            1 :                                                  state.dataIPShortCut->cCurrentModuleObject,
    3656            1 :                                                  state.dataIPShortCut->cAlphaFieldNames(1),
    3657              :                                                  ErrorsFound);
    3658              : 
    3659            1 :         auto &Tank = state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum);
    3660              : 
    3661            1 :         Tank.Name = state.dataIPShortCut->cAlphaArgs(1);
    3662            1 :         Tank.Type = state.dataIPShortCut->cCurrentModuleObject;
    3663            1 :         Tank.WaterThermalTankType = DataPlant::PlantEquipmentType::ChilledWaterTankStratified;
    3664              : 
    3665            1 :         if ((Tank.water = Fluid::GetWater(state)) == nullptr) {
    3666            0 :             ShowSevereError(state, "Fluid properties for WATER not found");
    3667            0 :             ErrorsFound = true;
    3668              :         }
    3669              : 
    3670            1 :         Tank.IsChilledWaterTank = true;
    3671            1 :         Tank.EndUseSubcategoryName = "Chilled Water Storage";
    3672              : 
    3673            1 :         Tank.Volume = state.dataIPShortCut->rNumericArgs(1);
    3674            1 :         if (Tank.Volume == DataSizing::AutoSize) {
    3675            0 :             Tank.VolumeWasAutoSized = true;
    3676              :         }
    3677              : 
    3678            1 :         Real64 rho = Tank.water->getDensity(state, Constant::InitConvTemp, routineName);
    3679              : 
    3680            1 :         Tank.Mass = Tank.Volume * rho;
    3681            1 :         Tank.Height = state.dataIPShortCut->rNumericArgs(2);
    3682            1 :         if (Tank.Height == DataSizing::AutoSize) {
    3683            0 :             Tank.HeightWasAutoSized = true;
    3684              :         }
    3685              : 
    3686            1 :         Tank.Shape = static_cast<TankShape>(getEnumValue(TankShapeNamesUC, Util::makeUPPER(state.dataIPShortCut->cAlphaArgs(2))));
    3687            1 :         switch (Tank.Shape) {
    3688            1 :         case TankShape::HorizCylinder:
    3689              :         case TankShape::VertCylinder: {
    3690            1 :             break;
    3691              :         }
    3692            0 :         case TankShape::Other: {
    3693            0 :             if (state.dataIPShortCut->rNumericArgs(3) > 0.0) {
    3694            0 :                 Tank.Perimeter = state.dataIPShortCut->rNumericArgs(3);
    3695              :             } else {
    3696            0 :                 ShowSevereError(state,
    3697            0 :                                 format("{} = {}:  Tank Perimeter must be greater than zero for Tank Shape=OTHER",
    3698            0 :                                        state.dataIPShortCut->cCurrentModuleObject,
    3699            0 :                                        state.dataIPShortCut->cAlphaArgs(1)));
    3700            0 :                 ErrorsFound = true;
    3701              :             }
    3702            0 :             break;
    3703              :         }
    3704            0 :         default: {
    3705            0 :             ShowSevereError(state,
    3706            0 :                             format("{} = {}:  Invalid Tank Shape entered={}",
    3707            0 :                                    state.dataIPShortCut->cCurrentModuleObject,
    3708            0 :                                    state.dataIPShortCut->cAlphaArgs(1),
    3709            0 :                                    state.dataIPShortCut->cAlphaArgs(2)));
    3710            0 :             Tank.Shape = TankShape::VertCylinder;
    3711            0 :             ErrorsFound = true;
    3712            0 :             break;
    3713              :         }
    3714              :         }
    3715              : 
    3716            1 :         if (state.dataIPShortCut->rNumericArgs(6) > 0.0) {
    3717            1 :             Tank.TankTempLimit = state.dataIPShortCut->rNumericArgs(6);
    3718              :         } else {
    3719              :             // default to just above freezing
    3720            0 :             Tank.TankTempLimit = 1.0;
    3721              :         }
    3722              : 
    3723            1 :         if (state.dataIPShortCut->lAlphaFieldBlanks(3)) {
    3724            0 :             ShowSevereEmptyField(state, eoh, state.dataIPShortCut->cAlphaFieldNames(3));
    3725            0 :             ErrorsFound = true;
    3726            1 :         } else if ((Tank.setptTempSched = Sched::GetSchedule(state, state.dataIPShortCut->cAlphaArgs(3))) == nullptr) {
    3727            0 :             ShowSevereItemNotFound(state, eoh, state.dataIPShortCut->cAlphaFieldNames(3), state.dataIPShortCut->cAlphaArgs(3));
    3728            0 :             ErrorsFound = true;
    3729              :         }
    3730              : 
    3731            1 :         if (state.dataIPShortCut->rNumericArgs(4) > 0.0) {
    3732            1 :             Tank.DeadBandDeltaTemp = state.dataIPShortCut->rNumericArgs(4);
    3733              :         } else {
    3734              :             // Default to very small number (however it can't be TINY or it will break the algorithm)
    3735            0 :             Tank.DeadBandDeltaTemp = 0.0001;
    3736              :         }
    3737              : 
    3738            1 :         Tank.HeaterHeight1 = state.dataIPShortCut->rNumericArgs(5);
    3739            1 :         Tank.MaxCapacity = state.dataIPShortCut->rNumericArgs(7);
    3740            1 :         if (Tank.MaxCapacity == DataSizing::AutoSize) {
    3741            0 :             Tank.MaxCapacityWasAutoSized = true;
    3742              :         }
    3743              : 
    3744            1 :         Tank.Efficiency = 1.0;
    3745            1 :         Tank.setptTemp2Sched = nullptr;
    3746            1 :         Tank.MaxCapacity2 = 0.0;
    3747            1 :         Tank.HeaterHeight2 = 0.0;
    3748            1 :         Tank.FuelType = Constant::eFuel::Electricity;
    3749              : 
    3750            1 :         Tank.OffCycParaLoad = 0.0;
    3751            1 :         Tank.OffCycParaFuelType = Constant::eFuel::Electricity;
    3752            1 :         Tank.OffCycParaFracToTank = 0.0;
    3753            1 :         Tank.OffCycParaHeight = 0.0;
    3754            1 :         Tank.OnCycParaLoad = 0.0;
    3755            1 :         Tank.OnCycParaFuelType = Constant::eFuel::Electricity;
    3756            1 :         Tank.OnCycParaFracToTank = 0.0;
    3757            1 :         Tank.OnCycParaHeight = 0.0;
    3758              : 
    3759            1 :         Tank.AmbientTempIndicator =
    3760            1 :             static_cast<WTTAmbientTemp>(getEnumValue(TankAmbientTempNamesUC, Util::makeUPPER(state.dataIPShortCut->cAlphaArgs(4))));
    3761            1 :         switch (Tank.AmbientTempIndicator) {
    3762              : 
    3763            0 :         case WTTAmbientTemp::Schedule: {
    3764            0 :             if (state.dataIPShortCut->lAlphaFieldBlanks(5)) {
    3765            0 :                 ShowSevereEmptyField(state, eoh, state.dataIPShortCut->cAlphaFieldNames(5));
    3766            0 :                 ErrorsFound = true;
    3767            0 :             } else if ((Tank.ambientTempSched = Sched::GetSchedule(state, state.dataIPShortCut->cAlphaArgs(5))) == nullptr) {
    3768            0 :                 ShowSevereItemNotFound(state, eoh, state.dataIPShortCut->cAlphaFieldNames(5), state.dataIPShortCut->cAlphaArgs(5));
    3769            0 :                 ErrorsFound = true;
    3770              :             }
    3771            0 :         } break;
    3772              : 
    3773            1 :         case WTTAmbientTemp::TempZone: {
    3774            1 :             Tank.AmbientTempZone = Util::FindItemInList(state.dataIPShortCut->cAlphaArgs(6), state.dataHeatBal->Zone);
    3775            1 :             if (Tank.AmbientTempZone == 0) {
    3776            0 :                 ShowSevereError(state, format("Invalid, {} = {}", state.dataIPShortCut->cAlphaFieldNames(6), state.dataIPShortCut->cAlphaArgs(6)));
    3777            0 :                 ShowContinueError(state,
    3778            0 :                                   format("Entered in {} = {}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
    3779            0 :                 ShowContinueError(state, "Zone was not found.");
    3780            0 :                 ErrorsFound = true;
    3781              :             }
    3782            1 :             Tank.OffCycLossFracToZone = 1.0;
    3783              : 
    3784            1 :             break;
    3785              :         }
    3786            0 :         case WTTAmbientTemp::OutsideAir: {
    3787            0 :             Tank.AmbientTempOutsideAirNode =
    3788            0 :                 NodeInputManager::GetOnlySingleNode(state,
    3789            0 :                                                     state.dataIPShortCut->cAlphaArgs(7),
    3790              :                                                     ErrorsFound,
    3791              :                                                     DataLoopNode::ConnectionObjectType::ThermalStorageChilledWaterStratified,
    3792            0 :                                                     state.dataIPShortCut->cAlphaArgs(1),
    3793              :                                                     DataLoopNode::NodeFluidType::Air,
    3794              :                                                     DataLoopNode::ConnectionType::Inlet,
    3795              :                                                     NodeInputManager::CompFluidStream::Primary,
    3796              :                                                     DataLoopNode::ObjectIsNotParent);
    3797            0 :             if (!state.dataIPShortCut->lAlphaFieldBlanks(7)) {
    3798            0 :                 if (!OutAirNodeManager::CheckOutAirNodeNumber(state, Tank.AmbientTempOutsideAirNode)) {
    3799            0 :                     ShowSevereError(state,
    3800            0 :                                     format("Invalid, {} = {}", state.dataIPShortCut->cAlphaFieldNames(7), state.dataIPShortCut->cAlphaArgs(7)));
    3801            0 :                     ShowContinueError(state,
    3802            0 :                                       format("Entered in {} = {}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
    3803            0 :                     ShowContinueError(state, "Outdoor Air Node not on OutdoorAir:NodeList or OutdoorAir:Node");
    3804            0 :                     ErrorsFound = true;
    3805              :                 }
    3806              :             } else {
    3807            0 :                 ShowSevereError(state, format("{} = {}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
    3808            0 :                 ShowContinueError(state, "An Ambient Outdoor Air Node name must be used when the Ambient Temperature Indicator is Outdoors.");
    3809            0 :                 ErrorsFound = true;
    3810              :             }
    3811              : 
    3812            0 :             break;
    3813              :         }
    3814            0 :         default: {
    3815            0 :             ShowSevereError(state,
    3816            0 :                             format("{} = {}:  Invalid Ambient Temperature Indicator entered={}",
    3817            0 :                                    state.dataIPShortCut->cCurrentModuleObject,
    3818            0 :                                    state.dataIPShortCut->cAlphaArgs(1),
    3819            0 :                                    state.dataIPShortCut->cAlphaArgs(4)));
    3820            0 :             ShowContinueError(state, "  Valid entries are Schedule, Zone, and Outdoors.");
    3821            0 :             ErrorsFound = true;
    3822            0 :             break;
    3823              :         }
    3824              :         }
    3825              : 
    3826            1 :         Tank.SkinLossCoeff = state.dataIPShortCut->rNumericArgs(8);
    3827            1 :         Tank.SkinLossFracToZone = 1.0;
    3828            1 :         Tank.OffCycFlueLossCoeff = 0.0;
    3829            1 :         Tank.OffCycFlueLossFracToZone = 0.0;
    3830              : 
    3831            1 :         Tank.MassFlowRateMax = 0.0;
    3832            1 :         Tank.flowRateSched = nullptr;
    3833            1 :         Tank.useInletTempSched = nullptr;
    3834            1 :         Tank.UseEffectiveness = state.dataIPShortCut->rNumericArgs(9);
    3835            1 :         Tank.UseInletHeight = state.dataIPShortCut->rNumericArgs(10);
    3836              : 
    3837              :         // default to always on
    3838            1 :         Tank.sourceSideAvailSched = Sched::GetScheduleAlwaysOn(state);
    3839            1 :         Tank.useSideAvailSched = Sched::GetScheduleAlwaysOn(state);
    3840              : 
    3841            1 :         if (state.dataIPShortCut->rNumericArgs(10) == Constant::AutoCalculate) {
    3842            0 :             Tank.UseInletHeight = Tank.Height; // top of tank
    3843              :         }
    3844            1 :         if (Tank.UseInletHeight > Tank.Height) {
    3845            0 :             ShowSevereError(state,
    3846            0 :                             format("{} = {}: Use inlet is located higher than overall tank height.",
    3847            0 :                                    state.dataIPShortCut->cCurrentModuleObject,
    3848            0 :                                    state.dataIPShortCut->cAlphaArgs(1)));
    3849            0 :             ShowContinueError(state, format("{} = {:.4R}", state.dataIPShortCut->cNumericFieldNames(2), state.dataIPShortCut->rNumericArgs(2)));
    3850            0 :             ShowContinueError(state, format("{} = {:.4R}", state.dataIPShortCut->cNumericFieldNames(10), state.dataIPShortCut->rNumericArgs(10)));
    3851            0 :             ErrorsFound = true;
    3852              :         }
    3853              : 
    3854            1 :         Tank.UseOutletHeight = state.dataIPShortCut->rNumericArgs(11);
    3855            1 :         if (Tank.UseOutletHeight > Tank.Height) {
    3856            0 :             ShowSevereError(state,
    3857            0 :                             format("{} = {}: Use outlet is located higher than overall tank height.",
    3858            0 :                                    state.dataIPShortCut->cCurrentModuleObject,
    3859            0 :                                    state.dataIPShortCut->cAlphaArgs(1)));
    3860            0 :             ShowContinueError(state, format("{} = {:.4R}", state.dataIPShortCut->cNumericFieldNames(2), state.dataIPShortCut->rNumericArgs(2)));
    3861            0 :             ShowContinueError(state, format("{} = {:.4R}", state.dataIPShortCut->cNumericFieldNames(11), state.dataIPShortCut->rNumericArgs(11)));
    3862            0 :             ErrorsFound = true;
    3863              :         }
    3864              : 
    3865            1 :         if ((state.dataIPShortCut->rNumericArgs(13) > 1) || (state.dataIPShortCut->rNumericArgs(13) <= 0)) {
    3866            0 :             ShowSevereError(state,
    3867            0 :                             format("{} = {}:  Source Side Effectiveness is out of bounds (>0 to 1)",
    3868            0 :                                    state.dataIPShortCut->cCurrentModuleObject,
    3869            0 :                                    state.dataIPShortCut->cAlphaArgs(1)));
    3870            0 :             ErrorsFound = true;
    3871              :         }
    3872            1 :         Tank.SourceEffectiveness = state.dataIPShortCut->rNumericArgs(13);
    3873              : 
    3874            1 :         Tank.SourceInletHeight = state.dataIPShortCut->rNumericArgs(14);
    3875            1 :         if (Tank.SourceInletHeight > Tank.Height) {
    3876            0 :             ShowSevereError(state,
    3877            0 :                             format("{} = {}: Source inlet is located higher than overall tank height.",
    3878            0 :                                    state.dataIPShortCut->cCurrentModuleObject,
    3879            0 :                                    state.dataIPShortCut->cAlphaArgs(1)));
    3880            0 :             ShowContinueError(state, format("{} = {:.4R}", state.dataIPShortCut->cNumericFieldNames(2), state.dataIPShortCut->rNumericArgs(2)));
    3881            0 :             ShowContinueError(state, format("{} = {:.4R}", state.dataIPShortCut->cNumericFieldNames(14), state.dataIPShortCut->rNumericArgs(14)));
    3882            0 :             ErrorsFound = true;
    3883              :         }
    3884              : 
    3885            1 :         Tank.SourceOutletHeight = state.dataIPShortCut->rNumericArgs(15);
    3886            1 :         if (state.dataIPShortCut->rNumericArgs(15) == Constant::AutoCalculate) {
    3887            0 :             Tank.SourceOutletHeight = Tank.Height; // top of tank
    3888              :         }
    3889            1 :         if (Tank.SourceOutletHeight > Tank.Height) {
    3890            0 :             ShowSevereError(state,
    3891            0 :                             format("{} = {}: Source outlet is located higher than overall tank height.",
    3892            0 :                                    state.dataIPShortCut->cCurrentModuleObject,
    3893            0 :                                    state.dataIPShortCut->cAlphaArgs(1)));
    3894            0 :             ShowContinueError(state, format("{} = {:.4R}", state.dataIPShortCut->cNumericFieldNames(2), state.dataIPShortCut->rNumericArgs(2)));
    3895            0 :             ShowContinueError(state, format("{} = {:.4R}", state.dataIPShortCut->cNumericFieldNames(15), state.dataIPShortCut->rNumericArgs(15)));
    3896            0 :             ErrorsFound = true;
    3897              :         }
    3898              : 
    3899            1 :         Tank.StandAlone = false;
    3900              : 
    3901            1 :         if (state.dataIPShortCut->lNumericFieldBlanks(12)) {
    3902            0 :             Tank.UseDesignVolFlowRate = 0.0;
    3903              :         } else {
    3904            1 :             Tank.UseDesignVolFlowRate = state.dataIPShortCut->rNumericArgs(12);
    3905            1 :             if (Tank.UseDesignVolFlowRate == DataSizing::AutoSize) {
    3906            0 :                 Tank.UseDesignVolFlowRateWasAutoSized = true;
    3907              :             }
    3908              :         }
    3909              : 
    3910            1 :         Tank.UseSidePlantLoc.loopSideNum = DataPlant::LoopSideLocation::Invalid;
    3911              : 
    3912            1 :         if (state.dataIPShortCut->lNumericFieldBlanks(16)) {
    3913            0 :             Tank.SourceDesignVolFlowRate = 0.0;
    3914              :         } else {
    3915            1 :             Tank.SourceDesignVolFlowRate = state.dataIPShortCut->rNumericArgs(16);
    3916            1 :             if (Tank.SourceDesignVolFlowRate == DataSizing::AutoSize) {
    3917            0 :                 Tank.SourceDesignVolFlowRateWasAutoSized = true;
    3918              :             }
    3919              :         }
    3920              : 
    3921            1 :         Tank.SizingRecoveryTime = state.dataIPShortCut->rNumericArgs(17);
    3922              : 
    3923            1 :         Tank.SrcSidePlantLoc.loopSideNum = DataPlant::LoopSideLocation::Invalid;
    3924              : 
    3925            1 :         if ((!state.dataIPShortCut->lAlphaFieldBlanks(8)) || (!state.dataIPShortCut->lAlphaFieldBlanks(9))) {
    3926            1 :             Tank.UseInletNode = NodeInputManager::GetOnlySingleNode(state,
    3927            1 :                                                                     state.dataIPShortCut->cAlphaArgs(8),
    3928              :                                                                     ErrorsFound,
    3929              :                                                                     DataLoopNode::ConnectionObjectType::ThermalStorageChilledWaterStratified,
    3930            1 :                                                                     state.dataIPShortCut->cAlphaArgs(1),
    3931              :                                                                     DataLoopNode::NodeFluidType::Water,
    3932              :                                                                     DataLoopNode::ConnectionType::Inlet,
    3933              :                                                                     NodeInputManager::CompFluidStream::Primary,
    3934              :                                                                     DataLoopNode::ObjectIsNotParent);
    3935            1 :             Tank.InletNodeName1 = state.dataIPShortCut->cAlphaArgs(8);
    3936            1 :             Tank.UseOutletNode = NodeInputManager::GetOnlySingleNode(state,
    3937            1 :                                                                      state.dataIPShortCut->cAlphaArgs(9),
    3938              :                                                                      ErrorsFound,
    3939              :                                                                      DataLoopNode::ConnectionObjectType::ThermalStorageChilledWaterStratified,
    3940            1 :                                                                      state.dataIPShortCut->cAlphaArgs(1),
    3941              :                                                                      DataLoopNode::NodeFluidType::Water,
    3942              :                                                                      DataLoopNode::ConnectionType::Outlet,
    3943              :                                                                      NodeInputManager::CompFluidStream::Primary,
    3944              :                                                                      DataLoopNode::ObjectIsNotParent);
    3945            1 :             Tank.OutletNodeName1 = state.dataIPShortCut->cAlphaArgs(9);
    3946              :         }
    3947              : 
    3948            1 :         if ((!state.dataIPShortCut->lAlphaFieldBlanks(11)) || (!state.dataIPShortCut->lAlphaFieldBlanks(12))) {
    3949            1 :             Tank.SourceInletNode = NodeInputManager::GetOnlySingleNode(state,
    3950            1 :                                                                        state.dataIPShortCut->cAlphaArgs(11),
    3951              :                                                                        ErrorsFound,
    3952              :                                                                        DataLoopNode::ConnectionObjectType::ThermalStorageChilledWaterStratified,
    3953            1 :                                                                        state.dataIPShortCut->cAlphaArgs(1),
    3954              :                                                                        DataLoopNode::NodeFluidType::Water,
    3955              :                                                                        DataLoopNode::ConnectionType::Inlet,
    3956              :                                                                        NodeInputManager::CompFluidStream::Secondary,
    3957              :                                                                        DataLoopNode::ObjectIsNotParent);
    3958            1 :             Tank.InletNodeName2 = state.dataIPShortCut->cAlphaArgs(11);
    3959            1 :             Tank.SourceOutletNode = NodeInputManager::GetOnlySingleNode(state,
    3960            1 :                                                                         state.dataIPShortCut->cAlphaArgs(12),
    3961              :                                                                         ErrorsFound,
    3962              :                                                                         DataLoopNode::ConnectionObjectType::ThermalStorageChilledWaterStratified,
    3963            1 :                                                                         state.dataIPShortCut->cAlphaArgs(1),
    3964              :                                                                         DataLoopNode::NodeFluidType::Water,
    3965              :                                                                         DataLoopNode::ConnectionType::Outlet,
    3966              :                                                                         NodeInputManager::CompFluidStream::Secondary,
    3967              :                                                                         DataLoopNode::ObjectIsNotParent);
    3968            1 :             Tank.OutletNodeName2 = state.dataIPShortCut->cAlphaArgs(12);
    3969              :         }
    3970              : 
    3971            1 :         if (state.dataIPShortCut->lAlphaFieldBlanks(10)) {
    3972            0 :             Tank.useSideAvailSched = Sched::GetScheduleAlwaysOn(state);
    3973            1 :         } else if ((Tank.useSideAvailSched = Sched::GetSchedule(state, state.dataIPShortCut->cAlphaArgs(10))) == nullptr) {
    3974            0 :             ShowSevereItemNotFound(state, eoh, state.dataIPShortCut->cAlphaFieldNames(10), state.dataIPShortCut->cAlphaArgs(10));
    3975            0 :             ErrorsFound = true;
    3976              :         }
    3977              : 
    3978            1 :         if (Tank.UseSidePlantLoc.loopSideNum == DataPlant::LoopSideLocation::Demand && Tank.SourceInletNode != 0) {
    3979            0 :             PlantUtilities::RegisterPlantCompDesignFlow(state, Tank.SourceInletNode, Tank.SourceDesignVolFlowRate);
    3980              :         }
    3981              : 
    3982            1 :         if (state.dataIPShortCut->lAlphaFieldBlanks(13)) {
    3983            0 :             Tank.sourceSideAvailSched = Sched::GetScheduleAlwaysOn(state);
    3984            1 :         } else if ((Tank.sourceSideAvailSched = Sched::GetSchedule(state, state.dataIPShortCut->cAlphaArgs(13))) == nullptr) {
    3985            0 :             ShowSevereItemNotFound(state, eoh, state.dataIPShortCut->cAlphaFieldNames(13), state.dataIPShortCut->cAlphaArgs(13));
    3986            0 :             ErrorsFound = true;
    3987              :         }
    3988              : 
    3989              :         // Validate inlet mode
    3990            1 :         Tank.InletMode =
    3991            1 :             static_cast<InletPositionMode>(getEnumValue(InletPositionModeNamesUC, Util::makeUPPER(state.dataIPShortCut->cAlphaArgs(14))));
    3992              : 
    3993            1 :         Tank.Nodes = state.dataIPShortCut->rNumericArgs(18);
    3994            1 :         Tank.AdditionalCond = state.dataIPShortCut->rNumericArgs(19);
    3995              : 
    3996            1 :         Tank.AdditionalLossCoeff.allocate(Tank.Nodes);
    3997            1 :         Tank.AdditionalLossCoeff = 0.0;
    3998            1 :         for (int NodeNum = 1; NodeNum <= Tank.Nodes; ++NodeNum) {
    3999            1 :             if (NumNums > 19 + NodeNum) {
    4000            0 :                 Tank.AdditionalLossCoeff(NodeNum) = state.dataIPShortCut->rNumericArgs(19 + NodeNum);
    4001              :             } else {
    4002            1 :                 break;
    4003              :             }
    4004              :         }
    4005              : 
    4006            1 :         if (NumNums > 19 + Tank.Nodes) {
    4007            0 :             ShowWarningError(
    4008              :                 state,
    4009            0 :                 format("{} = {}:  More Additional Loss Coefficients were entered than the number of nodes; extra coefficients will not be used",
    4010            0 :                        state.dataIPShortCut->cCurrentModuleObject,
    4011            0 :                        state.dataIPShortCut->cAlphaArgs(1)));
    4012              :         }
    4013              : 
    4014            1 :         Tank.SetupStratifiedNodes(state);
    4015              :     }
    4016              : 
    4017            1 :     return ErrorsFound;
    4018              : }
    4019              : 
    4020           72 : bool GetWaterThermalTankInput(EnergyPlusData &state)
    4021              : {
    4022              : 
    4023              :     // SUBROUTINE INFORMATION:
    4024              :     //       AUTHOR         Dan Fisher and Brandon Anderson
    4025              :     //       DATE WRITTEN   May 2000
    4026              :     //       MODIFIED       R. Raustad, June 2005, added HPWH and desuperheater water heating coils
    4027              :     //                      B. Griffith, Oct. 2007 extensions for indirect water heaters
    4028              :     //                      B. Griffith, Feb. 2008 extensions for autosizing water heaters
    4029              :     //                      BG Mar 2009.  Trap for bad heater height input for stratified water heater CR7718
    4030              :     //                      B. Shen 12/2014, add air-source variable-speed heat pump water heating
    4031              : 
    4032              :     // PURPOSE OF THIS SUBROUTINE:
    4033              :     // Gets the water heater, HPWH, and/or desuperheater heating coil input from the input file.
    4034              : 
    4035           72 :     bool ErrorsFound = false;
    4036              : 
    4037              :     // Make sure refrigeration input is gotten before this input
    4038           72 :     RefrigeratedCase::CheckRefrigerationInput(state);
    4039              : 
    4040           72 :     if (state.dataWaterThermalTanks->getWaterThermalTankInputFlag) {
    4041           72 :         state.dataWaterThermalTanks->numWaterHeaterMixed = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cMixedWHModuleObj);
    4042          144 :         state.dataWaterThermalTanks->numWaterHeaterStratified =
    4043           72 :             state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cStratifiedWHModuleObj);
    4044          144 :         state.dataWaterThermalTanks->numChilledWaterMixed =
    4045           72 :             state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cMixedCWTankModuleObj);
    4046          144 :         state.dataWaterThermalTanks->numChilledWaterStratified =
    4047           72 :             state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cStratifiedCWTankModuleObj);
    4048          144 :         state.dataWaterThermalTanks->numWaterThermalTank =
    4049           72 :             state.dataWaterThermalTanks->numWaterHeaterMixed + state.dataWaterThermalTanks->numWaterHeaterStratified +
    4050           72 :             state.dataWaterThermalTanks->numChilledWaterMixed + state.dataWaterThermalTanks->numChilledWaterStratified;
    4051          144 :         state.dataWaterThermalTanks->numHeatPumpWaterHeater =
    4052           72 :             state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cHPWHPumpedCondenser) +
    4053           72 :             state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cHPWHWrappedCondenser);
    4054          144 :         state.dataWaterThermalTanks->numWaterHeaterDesuperheater =
    4055           72 :             state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCoilDesuperheater);
    4056              : 
    4057           72 :         if (state.dataWaterThermalTanks->numWaterThermalTank > 0) {
    4058              :             static constexpr std::string_view Format_720(
    4059              :                 "! <Water Heater Information>,Type,Name,Volume {{m3}},Maximum Capacity {{W}},Standard Rated Recovery Efficiency, "
    4060              :                 "Standard Rated Energy Factor\n");
    4061              :             static constexpr std::string_view Format_721(
    4062              :                 "! <Heat Pump Water Heater Information>,Type,Name,Volume {{m3}},Maximum Capacity {{W}},Standard Rated Recovery "
    4063              :                 "Efficiency,Standard Rated Energy Factor,DX Coil Total Cooling Rate {{W}}\n");
    4064              :             static constexpr std::string_view Format_722(
    4065              :                 "! <Water Heater Stratified Node Information>,Node Number,Height {{m}},Volume {{m3}},Maximum Capacity "
    4066              :                 "{{W}},Off-Cycle UA {{W/K}},On-Cycle UA {{W/K}},Number Of Inlets,Number Of Outlets\n");
    4067              :             static constexpr std::string_view Format_725(
    4068              :                 "! <Chilled Water Tank Information>,Type,Name,Volume {{m3}},Use Side Design Flow Rate {{m3/s}}, "
    4069              :                 "Source Side Design Flow Rate {{m3/s}}\n");
    4070              :             static constexpr std::string_view Format_726(
    4071              :                 "! <Chilled Water Tank Stratified Node Information>,Node Number,Height {{m}},Volume {{m3}},UA {{W/K}},Number Of "
    4072              :                 "Inlets,Number Of Outlets\n");
    4073              : 
    4074              :             // Write water heater header for EIO
    4075           27 :             if ((state.dataWaterThermalTanks->numWaterHeaterMixed > 0) || (state.dataWaterThermalTanks->numWaterHeaterStratified > 0))
    4076           26 :                 print(state.files.eio, Format_720);
    4077           27 :             if (state.dataWaterThermalTanks->numHeatPumpWaterHeater > 0) print(state.files.eio, Format_721);
    4078           27 :             if (state.dataWaterThermalTanks->numWaterHeaterStratified > 0) print(state.files.eio, Format_722);
    4079           27 :             if (state.dataWaterThermalTanks->numChilledWaterMixed > 0) print(state.files.eio, Format_725);
    4080           27 :             if (state.dataWaterThermalTanks->numChilledWaterStratified > 0) print(state.files.eio, Format_726);
    4081              :         }
    4082              : 
    4083           72 :         if (state.dataWaterThermalTanks->numWaterThermalTank > 0) {
    4084           27 :             state.dataWaterThermalTanks->WaterThermalTank.allocate(state.dataWaterThermalTanks->numWaterThermalTank);
    4085           27 :             state.dataWaterThermalTanks->UniqueWaterThermalTankNames.reserve(static_cast<unsigned>(state.dataWaterThermalTanks->numWaterThermalTank));
    4086              :         }
    4087           72 :         if (state.dataWaterThermalTanks->numHeatPumpWaterHeater > 0) {
    4088           10 :             state.dataWaterThermalTanks->HPWaterHeater.allocate(state.dataWaterThermalTanks->numHeatPumpWaterHeater);
    4089              :         }
    4090              : 
    4091           72 :         if (state.dataWaterThermalTanks->numWaterHeaterDesuperheater > 0) {
    4092            5 :             state.dataWaterThermalTanks->WaterHeaterDesuperheater.allocate(state.dataWaterThermalTanks->numWaterHeaterDesuperheater);
    4093              :         }
    4094              : 
    4095              :         // =======   Get Coil:WaterHeating:Desuperheater ======================================================================
    4096           72 :         if (state.dataWaterThermalTanks->numWaterHeaterDesuperheater > 0) {
    4097            5 :             ErrorsFound |= getDesuperHtrInput(state);
    4098              :         }
    4099              : 
    4100              :         //  =======   Get HEAT PUMP:WATER HEATER ===============================================================================
    4101           72 :         if (state.dataWaterThermalTanks->numHeatPumpWaterHeater > 0) {
    4102           10 :             ErrorsFound |= getHPWaterHeaterInput(state);
    4103              :         }
    4104              : 
    4105              :         //  =======   Get WATER HEATER:MIXED ===================================================================================
    4106           72 :         if (state.dataWaterThermalTanks->numWaterHeaterMixed > 0) {
    4107           14 :             ErrorsFound |= getWaterHeaterMixedInputs(state);
    4108              :         }
    4109              : 
    4110              :         //  =======   Get WATER HEATER:STRATIFIED ==============================================================================
    4111           72 :         if (state.dataWaterThermalTanks->numWaterHeaterStratified > 0) {
    4112           13 :             ErrorsFound |= getWaterHeaterStratifiedInput(state);
    4113              :         }
    4114              : 
    4115              :         //  =======   Get Chilled Water :MIXED ===================================================================================
    4116           72 :         if (state.dataWaterThermalTanks->numChilledWaterMixed > 0) {
    4117            0 :             ErrorsFound |= getWaterTankMixedInput(state);
    4118              :         }
    4119              : 
    4120              :         //  =======   Get 'ThermalStorage:ChilledWater:Stratified' =======================================================
    4121           72 :         if (state.dataWaterThermalTanks->numChilledWaterStratified > 0) {
    4122            1 :             ErrorsFound |= getWaterTankStratifiedInput(state);
    4123              :         }
    4124              : 
    4125              :         //   Loop through all desuperheating coils and then search all water heaters for the tank connected to the desuperheating coil
    4126           72 :         if (state.dataWaterThermalTanks->numWaterHeaterDesuperheater > 0) {
    4127            5 :             state.dataIPShortCut->cCurrentModuleObject = cCoilDesuperheater;
    4128           11 :             for (int DesuperheaterNum = 1; DesuperheaterNum <= state.dataWaterThermalTanks->numWaterHeaterDesuperheater; ++DesuperheaterNum) {
    4129            6 :                 auto &DesuperHtr = state.dataWaterThermalTanks->WaterHeaterDesuperheater(DesuperheaterNum);
    4130           14 :                 for (int WtrHtrNum = 1; WtrHtrNum <= state.dataWaterThermalTanks->numWaterThermalTank; ++WtrHtrNum) {
    4131            8 :                     auto &Tank = state.dataWaterThermalTanks->WaterThermalTank(WtrHtrNum);
    4132            8 :                     if (!Util::SameString(DesuperHtr.TankName, Tank.Name) || !Util::SameString(DesuperHtr.TankType, Tank.Type)) continue;
    4133            6 :                     Tank.DesuperheaterNum = DesuperheaterNum;
    4134            6 :                     DesuperHtr.WaterHeaterTankNum = WtrHtrNum;
    4135            6 :                     DesuperHtr.TankTypeNum = Tank.WaterThermalTankType;
    4136            6 :                     DesuperHtr.BackupElementCapacity = Tank.MaxCapacity;
    4137            6 :                     if (Tank.UseInletNode == 0 && Tank.UseOutletNode == 0) DesuperHtr.StandAlone = true;
    4138              : 
    4139              :                     //         verify Desuperheater/tank source node connections
    4140            6 :                     if (DesuperHtr.WaterInletNode != Tank.SourceOutletNode) {
    4141            0 :                         ShowSevereError(state, format("{} = {}:", state.dataIPShortCut->cCurrentModuleObject, DesuperHtr.Name));
    4142            0 :                         ShowContinueError(state, "Desuperheater inlet node name does not match thermal tank source outlet node name.");
    4143            0 :                         ShowContinueError(state,
    4144            0 :                                           format("Desuperheater water inlet and outlet node names = {} and {}",
    4145            0 :                                                  DesuperHtr.InletNodeName1,
    4146            0 :                                                  DesuperHtr.OutletNodeName1));
    4147            0 :                         ShowContinueError(state,
    4148            0 :                                           format("Thermal tank source side inlet and outlet node names      = {} and {}",
    4149            0 :                                                  Tank.InletNodeName2,
    4150            0 :                                                  Tank.OutletNodeName2));
    4151            0 :                         ErrorsFound = true;
    4152              :                     }
    4153              : 
    4154            6 :                     if (DesuperHtr.WaterOutletNode != Tank.SourceInletNode) {
    4155            0 :                         ShowSevereError(state, format("{} = {}:", state.dataIPShortCut->cCurrentModuleObject, DesuperHtr.Name));
    4156            0 :                         ShowContinueError(state, "Desuperheater water outlet node name does not match thermal tank source inlet node name.");
    4157            0 :                         ShowContinueError(state,
    4158            0 :                                           format("Desuperheater water inlet and outlet node names = {} and {}",
    4159            0 :                                                  DesuperHtr.InletNodeName1,
    4160            0 :                                                  DesuperHtr.OutletNodeName1));
    4161            0 :                         ShowContinueError(state,
    4162            0 :                                           format("Thermal tank source side inlet and outlet node names      = {} and {}",
    4163            0 :                                                  Tank.InletNodeName2,
    4164            0 :                                                  Tank.OutletNodeName2));
    4165            0 :                         ErrorsFound = true;
    4166              :                     }
    4167              :                 }
    4168              : 
    4169            6 :                 if (DesuperHtr.WaterHeaterTankNum == 0) {
    4170            0 :                     ShowSevereError(state, format("{} = {}:", state.dataIPShortCut->cCurrentModuleObject, DesuperHtr.Name));
    4171            0 :                     ShowContinueError(state, format(" Water heater tank = {} not found.", DesuperHtr.TankName));
    4172            0 :                     ErrorsFound = true;
    4173              :                 }
    4174              :             }
    4175              :         }
    4176              : 
    4177              :         // Loop through HPWH's and then search all water heaters for the tank connected to the HPWH
    4178           72 :         if (state.dataWaterThermalTanks->numHeatPumpWaterHeater > 0) {
    4179              : 
    4180           10 :             int const NumPumpedCondenser = state.dataInputProcessing->inputProcessor->getNumObjectsFound(
    4181              :                 state, cHPWHPumpedCondenser); // number of WaterHeater:HeatPump:PumpedCondenser objects
    4182           22 :             for (int HPWaterHeaterNum = 1; HPWaterHeaterNum <= state.dataWaterThermalTanks->numHeatPumpWaterHeater; ++HPWaterHeaterNum) {
    4183              : 
    4184              :                 // Create reference to current HPWH object in array.
    4185           12 :                 HeatPumpWaterHeaterData &HPWH = state.dataWaterThermalTanks->HPWaterHeater(HPWaterHeaterNum);
    4186           12 :                 if (HPWaterHeaterNum <= NumPumpedCondenser) {
    4187              :                     // Pumped Condenser
    4188            7 :                     state.dataIPShortCut->cCurrentModuleObject = cHPWHPumpedCondenser;
    4189              :                 } else {
    4190              :                     // Wrapped Condenser
    4191            5 :                     state.dataIPShortCut->cCurrentModuleObject = cHPWHWrappedCondenser;
    4192              :                 }
    4193              : 
    4194              :                 // find the tank associated with the heat pump water heater and change its %TYPE to HEAT PUMP:WATER HEATER
    4195           29 :                 for (int CheckWaterHeaterNum = 1; CheckWaterHeaterNum <= state.dataWaterThermalTanks->numWaterThermalTank; ++CheckWaterHeaterNum) {
    4196              : 
    4197           17 :                     auto &Tank = state.dataWaterThermalTanks->WaterThermalTank(CheckWaterHeaterNum);
    4198              : 
    4199           17 :                     if (!(Util::SameString(HPWH.TankName, Tank.Name) && Util::SameString(HPWH.TankType, Tank.Type))) continue;
    4200              : 
    4201              :                     // save backup element and on/off-cycle parasitic properties for use during standard rating procedure
    4202           12 :                     HPWH.BackupElementCapacity = Tank.MaxCapacity;
    4203           12 :                     HPWH.BackupElementEfficiency = Tank.Efficiency;
    4204           12 :                     HPWH.WHOnCycParaLoad = Tank.OnCycParaLoad;
    4205           12 :                     HPWH.WHOffCycParaLoad = Tank.OffCycParaLoad;
    4206           12 :                     HPWH.WHOnCycParaFracToTank = Tank.OnCycParaFracToTank;
    4207           12 :                     HPWH.WHOffCycParaFracToTank = Tank.OffCycParaFracToTank;
    4208           12 :                     HPWH.WHPLFCurve = Tank.PLFCurve;
    4209              : 
    4210           12 :                     if (((Tank.WaterThermalTankType == DataPlant::PlantEquipmentType::WtrHeaterMixed) &&
    4211            6 :                          (HPWH.HPWHType == DataPlant::PlantEquipmentType::HeatPumpWtrHeaterPumped)) ||
    4212            6 :                         (Tank.WaterThermalTankType == DataPlant::PlantEquipmentType::WtrHeaterStratified)) {
    4213           12 :                         HPWH.TankType = Tank.Type;
    4214           12 :                         HPWH.HPWHTankType = Tank.WaterThermalTankType;
    4215              :                     } else {
    4216            0 :                         ShowSevereError(state, format("{} = {}:", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    4217            0 :                         ShowContinueError(state, format("Invalid water heater tank type = {}", Tank.Type));
    4218            0 :                         ErrorsFound = true;
    4219              :                     }
    4220              : 
    4221              :                     // Set up comp set for condenser water side nodes (reverse inlet/outlet for water heater)
    4222           12 :                     if (HPWH.bIsIHP) {
    4223            0 :                         BranchNodeConnections::SetUpCompSets(state,
    4224              :                                                              HPWH.Type,
    4225              :                                                              HPWH.Name,
    4226              :                                                              HPWH.DXCoilType,
    4227            0 :                                                              HPWH.DXCoilName + " Water Coil",
    4228              :                                                              HPWH.InletNodeName1,
    4229              :                                                              HPWH.OutletNodeName1,
    4230              :                                                              "HPWH To Coil");
    4231              :                     } else {
    4232           12 :                         BranchNodeConnections::SetUpCompSets(
    4233              :                             state, HPWH.Type, HPWH.Name, HPWH.DXCoilType, HPWH.DXCoilName, HPWH.InletNodeName1, HPWH.OutletNodeName1, "HPWH To Coil");
    4234              :                     }
    4235           12 :                     BranchNodeConnections::SetUpCompSets(
    4236              :                         state, HPWH.Type, HPWH.Name, HPWH.TankType, HPWH.TankName, HPWH.OutletNodeName1, HPWH.InletNodeName1, "HPWH To Tank");
    4237              : 
    4238              :                     // If WaterHeaterMixed: do not allow modulating control for HPWH's (i.e. modulating control usually used for tankless WH's)
    4239           12 :                     if ((Tank.WaterThermalTankType == DataPlant::PlantEquipmentType::WtrHeaterMixed) &&
    4240            6 :                         (Tank.ControlType == HeaterControlMode::Modulate)) {
    4241            0 :                         ShowSevereError(state, format("{} = {}:", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    4242            0 :                         ShowContinueError(state, format("Heater Control Type for {} = {} must be CYCLE.", Tank.Type, Tank.Name));
    4243            0 :                         ErrorsFound = true;
    4244              :                     }
    4245              : 
    4246           12 :                     Tank.HeatPumpNum = HPWaterHeaterNum;
    4247           12 :                     HPWH.WaterHeaterTankNum = CheckWaterHeaterNum;
    4248           12 :                     HPWH.FoundTank = true;
    4249              : 
    4250           12 :                     if (Tank.DesuperheaterNum > 0) {
    4251            0 :                         ShowSevereError(
    4252              :                             state,
    4253            0 :                             format("{} = {}and Coil:WaterHeating:Desuperheater = {}:  cannot be connected to the same water heater tank = {}",
    4254            0 :                                    state.dataIPShortCut->cCurrentModuleObject,
    4255            0 :                                    HPWH.Name,
    4256            0 :                                    state.dataWaterThermalTanks->WaterHeaterDesuperheater(CheckWaterHeaterNum).Name,
    4257            0 :                                    Tank.Name));
    4258              :                     }
    4259              : 
    4260              :                     // check that water heater source side effectiveness is greater than 0
    4261           12 :                     if (Tank.SourceEffectiveness <= 0.0) {
    4262            0 :                         ShowSevereError(state,
    4263            0 :                                         format("{} = {}:  Invalid source side effectiveness for heat pump water heater = {:.3T}",
    4264            0 :                                                state.dataIPShortCut->cCurrentModuleObject,
    4265            0 :                                                HPWH.Name,
    4266            0 :                                                Tank.SourceEffectiveness));
    4267            0 :                         ShowContinueError(state, " water heater source effectiveness will default to 1.0 and simulation continues.");
    4268            0 :                         Tank.SourceEffectiveness = 1.0;
    4269              :                     }
    4270              : 
    4271              :                     // Set up the source side nodes for wrapped condensers
    4272           12 :                     if (HPWH.HPWHType == DataPlant::PlantEquipmentType::HeatPumpWtrHeaterWrapped) {
    4273            5 :                         if (Tank.SourceInletNode > 0 || Tank.SourceOutletNode > 0) {
    4274            0 :                             ShowSevereError(state, format("{} = {} has a source inlet or outlet node specified,", Tank.Type, Tank.Name));
    4275            0 :                             ShowContinueError(
    4276            0 :                                 state, format("but it is attached to {} = {}, which doesn't permit source side connections.", HPWH.Type, HPWH.Name));
    4277            0 :                             ShowContinueError(state, "Please leave the source side inlet and outlet fields blank.");
    4278            0 :                             ErrorsFound = true;
    4279              :                         } else {
    4280              : 
    4281              :                             DataLoopNode::ConnectionObjectType objType = static_cast<DataLoopNode::ConnectionObjectType>(
    4282            5 :                                 getEnumValue(BranchNodeConnections::ConnectionObjectTypeNamesUC, Util::makeUPPER(Tank.Type)));
    4283              : 
    4284            5 :                             Tank.SourceInletNode = NodeInputManager::GetOnlySingleNode(state,
    4285            5 :                                                                                        HPWH.OutletNodeName1,
    4286              :                                                                                        ErrorsFound,
    4287              :                                                                                        objType,
    4288            5 :                                                                                        Tank.Name,
    4289              :                                                                                        DataLoopNode::NodeFluidType::Water,
    4290              :                                                                                        DataLoopNode::ConnectionType::Inlet,
    4291              :                                                                                        NodeInputManager::CompFluidStream::Secondary,
    4292              :                                                                                        DataLoopNode::ObjectIsNotParent);
    4293            5 :                             Tank.InletNodeName2 = HPWH.OutletNodeName1;
    4294            5 :                             Tank.SourceOutletNode = NodeInputManager::GetOnlySingleNode(state,
    4295            5 :                                                                                         HPWH.InletNodeName1,
    4296              :                                                                                         ErrorsFound,
    4297              :                                                                                         objType,
    4298            5 :                                                                                         Tank.Name,
    4299              :                                                                                         DataLoopNode::NodeFluidType::Water,
    4300              :                                                                                         DataLoopNode::ConnectionType::Outlet,
    4301              :                                                                                         NodeInputManager::CompFluidStream::Secondary,
    4302              :                                                                                         DataLoopNode::ObjectIsNotParent);
    4303            5 :                             Tank.OutletNodeName2 = HPWH.InletNodeName1;
    4304              :                         }
    4305              : 
    4306              :                         // Mark the tank as not stand alone because it is connected now.
    4307            5 :                         Tank.StandAlone = false;
    4308              :                     }
    4309              : 
    4310              :                     // Set HPWH structure variable StandAlone to TRUE if use nodes are not connected
    4311           12 :                     if (Tank.UseInletNode == 0 && Tank.UseOutletNode == 0) HPWH.StandAlone = true;
    4312              : 
    4313           12 :                     if (HPWH.WHUseInletNode != Tank.UseInletNode || HPWH.WHUseOutletNode != Tank.UseOutletNode) {
    4314            0 :                         ShowSevereError(state, format("{} = {}:", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    4315            0 :                         ShowContinueError(state,
    4316            0 :                                           format("Heat pump water heater tank use side inlet and outlet node names must match the use side inlet and "
    4317              :                                                  "outlet node names for water heater tank = {}: {}",
    4318            0 :                                                  HPWH.TankType,
    4319            0 :                                                  HPWH.TankName));
    4320            0 :                         ShowContinueError(state,
    4321            0 :                                           format("Heat pump water heater use side inlet and outlet node names = {} and {}",
    4322            0 :                                                  HPWH.InletNodeName2,
    4323            0 :                                                  HPWH.OutletNodeName2));
    4324            0 :                         ShowContinueError(state,
    4325            0 :                                           format("Water heater tank use side inlet and outlet node names      = {} and {}",
    4326            0 :                                                  Tank.InletNodeName1,
    4327            0 :                                                  Tank.OutletNodeName1));
    4328            0 :                         ErrorsFound = true;
    4329              :                     } else {
    4330           12 :                         if (!HPWH.StandAlone) {
    4331           14 :                             BranchNodeConnections::TestCompSet(state, HPWH.Type, HPWH.Name, Tank.InletNodeName1, Tank.OutletNodeName1, "Water Nodes");
    4332              :                         }
    4333              :                     }
    4334              : 
    4335              :                     // verify HP/tank source node connections
    4336           12 :                     if (HPWH.CondWaterInletNode != Tank.SourceOutletNode) {
    4337            0 :                         ShowSevereError(state, format("{} = {}:", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    4338            0 :                         ShowContinueError(state,
    4339              :                                           "Heat Pump condenser water inlet node name does not match water heater tank source outlet node name.");
    4340            0 :                         ShowContinueError(
    4341              :                             state,
    4342            0 :                             format("Heat pump condenser water inlet and outlet node names = {} and {}", HPWH.InletNodeName1, HPWH.OutletNodeName1));
    4343            0 :                         ShowContinueError(state,
    4344            0 :                                           format("Water heater tank source side inlet and outlet node names      = {} and {}",
    4345            0 :                                                  Tank.InletNodeName2,
    4346            0 :                                                  Tank.OutletNodeName2));
    4347            0 :                         ErrorsFound = true;
    4348              :                     }
    4349              : 
    4350           12 :                     if (HPWH.CondWaterOutletNode != Tank.SourceInletNode) {
    4351            0 :                         ShowSevereError(state, format("{} = {}:", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    4352            0 :                         ShowContinueError(state,
    4353              :                                           "Heat Pump condenser water outlet node name does not match water heater tank source inlet node name.");
    4354            0 :                         ShowContinueError(
    4355              :                             state,
    4356            0 :                             format("Heat pump condenser water inlet and outlet node names = {} and {}", HPWH.InletNodeName1, HPWH.OutletNodeName1));
    4357            0 :                         ShowContinueError(state,
    4358            0 :                                           format("Water heater tank source side inlet and outlet node names      = {} and {}",
    4359            0 :                                                  Tank.InletNodeName2,
    4360            0 :                                                  Tank.OutletNodeName2));
    4361            0 :                         ErrorsFound = true;
    4362              :                     }
    4363              : 
    4364              :                     // verify wrapped condenser location
    4365           12 :                     if (HPWH.HPWHType == DataPlant::PlantEquipmentType::HeatPumpWtrHeaterWrapped) {
    4366              :                         // make sure the top of the condenser is not above the tank height.
    4367            5 :                         if (HPWH.WrappedCondenserTopLocation > Tank.Height) {
    4368            0 :                             ShowSevereError(state, format("{} = {}:", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    4369            0 :                             ShowContinueError(state, "The height of the top of the wrapped condenser is greater than the height of the tank.");
    4370            0 :                             ErrorsFound = true;
    4371              :                         }
    4372              :                     }
    4373              : 
    4374              :                     // Verify tank name is in a zone equipment list if HPWH Inlet Air Configuration is Zone Air Only or Zone and Outdoor Air
    4375           12 :                     if (HPWH.InletAirConfiguration == WTTAmbientTemp::TempZone || HPWH.InletAirConfiguration == WTTAmbientTemp::ZoneAndOA) {
    4376            4 :                         if (allocated(state.dataZoneEquip->ZoneEquipConfig) && allocated(state.dataZoneEquip->ZoneEquipList)) {
    4377            1 :                             bool FoundTankInList = false;
    4378            1 :                             bool TankNotLowestPriority = false;
    4379            1 :                             int ZoneEquipConfigNum = HPWH.AmbientTempZone;
    4380            1 :                             int ZoneEquipListNum = state.dataZoneEquip->ZoneEquipConfig(ZoneEquipConfigNum).EquipListIndex;
    4381            1 :                             int TankCoolingPriority = 0;
    4382            1 :                             int TankHeatingPriority = 0;
    4383            1 :                             auto const &zoneEquipList = state.dataZoneEquip->ZoneEquipList(ZoneEquipListNum);
    4384            2 :                             for (int EquipmentTypeNum = 1; EquipmentTypeNum <= zoneEquipList.NumOfEquipTypes; ++EquipmentTypeNum) {
    4385            2 :                                 if (zoneEquipList.EquipName(EquipmentTypeNum) != HPWH.Name) continue;
    4386            1 :                                 FoundTankInList = true;
    4387            1 :                                 TankCoolingPriority = zoneEquipList.CoolingPriority(EquipmentTypeNum);
    4388            1 :                                 TankHeatingPriority = zoneEquipList.HeatingPriority(EquipmentTypeNum);
    4389            1 :                                 break;
    4390              :                             } // EquipmentTypeNum
    4391            1 :                             if (!FoundTankInList) {
    4392            0 :                                 ShowSevereError(state, format("{} = {}:", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    4393            0 :                                 ShowContinueError(state,
    4394              :                                                   "Heat pump water heater type and name must be listed in the correct "
    4395              :                                                   "ZoneHVAC:EquipmentList object when Inlet Air Configuration is equal to "
    4396              :                                                   "ZoneAirOnly or ZoneAndOutdoorAir.");
    4397            0 :                                 ErrorsFound = true;
    4398              :                             }
    4399              :                             //                     check that tank has lower priority than all other non-HPWH objects in Zone
    4400              :                             //                     Equipment List
    4401            3 :                             for (int EquipmentTypeNum = 1; EquipmentTypeNum <= zoneEquipList.NumOfEquipTypes; ++EquipmentTypeNum) {
    4402            2 :                                 if (Util::SameString(zoneEquipList.EquipTypeName(EquipmentTypeNum), state.dataIPShortCut->cCurrentModuleObject))
    4403            1 :                                     continue;
    4404            1 :                                 if (TankCoolingPriority > zoneEquipList.CoolingPriority(EquipmentTypeNum) ||
    4405            0 :                                     TankHeatingPriority > zoneEquipList.HeatingPriority(EquipmentTypeNum)) {
    4406            1 :                                     TankNotLowestPriority = true;
    4407              :                                 }
    4408              :                             } // EquipmentTypeNum
    4409            1 :                             if (TankNotLowestPriority && FoundTankInList) {
    4410            1 :                                 ShowWarningError(state, format("{} = {}:", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    4411            2 :                                 ShowContinueError(state,
    4412              :                                                   "Heat pump water heaters should be simulated first, before other space "
    4413              :                                                   "conditioning equipment.");
    4414            3 :                                 ShowContinueError(state,
    4415              :                                                   "Poor temperature control may result if the Heating/Cooling sequence number is "
    4416              :                                                   "not 1 in the ZoneHVAC:EquipmentList.");
    4417              :                             }
    4418              :                         } else {
    4419            3 :                             ShowSevereError(state, format("{} = {}:", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    4420            6 :                             ShowContinueError(state,
    4421              :                                               "ZoneHVAC:EquipmentList and ZoneHVAC:EquipmentConnections objects are required when Inlet Air "
    4422              :                                               "Configuration is either ZoneAirOnly or ZoneAndOutdoorAir.");
    4423            3 :                             ErrorsFound = true;
    4424              :                         } // ALLOCATED
    4425              :                     }     // InletAirConfiguration
    4426              : 
    4427           12 :                     if (Tank.WaterThermalTankType == DataPlant::PlantEquipmentType::WtrHeaterStratified) {
    4428              : 
    4429              :                         // Nodal heat distribution fraction for stratified tank wrapped condensers
    4430            6 :                         if (HPWH.HPWHType == DataPlant::PlantEquipmentType::HeatPumpWtrHeaterWrapped) {
    4431            5 :                             if (Tank.Shape == TankShape::HorizCylinder) {
    4432            0 :                                 ShowWarningError(state, format("{} = {}:", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    4433            0 :                                 ShowContinueError(state, "A wrapped condenser HPWH model should not be used with a horizontal stratified tank.");
    4434            0 :                                 ShowContinueError(
    4435              :                                     state, "Ignoring condenser location and distributing heat evenly throughout the tank. Simulation continues.");
    4436            0 :                                 Real64 const SameFrac = 1.0 / Tank.Nodes;
    4437            0 :                                 for (int NodeNum = 1; NodeNum <= Tank.Nodes; ++NodeNum) {
    4438            0 :                                     Tank.Node(NodeNum).HPWHWrappedCondenserHeatingFrac = SameFrac;
    4439              :                                 }
    4440              :                             } else {
    4441            5 :                                 Real64 H0 = Tank.Height; // height of top of node
    4442              :                                 Real64 H;                // height of bottom of node
    4443            5 :                                 Real64 SumFrac(0.0);
    4444              :                                 // Get the fraction of each stratified node that is wrapped by the condenser
    4445           59 :                                 for (int NodeNum = 1; NodeNum <= Tank.Nodes; ++NodeNum) {
    4446           54 :                                     StratifiedNodeData &CurNode = Tank.Node(NodeNum);
    4447           54 :                                     if (NodeNum == Tank.Nodes) {
    4448            5 :                                         H = 0.0;
    4449              :                                     } else {
    4450           49 :                                         H = H0 - CurNode.Height;
    4451              :                                     }
    4452           54 :                                     if (H < HPWH.WrappedCondenserBottomLocation && H0 > HPWH.WrappedCondenserBottomLocation) {
    4453              :                                         // The bottom of the condenser starts partway through this node.
    4454            5 :                                         CurNode.HPWHWrappedCondenserHeatingFrac = 1.0 - (HPWH.WrappedCondenserBottomLocation - H) / CurNode.Height;
    4455           49 :                                     } else if (H >= HPWH.WrappedCondenserBottomLocation && H <= HPWH.WrappedCondenserTopLocation) {
    4456           27 :                                         if (H0 > HPWH.WrappedCondenserTopLocation) {
    4457              :                                             // the top of the condenser ends partway through this node.
    4458            5 :                                             CurNode.HPWHWrappedCondenserHeatingFrac = (HPWH.WrappedCondenserTopLocation - H) / CurNode.Height;
    4459              :                                         } else {
    4460              :                                             // the entire node is wrapped by the condenser
    4461           22 :                                             CurNode.HPWHWrappedCondenserHeatingFrac = 1.0;
    4462              :                                         }
    4463              :                                     } else {
    4464           22 :                                         CurNode.HPWHWrappedCondenserHeatingFrac = 0.0;
    4465              :                                     }
    4466           54 :                                     SumFrac += CurNode.HPWHWrappedCondenserHeatingFrac;
    4467           54 :                                     H0 = H;
    4468              :                                 }
    4469              :                                 // Normalize the fractions so they sum to 1.
    4470           59 :                                 for (int NodeNum = 1; NodeNum <= Tank.Nodes; ++NodeNum) {
    4471           54 :                                     Tank.Node(NodeNum).HPWHWrappedCondenserHeatingFrac /= SumFrac;
    4472              :                                 }
    4473              :                             }
    4474              :                         }
    4475              : 
    4476              :                         // Stratified Tank HPWH control sensor node locations
    4477            6 :                         if (HPWH.ControlSensor1Height < 0.0) {
    4478              :                             // default to heater 1
    4479            1 :                             HPWH.ControlSensor1Height = Tank.HeaterHeight1;
    4480              :                         }
    4481            6 :                         if (HPWH.ControlSensor2Height < 0.0) {
    4482              :                             // default to heater 2
    4483            0 :                             HPWH.ControlSensor2Height = Tank.HeaterHeight2;
    4484              :                         }
    4485              : 
    4486              :                         // Get the vertical tank height depending on the type of tank
    4487              :                         Real64 TankHeight;
    4488            6 :                         if (Tank.Shape == TankShape::VertCylinder || Tank.Shape == TankShape::Other) {
    4489            6 :                             TankHeight = Tank.Height;
    4490              :                         } else {
    4491            0 :                             assert(Tank.Shape == TankShape::HorizCylinder);
    4492              :                             // For horizontal cylinders, the tank "height" is actually the length.
    4493              :                             // We need to calculate the height.
    4494            0 :                             Real64 EndArea = Tank.Volume / Tank.Height;
    4495            0 :                             Real64 Radius = std::sqrt(EndArea / Constant::Pi);
    4496            0 :                             TankHeight = 2.0 * Radius; // actual vertical height
    4497              :                         }
    4498              : 
    4499              :                         // Make sure the control sensor locations are in the tank
    4500            6 :                         if (HPWH.ControlSensor1Height < 0.0 || HPWH.ControlSensor1Height > TankHeight) {
    4501            0 :                             ShowSevereError(state, format("{} = {}:", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    4502            0 :                             ShowContinueError(state, "Control Sensor 1 is located outside the tank.");
    4503            0 :                             ErrorsFound = true;
    4504              :                         }
    4505            6 :                         if (HPWH.ControlSensor2Height < 0.0 || HPWH.ControlSensor2Height > TankHeight) {
    4506            0 :                             ShowSevereError(state, format("{} = {}:", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    4507            0 :                             ShowContinueError(state, "Control Sensor 2 is located outside the tank.");
    4508            0 :                             ErrorsFound = true;
    4509              :                         }
    4510              : 
    4511              :                         // Assign the control sensors to the appropriate nodes
    4512            6 :                         Real64 H0 = TankHeight;
    4513              :                         Real64 H;
    4514           72 :                         for (int NodeNum = 1; NodeNum <= Tank.Nodes; ++NodeNum) {
    4515           66 :                             StratifiedNodeData const &TankNode = Tank.Node(NodeNum);
    4516           66 :                             if (NodeNum == Tank.Nodes) {
    4517            6 :                                 H = -1.0; // Avoids rounding errors and ensures that anything at height 0.0 goes into the bottom node
    4518              :                             } else {
    4519           60 :                                 H = H0 - TankNode.Height;
    4520              :                             }
    4521              : 
    4522              :                             // Control Sensor 1 Node
    4523           66 :                             if (HPWH.ControlSensor1Height <= H0 && HPWH.ControlSensor1Height > H) {
    4524            6 :                                 HPWH.ControlSensor1Node = NodeNum;
    4525              :                             }
    4526              : 
    4527              :                             // Control Sensor 2 Node
    4528           66 :                             if (HPWH.ControlSensor2Height <= H0 && HPWH.ControlSensor2Height > H) {
    4529            6 :                                 HPWH.ControlSensor2Node = NodeNum;
    4530              :                             }
    4531              : 
    4532           66 :                             H0 = H;
    4533              :                         }
    4534              :                     }
    4535              : 
    4536              :                 } // DO CheckWaterHeaterNum = 1, NumWaterHeater
    4537              : 
    4538           12 :                 if (!HPWH.FoundTank) {
    4539            0 :                     ShowSevereError(state, format("{} = {}:", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    4540            0 :                     ShowContinueError(state, format("Water heater tank object not found = {}, {}", HPWH.TankType, HPWH.TankName));
    4541            0 :                     ErrorsFound = true;
    4542              :                 }
    4543              : 
    4544              :             } // DO HPWaterHeaterNum = 1, NumHeatPumpWaterHeater
    4545              :         }
    4546              : 
    4547              :         // Get water heater sizing input.
    4548           72 :         state.dataIPShortCut->cCurrentModuleObject = "WaterHeater:Sizing";
    4549          144 :         state.dataWaterThermalTanks->numWaterHeaterSizing =
    4550           72 :             state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, state.dataIPShortCut->cCurrentModuleObject);
    4551              : 
    4552           72 :         if (state.dataWaterThermalTanks->numWaterHeaterSizing > 0) {
    4553              : 
    4554            2 :             for (int WHsizingNum = 1; WHsizingNum <= state.dataWaterThermalTanks->numWaterHeaterSizing; ++WHsizingNum) {
    4555              :                 int NumAlphas;
    4556              :                 int NumNums;
    4557              :                 int IOStat;
    4558            2 :                 state.dataInputProcessing->inputProcessor->getObjectItem(state,
    4559            1 :                                                                          state.dataIPShortCut->cCurrentModuleObject,
    4560              :                                                                          WHsizingNum,
    4561            1 :                                                                          state.dataIPShortCut->cAlphaArgs,
    4562              :                                                                          NumAlphas,
    4563            1 :                                                                          state.dataIPShortCut->rNumericArgs,
    4564              :                                                                          NumNums,
    4565              :                                                                          IOStat);
    4566              : 
    4567              :                 // find which water heater this object is for
    4568            1 :                 int WaterThermalTankNum = Util::FindItemInList(state.dataIPShortCut->cAlphaArgs(1), state.dataWaterThermalTanks->WaterThermalTank);
    4569            1 :                 if (WaterThermalTankNum == 0) {
    4570              :                     // did not match name throw warning.
    4571            0 :                     ShowSevereError(state,
    4572            0 :                                     format("{} object name: {} does not match any of the water heaters defined in the file",
    4573            0 :                                            state.dataIPShortCut->cCurrentModuleObject,
    4574            0 :                                            state.dataIPShortCut->cAlphaArgs(1)));
    4575            0 :                     ErrorsFound = true;
    4576            0 :                     continue;
    4577              :                 } else { // we have a match
    4578              :                     // store the sizing data in "sizing" nested derived type for the correct water heater
    4579              : 
    4580            1 :                     if (Util::SameString(state.dataIPShortCut->cAlphaArgs(2), "PeakDraw")) {
    4581            0 :                         state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.DesignMode = SizingMode::PeakDraw;
    4582            1 :                     } else if (Util::SameString(state.dataIPShortCut->cAlphaArgs(2), "ResidentialHUD-FHAMinimum")) {
    4583            0 :                         state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.DesignMode = SizingMode::ResidentialMin;
    4584            1 :                     } else if (Util::SameString(state.dataIPShortCut->cAlphaArgs(2), "PerPerson")) {
    4585            0 :                         state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.DesignMode = SizingMode::PerPerson;
    4586            1 :                     } else if (Util::SameString(state.dataIPShortCut->cAlphaArgs(2), "PerFloorArea")) {
    4587            0 :                         state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.DesignMode = SizingMode::PerFloorArea;
    4588            1 :                     } else if (Util::SameString(state.dataIPShortCut->cAlphaArgs(2), "PerUnit")) {
    4589            0 :                         state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.DesignMode = SizingMode::PerUnit;
    4590            1 :                     } else if (Util::SameString(state.dataIPShortCut->cAlphaArgs(2), "PerSolarCollectorArea")) {
    4591            1 :                         state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.DesignMode = SizingMode::PerSolarColArea;
    4592              :                     } else {
    4593              :                         // wrong design mode entered, throw error
    4594            0 :                         ShowSevereError(state,
    4595            0 :                                         format("{} object named: {} contains an incorrect Design Mode of: {}",
    4596            0 :                                                state.dataIPShortCut->cCurrentModuleObject,
    4597            0 :                                                state.dataIPShortCut->cAlphaArgs(1),
    4598            0 :                                                state.dataIPShortCut->cAlphaArgs(2)));
    4599            0 :                         ErrorsFound = true;
    4600              :                     }
    4601              : 
    4602            1 :                     state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.TankDrawTime = state.dataIPShortCut->rNumericArgs(1);
    4603            1 :                     state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.RecoveryTime = state.dataIPShortCut->rNumericArgs(2);
    4604            1 :                     state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.NominalVolForSizingDemandSideFlow =
    4605            1 :                         state.dataIPShortCut->rNumericArgs(3);
    4606            1 :                     state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.NumberOfBedrooms =
    4607            1 :                         int(state.dataIPShortCut->rNumericArgs(4));
    4608            1 :                     state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.NumberOfBathrooms =
    4609            1 :                         int(state.dataIPShortCut->rNumericArgs(5));
    4610            1 :                     state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.TankCapacityPerPerson =
    4611            1 :                         state.dataIPShortCut->rNumericArgs(6);
    4612            1 :                     state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.RecoveryCapacityPerPerson =
    4613            1 :                         state.dataIPShortCut->rNumericArgs(7);
    4614            1 :                     state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.TankCapacityPerArea =
    4615            1 :                         state.dataIPShortCut->rNumericArgs(8);
    4616            1 :                     state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.RecoveryCapacityPerArea =
    4617            1 :                         state.dataIPShortCut->rNumericArgs(9);
    4618            1 :                     state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.NumberOfUnits = state.dataIPShortCut->rNumericArgs(10);
    4619            1 :                     state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.TankCapacityPerUnit =
    4620            1 :                         state.dataIPShortCut->rNumericArgs(11);
    4621            1 :                     state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.RecoveryCapacityPerUnit =
    4622            1 :                         state.dataIPShortCut->rNumericArgs(12);
    4623            1 :                     state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.TankCapacityPerCollectorArea =
    4624            1 :                         state.dataIPShortCut->rNumericArgs(13);
    4625            1 :                     state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.HeightAspectRatio =
    4626            1 :                         state.dataIPShortCut->rNumericArgs(14);
    4627              : 
    4628            1 :                     switch (state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.DesignMode) {
    4629              : 
    4630            0 :                     case SizingMode::Invalid: {
    4631              :                         // do nothing, error thrown if design mode not found
    4632            0 :                         break;
    4633              :                     }
    4634            0 :                     case SizingMode::PeakDraw: { // need to have entered a reasonable value for TankDrawTime
    4635            0 :                         if (state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.TankDrawTime <= 0.0) {
    4636            0 :                             ShowSevereError(state,
    4637            0 :                                             format("{}, named {}, design mode set to Peak Draw but needs a positive value for tank draw time",
    4638            0 :                                                    state.dataIPShortCut->cCurrentModuleObject,
    4639            0 :                                                    state.dataIPShortCut->cAlphaArgs(1)));
    4640            0 :                             ErrorsFound = true;
    4641              :                         }
    4642              :                         // constrain crazy sizes by limiting to 10 years or 8760*10
    4643            0 :                         if (state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.TankDrawTime > 87600.0) {
    4644            0 :                             ShowWarningError(state,
    4645            0 :                                              format("{}, named {},  has input with an unreasonably large Tank Draw Time, more than 10 years",
    4646            0 :                                                     state.dataIPShortCut->cCurrentModuleObject,
    4647            0 :                                                     state.dataIPShortCut->cAlphaArgs(1)));
    4648            0 :                             ErrorsFound = true;
    4649              :                         }
    4650              :                         // if both volume and demand side flow connections are autosized, must be a good NominalVolForSizingDemandSideFlow
    4651            0 :                         if ((state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).UseSidePlantLoc.loopSideNum ==
    4652            0 :                              DataPlant::LoopSideLocation::Demand) &&
    4653            0 :                             (state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).UseDesignVolFlowRateWasAutoSized)) {
    4654            0 :                             if (state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.NominalVolForSizingDemandSideFlow <= 0.0) {
    4655            0 :                                 ShowWarningError(state,
    4656            0 :                                                  format("{}, named {} needs a value for Nominal Tank Volume for Autosizing Plant Connections",
    4657            0 :                                                         state.dataIPShortCut->cCurrentModuleObject,
    4658            0 :                                                         state.dataIPShortCut->cAlphaArgs(1)));
    4659            0 :                                 ErrorsFound = true;
    4660              :                             }
    4661              :                         }
    4662            0 :                         if ((state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).SrcSidePlantLoc.loopSideNum ==
    4663            0 :                              DataPlant::LoopSideLocation::Demand) &&
    4664            0 :                             (state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).SourceDesignVolFlowRateWasAutoSized)) {
    4665            0 :                             if (state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.NominalVolForSizingDemandSideFlow <= 0.0) {
    4666            0 :                                 ShowWarningError(state,
    4667            0 :                                                  format("{}, named {} needs a value for Nominal Tank Volume for Autosizing Plant Connections",
    4668            0 :                                                         state.dataIPShortCut->cCurrentModuleObject,
    4669            0 :                                                         state.dataIPShortCut->cAlphaArgs(1)));
    4670            0 :                                 ErrorsFound = true;
    4671              :                             }
    4672              :                         }
    4673              : 
    4674            0 :                         break;
    4675              :                     }
    4676            0 :                     case SizingMode::ResidentialMin: {
    4677              :                         // it would have to have at least on bedroom and any more than 10 is crazy for this mode
    4678            0 :                         if (state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.NumberOfBedrooms < 1) {
    4679            0 :                             ShowSevereError(state,
    4680            0 :                                             format("{}, named {}, mode needs at least one bedroom",
    4681            0 :                                                    state.dataIPShortCut->cCurrentModuleObject,
    4682            0 :                                                    state.dataIPShortCut->cAlphaArgs(1)));
    4683            0 :                             ErrorsFound = true;
    4684              :                         }
    4685            0 :                         if (state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.NumberOfBedrooms > 10) {
    4686            0 :                             ShowWarningError(state,
    4687            0 :                                              format("{}, named {}, probably has too many bedrooms for the selected design mode",
    4688            0 :                                                     state.dataIPShortCut->cCurrentModuleObject,
    4689            0 :                                                     state.dataIPShortCut->cAlphaArgs(1)));
    4690              :                         }
    4691              : 
    4692            0 :                         break;
    4693              :                     }
    4694            0 :                     case SizingMode::PerPerson: {
    4695              : 
    4696            0 :                         if ((state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).VolumeWasAutoSized) &&
    4697            0 :                             (state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.TankCapacityPerPerson <= 0.0)) {
    4698            0 :                             ShowSevereError(state,
    4699            0 :                                             format("{}, named {}, PerPerson mode needs positive value input for storage capacity per person",
    4700            0 :                                                    state.dataIPShortCut->cCurrentModuleObject,
    4701            0 :                                                    state.dataIPShortCut->cAlphaArgs(1)));
    4702            0 :                             ErrorsFound = true;
    4703              :                         }
    4704              : 
    4705            0 :                         if ((state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).MaxCapacityWasAutoSized) &&
    4706            0 :                             (state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.RecoveryCapacityPerPerson <= 0.0)) {
    4707            0 :                             ShowSevereError(state,
    4708            0 :                                             format("{}, named {}, PerPerson mode needs positive value input for recovery capacity per person",
    4709            0 :                                                    state.dataIPShortCut->cCurrentModuleObject,
    4710            0 :                                                    state.dataIPShortCut->cAlphaArgs(1)));
    4711            0 :                             ErrorsFound = true;
    4712              :                         }
    4713              : 
    4714            0 :                         break;
    4715              :                     }
    4716            0 :                     case SizingMode::PerFloorArea: {
    4717            0 :                         if ((state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).VolumeWasAutoSized) &&
    4718            0 :                             (state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.TankCapacityPerArea <= 0.0)) {
    4719            0 :                             ShowSevereError(state,
    4720            0 :                                             format("{}, named {}, PerArea mode needs positive value input for storage capacity per floor area",
    4721            0 :                                                    state.dataIPShortCut->cCurrentModuleObject,
    4722            0 :                                                    state.dataIPShortCut->cAlphaArgs(1)));
    4723            0 :                             ErrorsFound = true;
    4724              :                         }
    4725            0 :                         if ((state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).MaxCapacityWasAutoSized) &&
    4726            0 :                             (state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.RecoveryCapacityPerArea <= 0.0)) {
    4727            0 :                             ShowSevereError(state,
    4728            0 :                                             format("{}, named {}, PerArea mode needs positive value input for recovery capacity per floor area",
    4729            0 :                                                    state.dataIPShortCut->cCurrentModuleObject,
    4730            0 :                                                    state.dataIPShortCut->cAlphaArgs(1)));
    4731            0 :                             ErrorsFound = true;
    4732              :                         }
    4733              : 
    4734            0 :                         break;
    4735              :                     }
    4736            0 :                     case SizingMode::PerUnit: {
    4737            0 :                         if ((state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).VolumeWasAutoSized) &&
    4738            0 :                             (state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.TankCapacityPerUnit <= 0.0)) {
    4739            0 :                             ShowSevereError(state,
    4740            0 :                                             format("{}, named {}, PerUnit mode needs positive value input for storage capacity per unit",
    4741            0 :                                                    state.dataIPShortCut->cCurrentModuleObject,
    4742            0 :                                                    state.dataIPShortCut->cAlphaArgs(1)));
    4743            0 :                             ErrorsFound = true;
    4744              :                         }
    4745            0 :                         if ((state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).VolumeWasAutoSized) &&
    4746            0 :                             (state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.NumberOfUnits <= 0.0)) {
    4747            0 :                             ShowSevereError(state,
    4748            0 :                                             format("{}, named {}, PerUnit mode needs positive value input for number of units",
    4749            0 :                                                    state.dataIPShortCut->cCurrentModuleObject,
    4750            0 :                                                    state.dataIPShortCut->cAlphaArgs(1)));
    4751            0 :                             ErrorsFound = true;
    4752              :                         }
    4753            0 :                         if ((state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).MaxCapacityWasAutoSized) &&
    4754            0 :                             (state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.RecoveryCapacityPerUnit <= 0.0)) {
    4755            0 :                             ShowSevereError(state,
    4756            0 :                                             format("{}, named {}, PerUnit mode needs positive value input for recovery capacity per unit",
    4757            0 :                                                    state.dataIPShortCut->cCurrentModuleObject,
    4758            0 :                                                    state.dataIPShortCut->cAlphaArgs(1)));
    4759            0 :                             ErrorsFound = true;
    4760              :                         }
    4761            0 :                         if ((state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).MaxCapacityWasAutoSized) &&
    4762            0 :                             (state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.NumberOfUnits <= 0.0)) {
    4763            0 :                             ShowSevereError(state,
    4764            0 :                                             format("{}, named {}, PerUnit mode needs positive value input for number of units",
    4765            0 :                                                    state.dataIPShortCut->cCurrentModuleObject,
    4766            0 :                                                    state.dataIPShortCut->cAlphaArgs(1)));
    4767            0 :                             ErrorsFound = true;
    4768              :                         }
    4769            0 :                         break;
    4770              :                     }
    4771            1 :                     case SizingMode::PerSolarColArea: {
    4772            2 :                         if ((state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).VolumeWasAutoSized) &&
    4773            1 :                             (state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.TankCapacityPerCollectorArea <= 0.0)) {
    4774            0 :                             ShowSevereError(
    4775              :                                 state,
    4776            0 :                                 format("{}, named {}, PerSolarCollectorArea mode needs positive value input for storage capacity per collector area",
    4777            0 :                                        state.dataIPShortCut->cCurrentModuleObject,
    4778            0 :                                        state.dataIPShortCut->cAlphaArgs(1)));
    4779            0 :                             ErrorsFound = true;
    4780              :                         }
    4781            1 :                         break;
    4782              :                     }
    4783            0 :                     default:
    4784            0 :                         break;
    4785              :                     }
    4786              : 
    4787              :                 } // found water heater num okay
    4788              :             }     // loop over sizing objects
    4789              : 
    4790              :         } // any water heater sizing objects
    4791              : 
    4792              :         // now check that if water heater fields were autosized, that there was also a sizing object for that water heater
    4793           72 :         if (state.dataWaterThermalTanks->numWaterThermalTank > 0) {
    4794           58 :             for (int WaterThermalTankNum = 1; WaterThermalTankNum <= state.dataWaterThermalTanks->numWaterThermalTank; ++WaterThermalTankNum) {
    4795              : 
    4796           32 :                 if ((state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).VolumeWasAutoSized) &&
    4797            1 :                     (state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.DesignMode == SizingMode::Invalid)) {
    4798            0 :                     ShowWarningError(
    4799              :                         state,
    4800            0 :                         format("Water heater named {}has tank volume set to AUTOSIZE but it is missing associated WaterHeater:Sizing object",
    4801            0 :                                state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Name));
    4802            0 :                     ErrorsFound = true;
    4803              :                 }
    4804           31 :                 if ((state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).MaxCapacityWasAutoSized) &&
    4805            0 :                     (state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.DesignMode == SizingMode::Invalid)) {
    4806            0 :                     ShowWarningError(
    4807              :                         state,
    4808            0 :                         format("Water heater named {}has heater capacity set to AUTOSIZE but it is missing associated WaterHeater:Sizing object",
    4809            0 :                                state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Name));
    4810            0 :                     ErrorsFound = true;
    4811              :                 }
    4812           31 :                 if ((state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).HeightWasAutoSized) &&
    4813            0 :                     (state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.DesignMode == SizingMode::Invalid)) {
    4814            0 :                     ShowWarningError(
    4815              :                         state,
    4816            0 :                         format("Water heater named {}has tank height set to AUTOSIZE but it is missing associated WaterHeater:Sizing object",
    4817            0 :                                state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Name));
    4818            0 :                     ErrorsFound = true;
    4819              :                 }
    4820              :             }
    4821              :         }
    4822              : 
    4823              :         //    now do calls to TestCompSet for tanks, depending on nodes and heat pump water heater
    4824           72 :         if (state.dataWaterThermalTanks->numWaterThermalTank > 0) {
    4825           58 :             for (int WaterThermalTankNum = 1; WaterThermalTankNum <= state.dataWaterThermalTanks->numWaterThermalTank; ++WaterThermalTankNum) {
    4826           40 :                 if (state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).UseInletNode > 0 &&
    4827            9 :                     state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).UseOutletNode > 0) {
    4828            9 :                     if (state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).HeatPumpNum > 0) {
    4829              :                         // do nothing, Use nodes are tested for HeatPump:WaterHeater not tank
    4830              :                     } else {
    4831            6 :                         BranchNodeConnections::TestCompSet(state,
    4832            2 :                                                            state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Type,
    4833            2 :                                                            state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Name,
    4834            2 :                                                            state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).InletNodeName1,
    4835            2 :                                                            state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).OutletNodeName1,
    4836              :                                                            "Use Side Water Nodes");
    4837              :                     }
    4838              :                 }
    4839           53 :                 if (state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).SourceInletNode > 0 &&
    4840           22 :                     state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).SourceOutletNode > 0) {
    4841              : 
    4842           66 :                     BranchNodeConnections::TestCompSet(state,
    4843           22 :                                                        state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Type,
    4844           22 :                                                        state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Name,
    4845           22 :                                                        state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).InletNodeName2,
    4846           22 :                                                        state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).OutletNodeName2,
    4847              :                                                        "Source Side Water Nodes");
    4848              :                 }
    4849              :             }
    4850              :         }
    4851              : 
    4852           72 :         if (state.dataWaterThermalTanks->numWaterThermalTank > 0) {
    4853           58 :             for (int WaterThermalTankNum = 1; WaterThermalTankNum <= state.dataWaterThermalTanks->numWaterThermalTank; ++WaterThermalTankNum) {
    4854              : 
    4855           31 :                 state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).setupZoneInternalGains(state);
    4856              : 
    4857              :             } // WaterThermalTankNum
    4858              :         }
    4859              :     } // get input flag
    4860              : 
    4861           72 :     return ErrorsFound;
    4862              : }
    4863              : 
    4864            1 : void WaterThermalTankData::setupOutputVars(EnergyPlusData &state)
    4865              : {
    4866            1 :     if ((this->WaterThermalTankType == DataPlant::PlantEquipmentType::ChilledWaterTankMixed) ||
    4867            1 :         (this->WaterThermalTankType == DataPlant::PlantEquipmentType::ChilledWaterTankStratified)) {
    4868            0 :         this->setupChilledWaterTankOutputVars(state);
    4869              :     } else {
    4870              :         // moving setupWaterHeaterOutputVars to here causes big table diffs...
    4871            1 :         this->setupWaterHeaterOutputVars(state);
    4872              :     }
    4873              :     // moving setupZoneInternalGains to here causes math and table diffs...
    4874              :     // this->setupZoneInternalGains();
    4875            1 : }
    4876              : 
    4877            0 : void WaterThermalTankData::setupChilledWaterTankOutputVars(EnergyPlusData &state)
    4878              : {
    4879              : 
    4880              :     // CurrentModuleObject='ThermalStorage:ChilledWater:Mixed/ThermalStorage:ChilledWater:Stratified'
    4881            0 :     SetupOutputVariable(state,
    4882              :                         "Chilled Water Thermal Storage Tank Temperature",
    4883              :                         Constant::Units::C,
    4884            0 :                         this->TankTempAvg,
    4885              :                         OutputProcessor::TimeStepType::System,
    4886              :                         OutputProcessor::StoreType::Average,
    4887            0 :                         this->Name);
    4888              : 
    4889            0 :     SetupOutputVariable(state,
    4890              :                         "Chilled Water Thermal Storage Final Tank Temperature",
    4891              :                         Constant::Units::C,
    4892            0 :                         this->TankTemp,
    4893              :                         OutputProcessor::TimeStepType::System,
    4894              :                         OutputProcessor::StoreType::Average,
    4895            0 :                         this->Name);
    4896              : 
    4897            0 :     SetupOutputVariable(state,
    4898              :                         "Chilled Water Thermal Storage Tank Heat Gain Rate",
    4899              :                         Constant::Units::W,
    4900            0 :                         this->LossRate,
    4901              :                         OutputProcessor::TimeStepType::System,
    4902              :                         OutputProcessor::StoreType::Average,
    4903            0 :                         this->Name);
    4904            0 :     SetupOutputVariable(state,
    4905              :                         "Chilled Water Thermal Storage Tank Heat Gain Energy",
    4906              :                         Constant::Units::J,
    4907            0 :                         this->LossEnergy,
    4908              :                         OutputProcessor::TimeStepType::System,
    4909              :                         OutputProcessor::StoreType::Sum,
    4910            0 :                         this->Name);
    4911              : 
    4912            0 :     SetupOutputVariable(state,
    4913              :                         "Chilled Water Thermal Storage Use Side Mass Flow Rate",
    4914              :                         Constant::Units::kg_s,
    4915            0 :                         this->UseMassFlowRate,
    4916              :                         OutputProcessor::TimeStepType::System,
    4917              :                         OutputProcessor::StoreType::Average,
    4918            0 :                         this->Name);
    4919              : 
    4920            0 :     SetupOutputVariable(state,
    4921              :                         "Chilled Water Thermal Storage Use Side Inlet Temperature",
    4922              :                         Constant::Units::C,
    4923            0 :                         this->UseInletTemp,
    4924              :                         OutputProcessor::TimeStepType::System,
    4925              :                         OutputProcessor::StoreType::Average,
    4926            0 :                         this->Name);
    4927              : 
    4928            0 :     SetupOutputVariable(state,
    4929              :                         "Chilled Water Thermal Storage Use Side Outlet Temperature",
    4930              :                         Constant::Units::C,
    4931            0 :                         this->UseOutletTemp,
    4932              :                         OutputProcessor::TimeStepType::System,
    4933              :                         OutputProcessor::StoreType::Average,
    4934            0 :                         this->Name);
    4935              : 
    4936            0 :     SetupOutputVariable(state,
    4937              :                         "Chilled Water Thermal Storage Use Side Heat Transfer Rate",
    4938              :                         Constant::Units::W,
    4939            0 :                         this->UseRate,
    4940              :                         OutputProcessor::TimeStepType::System,
    4941              :                         OutputProcessor::StoreType::Average,
    4942            0 :                         this->Name);
    4943            0 :     SetupOutputVariable(state,
    4944              :                         "Chilled Water Thermal Storage Use Side Heat Transfer Energy",
    4945              :                         Constant::Units::J,
    4946            0 :                         this->UseEnergy,
    4947              :                         OutputProcessor::TimeStepType::System,
    4948              :                         OutputProcessor::StoreType::Sum,
    4949            0 :                         this->Name);
    4950              : 
    4951            0 :     SetupOutputVariable(state,
    4952              :                         "Chilled Water Thermal Storage Source Side Mass Flow Rate",
    4953              :                         Constant::Units::kg_s,
    4954            0 :                         this->SourceMassFlowRate,
    4955              :                         OutputProcessor::TimeStepType::System,
    4956              :                         OutputProcessor::StoreType::Average,
    4957            0 :                         this->Name);
    4958              : 
    4959            0 :     SetupOutputVariable(state,
    4960              :                         "Chilled Water Thermal Storage Source Side Inlet Temperature",
    4961              :                         Constant::Units::C,
    4962            0 :                         this->SourceInletTemp,
    4963              :                         OutputProcessor::TimeStepType::System,
    4964              :                         OutputProcessor::StoreType::Average,
    4965            0 :                         this->Name);
    4966              : 
    4967            0 :     SetupOutputVariable(state,
    4968              :                         "Chilled Water Thermal Storage Source Side Outlet Temperature",
    4969              :                         Constant::Units::C,
    4970            0 :                         this->SourceOutletTemp,
    4971              :                         OutputProcessor::TimeStepType::System,
    4972              :                         OutputProcessor::StoreType::Average,
    4973            0 :                         this->Name);
    4974              : 
    4975            0 :     SetupOutputVariable(state,
    4976              :                         "Chilled Water Thermal Storage Source Side Heat Transfer Rate",
    4977              :                         Constant::Units::W,
    4978            0 :                         this->SourceRate,
    4979              :                         OutputProcessor::TimeStepType::System,
    4980              :                         OutputProcessor::StoreType::Average,
    4981            0 :                         this->Name);
    4982            0 :     SetupOutputVariable(state,
    4983              :                         "Chilled Water Thermal Storage Source Side Heat Transfer Energy",
    4984              :                         Constant::Units::J,
    4985            0 :                         this->SourceEnergy,
    4986              :                         OutputProcessor::TimeStepType::System,
    4987              :                         OutputProcessor::StoreType::Sum,
    4988            0 :                         this->Name);
    4989              : 
    4990            0 :     if (this->WaterThermalTankType == DataPlant::PlantEquipmentType::ChilledWaterTankStratified) {
    4991              : 
    4992            0 :         for (int NodeNum = 1; NodeNum <= this->Nodes; ++NodeNum) {
    4993            0 :             SetupOutputVariable(state,
    4994            0 :                                 format("Chilled Water Thermal Storage Temperature Node {}", NodeNum),
    4995              :                                 Constant::Units::C,
    4996            0 :                                 this->Node(NodeNum).TempAvg,
    4997              :                                 OutputProcessor::TimeStepType::System,
    4998              :                                 OutputProcessor::StoreType::Average,
    4999            0 :                                 this->Name);
    5000              :         }
    5001              : 
    5002            0 :         for (int NodeNum = 1; NodeNum <= this->Nodes; ++NodeNum) {
    5003            0 :             SetupOutputVariable(state,
    5004            0 :                                 format("Chilled Water Thermal Storage Final Temperature Node {}", NodeNum),
    5005              :                                 Constant::Units::C,
    5006            0 :                                 this->Node(NodeNum).Temp,
    5007              :                                 OutputProcessor::TimeStepType::System,
    5008              :                                 OutputProcessor::StoreType::Average,
    5009            0 :                                 this->Name);
    5010              :         }
    5011              :     }
    5012              : 
    5013            0 :     if (this->WaterThermalTankType == DataPlant::PlantEquipmentType::ChilledWaterTankStratified) {
    5014              : 
    5015            0 :         for (int NodeNum = 1; NodeNum <= this->Nodes; ++NodeNum) {
    5016              :             static constexpr std::string_view Format_724("Chilled Water Tank Stratified Node Information,{},{:.4T},{:.4T},{:.4T},{},{}\n");
    5017              : 
    5018            0 :             print(state.files.eio,
    5019              :                   Format_724,
    5020              :                   NodeNum,
    5021            0 :                   this->Node(NodeNum).Height,
    5022            0 :                   this->Node(NodeNum).Volume,
    5023            0 :                   this->Node(NodeNum).OffCycLossCoeff,
    5024            0 :                   this->Node(NodeNum).Inlets,
    5025            0 :                   this->Node(NodeNum).Outlets);
    5026              :         }
    5027              :     }
    5028            0 : }
    5029              : 
    5030           31 : void WaterThermalTankData::setupZoneInternalGains(EnergyPlusData &state)
    5031              : {
    5032              :     // set up internal gains if tank is in a thermal zone
    5033           31 :     if (this->AmbientTempZone > 0) {
    5034            3 :         switch (this->WaterThermalTankType) {
    5035            2 :         case DataPlant::PlantEquipmentType::WtrHeaterMixed: {
    5036            2 :             SetupZoneInternalGain(state, this->AmbientTempZone, this->Name, DataHeatBalance::IntGainType::WaterHeaterMixed, &this->AmbientZoneGain);
    5037            2 :             break;
    5038              :         }
    5039            0 :         case DataPlant::PlantEquipmentType::WtrHeaterStratified: {
    5040            0 :             SetupZoneInternalGain(
    5041              :                 state, this->AmbientTempZone, this->Name, DataHeatBalance::IntGainType::WaterHeaterStratified, &this->AmbientZoneGain);
    5042            0 :             break;
    5043              :         }
    5044            0 :         case DataPlant::PlantEquipmentType::ChilledWaterTankMixed: {
    5045            0 :             SetupZoneInternalGain(
    5046              :                 state, this->AmbientTempZone, this->Name, DataHeatBalance::IntGainType::ThermalStorageChilledWaterMixed, &this->AmbientZoneGain);
    5047            0 :             break;
    5048              :         }
    5049            1 :         case DataPlant::PlantEquipmentType::ChilledWaterTankStratified: {
    5050            1 :             SetupZoneInternalGain(
    5051              :                 state, this->AmbientTempZone, this->Name, DataHeatBalance::IntGainType::ThermalStorageChilledWaterStratified, &this->AmbientZoneGain);
    5052            1 :             break;
    5053              :         }
    5054            0 :         default:
    5055            0 :             break;
    5056              :         }
    5057              :     }
    5058           31 : }
    5059              : 
    5060            1 : void WaterThermalTankData::setupWaterHeaterOutputVars(EnergyPlusData &state)
    5061              : {
    5062              : 
    5063              :     // Setup report variables for WaterHeater:Mixed
    5064              :     // CurrentModuleObject='WaterHeater:Mixed'
    5065            2 :     SetupOutputVariable(state,
    5066              :                         "Water Heater Tank Temperature",
    5067              :                         Constant::Units::C,
    5068            1 :                         this->TankTempAvg,
    5069              :                         OutputProcessor::TimeStepType::System,
    5070              :                         OutputProcessor::StoreType::Average,
    5071            1 :                         this->Name);
    5072              : 
    5073            2 :     SetupOutputVariable(state,
    5074              :                         "Water Heater Final Tank Temperature",
    5075              :                         Constant::Units::C,
    5076            1 :                         this->TankTemp,
    5077              :                         OutputProcessor::TimeStepType::System,
    5078              :                         OutputProcessor::StoreType::Average,
    5079            1 :                         this->Name);
    5080              : 
    5081            2 :     SetupOutputVariable(state,
    5082              :                         "Water Heater Heat Loss Rate",
    5083              :                         Constant::Units::W,
    5084            1 :                         this->LossRate,
    5085              :                         OutputProcessor::TimeStepType::System,
    5086              :                         OutputProcessor::StoreType::Average,
    5087            1 :                         this->Name);
    5088            2 :     SetupOutputVariable(state,
    5089              :                         "Water Heater Heat Loss Energy",
    5090              :                         Constant::Units::J,
    5091            1 :                         this->LossEnergy,
    5092              :                         OutputProcessor::TimeStepType::System,
    5093              :                         OutputProcessor::StoreType::Sum,
    5094            1 :                         this->Name);
    5095              : 
    5096            2 :     SetupOutputVariable(state,
    5097              :                         "Water Heater Use Side Mass Flow Rate",
    5098              :                         Constant::Units::kg_s,
    5099            1 :                         this->UseMassFlowRate,
    5100              :                         OutputProcessor::TimeStepType::System,
    5101              :                         OutputProcessor::StoreType::Average,
    5102            1 :                         this->Name);
    5103              : 
    5104            2 :     SetupOutputVariable(state,
    5105              :                         "Water Heater Use Side Inlet Temperature",
    5106              :                         Constant::Units::C,
    5107            1 :                         this->UseInletTemp,
    5108              :                         OutputProcessor::TimeStepType::System,
    5109              :                         OutputProcessor::StoreType::Average,
    5110            1 :                         this->Name);
    5111              : 
    5112            2 :     SetupOutputVariable(state,
    5113              :                         "Water Heater Use Side Outlet Temperature",
    5114              :                         Constant::Units::C,
    5115            1 :                         this->UseOutletTemp,
    5116              :                         OutputProcessor::TimeStepType::System,
    5117              :                         OutputProcessor::StoreType::Average,
    5118            1 :                         this->Name);
    5119              : 
    5120            2 :     SetupOutputVariable(state,
    5121              :                         "Water Heater Use Side Heat Transfer Rate",
    5122              :                         Constant::Units::W,
    5123            1 :                         this->UseRate,
    5124              :                         OutputProcessor::TimeStepType::System,
    5125              :                         OutputProcessor::StoreType::Average,
    5126            1 :                         this->Name);
    5127            2 :     SetupOutputVariable(state,
    5128              :                         "Water Heater Use Side Heat Transfer Energy",
    5129              :                         Constant::Units::J,
    5130            1 :                         this->UseEnergy,
    5131              :                         OutputProcessor::TimeStepType::System,
    5132              :                         OutputProcessor::StoreType::Sum,
    5133            1 :                         this->Name);
    5134              : 
    5135            2 :     SetupOutputVariable(state,
    5136              :                         "Water Heater Source Side Mass Flow Rate",
    5137              :                         Constant::Units::kg_s,
    5138            1 :                         this->SourceMassFlowRate,
    5139              :                         OutputProcessor::TimeStepType::System,
    5140              :                         OutputProcessor::StoreType::Average,
    5141            1 :                         this->Name);
    5142              : 
    5143            2 :     SetupOutputVariable(state,
    5144              :                         "Water Heater Source Side Inlet Temperature",
    5145              :                         Constant::Units::C,
    5146            1 :                         this->SourceInletTemp,
    5147              :                         OutputProcessor::TimeStepType::System,
    5148              :                         OutputProcessor::StoreType::Average,
    5149            1 :                         this->Name);
    5150              : 
    5151            2 :     SetupOutputVariable(state,
    5152              :                         "Water Heater Source Side Outlet Temperature",
    5153              :                         Constant::Units::C,
    5154            1 :                         this->SourceOutletTemp,
    5155              :                         OutputProcessor::TimeStepType::System,
    5156              :                         OutputProcessor::StoreType::Average,
    5157            1 :                         this->Name);
    5158              : 
    5159            2 :     SetupOutputVariable(state,
    5160              :                         "Water Heater Source Side Heat Transfer Rate",
    5161              :                         Constant::Units::W,
    5162            1 :                         this->SourceRate,
    5163              :                         OutputProcessor::TimeStepType::System,
    5164              :                         OutputProcessor::StoreType::Average,
    5165            1 :                         this->Name);
    5166            2 :     SetupOutputVariable(state,
    5167              :                         "Water Heater Source Side Heat Transfer Energy",
    5168              :                         Constant::Units::J,
    5169            1 :                         this->SourceEnergy,
    5170              :                         OutputProcessor::TimeStepType::System,
    5171              :                         OutputProcessor::StoreType::Sum,
    5172            1 :                         this->Name,
    5173              :                         Constant::eResource::PlantLoopHeatingDemand,
    5174              :                         OutputProcessor::Group::Plant,
    5175              :                         OutputProcessor::EndUseCat::WaterSystem, // DHW
    5176              :                         this->EndUseSubcategoryName);
    5177              : 
    5178            2 :     SetupOutputVariable(state,
    5179              :                         "Water Heater Off Cycle Parasitic Tank Heat Transfer Rate",
    5180              :                         Constant::Units::W,
    5181            1 :                         this->OffCycParaRateToTank,
    5182              :                         OutputProcessor::TimeStepType::System,
    5183              :                         OutputProcessor::StoreType::Average,
    5184            1 :                         this->Name);
    5185            2 :     SetupOutputVariable(state,
    5186              :                         "Water Heater Off Cycle Parasitic Tank Heat Transfer Energy",
    5187              :                         Constant::Units::J,
    5188            1 :                         this->OffCycParaEnergyToTank,
    5189              :                         OutputProcessor::TimeStepType::System,
    5190              :                         OutputProcessor::StoreType::Sum,
    5191            1 :                         this->Name);
    5192              : 
    5193            2 :     SetupOutputVariable(state,
    5194              :                         "Water Heater On Cycle Parasitic Tank Heat Transfer Rate",
    5195              :                         Constant::Units::W,
    5196            1 :                         this->OnCycParaRateToTank,
    5197              :                         OutputProcessor::TimeStepType::System,
    5198              :                         OutputProcessor::StoreType::Average,
    5199            1 :                         this->Name);
    5200            2 :     SetupOutputVariable(state,
    5201              :                         "Water Heater On Cycle Parasitic Tank Heat Transfer Energy",
    5202              :                         Constant::Units::J,
    5203            1 :                         this->OnCycParaEnergyToTank,
    5204              :                         OutputProcessor::TimeStepType::System,
    5205              :                         OutputProcessor::StoreType::Sum,
    5206            1 :                         this->Name);
    5207              : 
    5208            2 :     SetupOutputVariable(state,
    5209              :                         "Water Heater Total Demand Heat Transfer Rate",
    5210              :                         Constant::Units::W,
    5211            1 :                         this->TotalDemandRate,
    5212              :                         OutputProcessor::TimeStepType::System,
    5213              :                         OutputProcessor::StoreType::Average,
    5214            1 :                         this->Name);
    5215            2 :     SetupOutputVariable(state,
    5216              :                         "Water Heater Total Demand Heat Transfer Energy",
    5217              :                         Constant::Units::J,
    5218            1 :                         this->TotalDemandEnergy,
    5219              :                         OutputProcessor::TimeStepType::System,
    5220              :                         OutputProcessor::StoreType::Sum,
    5221            1 :                         this->Name);
    5222              : 
    5223            2 :     SetupOutputVariable(state,
    5224              :                         "Water Heater Heating Rate",
    5225              :                         Constant::Units::W,
    5226            1 :                         this->HeaterRate,
    5227              :                         OutputProcessor::TimeStepType::System,
    5228              :                         OutputProcessor::StoreType::Average,
    5229            1 :                         this->Name);
    5230            2 :     SetupOutputVariable(state,
    5231              :                         "Water Heater Heating Energy",
    5232              :                         Constant::Units::J,
    5233            1 :                         this->HeaterEnergy,
    5234              :                         OutputProcessor::TimeStepType::System,
    5235              :                         OutputProcessor::StoreType::Sum,
    5236            1 :                         this->Name);
    5237              : 
    5238            2 :     SetupOutputVariable(state,
    5239              :                         "Water Heater Unmet Demand Heat Transfer Rate",
    5240              :                         Constant::Units::W,
    5241            1 :                         this->UnmetRate,
    5242              :                         OutputProcessor::TimeStepType::System,
    5243              :                         OutputProcessor::StoreType::Average,
    5244            1 :                         this->Name);
    5245            2 :     SetupOutputVariable(state,
    5246              :                         "Water Heater Unmet Demand Heat Transfer Energy",
    5247              :                         Constant::Units::J,
    5248            1 :                         this->UnmetEnergy,
    5249              :                         OutputProcessor::TimeStepType::System,
    5250              :                         OutputProcessor::StoreType::Sum,
    5251            1 :                         this->Name);
    5252              : 
    5253            2 :     SetupOutputVariable(state,
    5254              :                         "Water Heater Venting Heat Transfer Rate",
    5255              :                         Constant::Units::W,
    5256            1 :                         this->VentRate,
    5257              :                         OutputProcessor::TimeStepType::System,
    5258              :                         OutputProcessor::StoreType::Average,
    5259            1 :                         this->Name);
    5260            2 :     SetupOutputVariable(state,
    5261              :                         "Water Heater Venting Heat Transfer Energy",
    5262              :                         Constant::Units::J,
    5263            1 :                         this->VentEnergy,
    5264              :                         OutputProcessor::TimeStepType::System,
    5265              :                         OutputProcessor::StoreType::Sum,
    5266            1 :                         this->Name);
    5267              : 
    5268            2 :     SetupOutputVariable(state,
    5269              :                         "Water Heater Net Heat Transfer Rate",
    5270              :                         Constant::Units::W,
    5271            1 :                         this->NetHeatTransferRate,
    5272              :                         OutputProcessor::TimeStepType::System,
    5273              :                         OutputProcessor::StoreType::Average,
    5274            1 :                         this->Name);
    5275            2 :     SetupOutputVariable(state,
    5276              :                         "Water Heater Net Heat Transfer Energy",
    5277              :                         Constant::Units::J,
    5278            1 :                         this->NetHeatTransferEnergy,
    5279              :                         OutputProcessor::TimeStepType::System,
    5280              :                         OutputProcessor::StoreType::Sum,
    5281            1 :                         this->Name);
    5282              : 
    5283            1 :     SetupOutputVariable(state,
    5284              :                         "Water Heater Cycle On Count",
    5285              :                         Constant::Units::None,
    5286            1 :                         this->CycleOnCount,
    5287              :                         OutputProcessor::TimeStepType::System,
    5288              :                         OutputProcessor::StoreType::Sum,
    5289            1 :                         this->Name);
    5290            2 :     SetupOutputVariable(state,
    5291              :                         "Water Heater Runtime Fraction",
    5292              :                         Constant::Units::None,
    5293            1 :                         this->RuntimeFraction,
    5294              :                         OutputProcessor::TimeStepType::System,
    5295              :                         OutputProcessor::StoreType::Average,
    5296            1 :                         this->Name);
    5297            2 :     SetupOutputVariable(state,
    5298              :                         "Water Heater Part Load Ratio",
    5299              :                         Constant::Units::None,
    5300            1 :                         this->PartLoadRatio,
    5301              :                         OutputProcessor::TimeStepType::System,
    5302              :                         OutputProcessor::StoreType::Average,
    5303            1 :                         this->Name);
    5304              : 
    5305            3 :     SetupOutputVariable(state,
    5306            2 :                         format("Water Heater {} Rate", Constant::eFuelNames[static_cast<int>(this->FuelType)]),
    5307              :                         Constant::Units::W,
    5308            1 :                         this->FuelRate,
    5309              :                         OutputProcessor::TimeStepType::System,
    5310              :                         OutputProcessor::StoreType::Average,
    5311            1 :                         this->Name);
    5312            3 :     SetupOutputVariable(state,
    5313            2 :                         format("Water Heater {} Energy", Constant::eFuelNames[static_cast<int>(this->FuelType)]),
    5314              :                         Constant::Units::J,
    5315            1 :                         this->FuelEnergy,
    5316              :                         OutputProcessor::TimeStepType::System,
    5317              :                         OutputProcessor::StoreType::Sum,
    5318            1 :                         this->Name,
    5319            1 :                         Constant::eFuel2eResource[(int)this->FuelType],
    5320              :                         OutputProcessor::Group::Plant,
    5321              :                         OutputProcessor::EndUseCat::WaterSystem, // DHW
    5322              :                         this->EndUseSubcategoryName);
    5323              : 
    5324            3 :     SetupOutputVariable(state,
    5325            2 :                         format("Water Heater Off Cycle Parasitic {} Rate", Constant::eFuelNames[static_cast<int>(this->OffCycParaFuelType)]),
    5326              :                         Constant::Units::W,
    5327            1 :                         this->OffCycParaFuelRate,
    5328              :                         OutputProcessor::TimeStepType::System,
    5329              :                         OutputProcessor::StoreType::Average,
    5330            1 :                         this->Name);
    5331            3 :     SetupOutputVariable(state,
    5332            2 :                         format("Water Heater Off Cycle Parasitic {} Energy", Constant::eFuelNames[static_cast<int>(this->OffCycParaFuelType)]),
    5333              :                         Constant::Units::J,
    5334            1 :                         this->OffCycParaFuelEnergy,
    5335              :                         OutputProcessor::TimeStepType::System,
    5336              :                         OutputProcessor::StoreType::Sum,
    5337            1 :                         this->Name,
    5338            1 :                         Constant::eFuel2eResource[(int)this->OffCycParaFuelType],
    5339              :                         OutputProcessor::Group::Plant,
    5340              :                         OutputProcessor::EndUseCat::WaterSystem, // DHW
    5341              :                         this->EndUseSubcategoryName);
    5342              : 
    5343            3 :     SetupOutputVariable(state,
    5344            2 :                         format("Water Heater On Cycle Parasitic {} Rate", Constant::eFuelNames[static_cast<int>(this->OnCycParaFuelType)]),
    5345              :                         Constant::Units::W,
    5346            1 :                         this->OnCycParaFuelRate,
    5347              :                         OutputProcessor::TimeStepType::System,
    5348              :                         OutputProcessor::StoreType::Average,
    5349            1 :                         this->Name);
    5350            3 :     SetupOutputVariable(state,
    5351            2 :                         format("Water Heater On Cycle Parasitic {} Energy", Constant::eFuelNames[static_cast<int>(this->OnCycParaFuelType)]),
    5352              :                         Constant::Units::J,
    5353            1 :                         this->OnCycParaFuelEnergy,
    5354              :                         OutputProcessor::TimeStepType::System,
    5355              :                         OutputProcessor::StoreType::Sum,
    5356            1 :                         this->Name,
    5357            1 :                         Constant::eFuel2eResource[(int)this->OnCycParaFuelType],
    5358              :                         OutputProcessor::Group::Plant,
    5359              :                         OutputProcessor::EndUseCat::WaterSystem, // DHW
    5360              :                         this->EndUseSubcategoryName);
    5361              : 
    5362            2 :     SetupOutputVariable(state,
    5363              :                         "Water Heater Water Volume Flow Rate",
    5364              :                         Constant::Units::m3_s,
    5365            1 :                         this->VolFlowRate,
    5366              :                         OutputProcessor::TimeStepType::System,
    5367              :                         OutputProcessor::StoreType::Average,
    5368            1 :                         this->Name);
    5369            2 :     SetupOutputVariable(state,
    5370              :                         "Water Heater Water Volume",
    5371              :                         Constant::Units::m3,
    5372            1 :                         this->VolumeConsumed,
    5373              :                         OutputProcessor::TimeStepType::System,
    5374              :                         OutputProcessor::StoreType::Sum,
    5375            1 :                         this->Name,
    5376              :                         Constant::eResource::Water,
    5377              :                         OutputProcessor::Group::Plant,
    5378              :                         OutputProcessor::EndUseCat::WaterSystem, // DHW
    5379              :                         this->EndUseSubcategoryName);
    5380            2 :     SetupOutputVariable(state,
    5381              :                         "Water Heater Mains Water Volume",
    5382              :                         Constant::Units::m3,
    5383            1 :                         this->VolumeConsumed,
    5384              :                         OutputProcessor::TimeStepType::System,
    5385              :                         OutputProcessor::StoreType::Sum,
    5386            1 :                         this->Name,
    5387              :                         Constant::eResource::MainsWater,
    5388              :                         OutputProcessor::Group::Plant,
    5389              :                         OutputProcessor::EndUseCat::WaterSystem, // DHW
    5390              :                         this->EndUseSubcategoryName);
    5391              : 
    5392            1 :     if (this->HeatPumpNum > 0) {
    5393              :         // CurrentModuleObject='WaterHeater:HeatPump:PumpedCondenser'
    5394            1 :         HeatPumpWaterHeaterData &HPWH = state.dataWaterThermalTanks->HPWaterHeater(this->HeatPumpNum);
    5395            2 :         SetupOutputVariable(state,
    5396              :                             "Water Heater Compressor Part Load Ratio",
    5397              :                             Constant::Units::None,
    5398            1 :                             HPWH.HeatingPLR,
    5399              :                             OutputProcessor::TimeStepType::System,
    5400              :                             OutputProcessor::StoreType::Average,
    5401            1 :                             HPWH.Name);
    5402            2 :         SetupOutputVariable(state,
    5403              :                             "Water Heater Off Cycle Ancillary Electricity Rate",
    5404              :                             Constant::Units::W,
    5405            1 :                             HPWH.OffCycParaFuelRate,
    5406              :                             OutputProcessor::TimeStepType::System,
    5407              :                             OutputProcessor::StoreType::Average,
    5408            1 :                             HPWH.Name);
    5409            2 :         SetupOutputVariable(state,
    5410              :                             "Water Heater Off Cycle Ancillary Electricity Energy",
    5411              :                             Constant::Units::J,
    5412            1 :                             HPWH.OffCycParaFuelEnergy,
    5413              :                             OutputProcessor::TimeStepType::System,
    5414              :                             OutputProcessor::StoreType::Sum,
    5415            1 :                             HPWH.Name,
    5416              :                             Constant::eResource::Electricity,
    5417              :                             OutputProcessor::Group::Plant,
    5418              :                             OutputProcessor::EndUseCat::WaterSystem, // DHW
    5419              :                             "Water Heater Parasitic");
    5420            2 :         SetupOutputVariable(state,
    5421              :                             "Water Heater On Cycle Ancillary Electricity Rate",
    5422              :                             Constant::Units::W,
    5423            1 :                             HPWH.OnCycParaFuelRate,
    5424              :                             OutputProcessor::TimeStepType::System,
    5425              :                             OutputProcessor::StoreType::Average,
    5426            1 :                             HPWH.Name);
    5427            2 :         SetupOutputVariable(state,
    5428              :                             "Water Heater On Cycle Ancillary Electricity Energy",
    5429              :                             Constant::Units::J,
    5430            1 :                             HPWH.OnCycParaFuelEnergy,
    5431              :                             OutputProcessor::TimeStepType::System,
    5432              :                             OutputProcessor::StoreType::Sum,
    5433            1 :                             HPWH.Name,
    5434              :                             Constant::eResource::Electricity,
    5435              :                             OutputProcessor::Group::Plant,
    5436              :                             OutputProcessor::EndUseCat::WaterSystem, // DHW
    5437              :                             "Water Heater Parasitic");
    5438            2 :         SetupOutputVariable(state,
    5439              :                             "Water Heater Heat Pump Control Tank Temperature",
    5440              :                             Constant::Units::C,
    5441            1 :                             HPWH.ControlTempAvg,
    5442              :                             OutputProcessor::TimeStepType::System,
    5443              :                             OutputProcessor::StoreType::Average,
    5444            1 :                             HPWH.Name);
    5445            2 :         SetupOutputVariable(state,
    5446              :                             "Water Heater Heat Pump Control Tank Final Temperature",
    5447              :                             Constant::Units::C,
    5448            1 :                             HPWH.ControlTempFinal,
    5449              :                             OutputProcessor::TimeStepType::System,
    5450              :                             OutputProcessor::StoreType::Average,
    5451            1 :                             HPWH.Name);
    5452              :     }
    5453              : 
    5454            1 :     if (this->DesuperheaterNum > 0) {
    5455              :         // CurrentModuleObject='Coil:WaterHeating:Desuperheater'
    5456            0 :         SetupOutputVariable(state,
    5457              :                             "Water Heater Part Load Ratio",
    5458              :                             Constant::Units::None,
    5459            0 :                             state.dataWaterThermalTanks->WaterHeaterDesuperheater(this->DesuperheaterNum).DesuperheaterPLR,
    5460              :                             OutputProcessor::TimeStepType::System,
    5461              :                             OutputProcessor::StoreType::Average,
    5462            0 :                             state.dataWaterThermalTanks->WaterHeaterDesuperheater(this->DesuperheaterNum).Name);
    5463            0 :         SetupOutputVariable(state,
    5464              :                             "Water Heater On Cycle Parasitic Electricity Rate",
    5465              :                             Constant::Units::W,
    5466            0 :                             state.dataWaterThermalTanks->WaterHeaterDesuperheater(this->DesuperheaterNum).OnCycParaFuelRate,
    5467              :                             OutputProcessor::TimeStepType::System,
    5468              :                             OutputProcessor::StoreType::Average,
    5469            0 :                             state.dataWaterThermalTanks->WaterHeaterDesuperheater(this->DesuperheaterNum).Name);
    5470            0 :         SetupOutputVariable(state,
    5471              :                             "Water Heater On Cycle Parasitic Electricity Energy",
    5472              :                             Constant::Units::J,
    5473            0 :                             state.dataWaterThermalTanks->WaterHeaterDesuperheater(this->DesuperheaterNum).OnCycParaFuelEnergy,
    5474              :                             OutputProcessor::TimeStepType::System,
    5475              :                             OutputProcessor::StoreType::Sum,
    5476            0 :                             state.dataWaterThermalTanks->WaterHeaterDesuperheater(this->DesuperheaterNum).Name,
    5477              :                             Constant::eResource::Electricity,
    5478              :                             OutputProcessor::Group::Plant,
    5479              :                             OutputProcessor::EndUseCat::WaterSystem, // DHW
    5480              :                             "Water Heater Parasitic");
    5481            0 :         SetupOutputVariable(state,
    5482              :                             "Water Heater Off Cycle Parasitic Electricity Rate",
    5483              :                             Constant::Units::W,
    5484            0 :                             state.dataWaterThermalTanks->WaterHeaterDesuperheater(this->DesuperheaterNum).OffCycParaFuelRate,
    5485              :                             OutputProcessor::TimeStepType::System,
    5486              :                             OutputProcessor::StoreType::Average,
    5487            0 :                             state.dataWaterThermalTanks->WaterHeaterDesuperheater(this->DesuperheaterNum).Name);
    5488            0 :         SetupOutputVariable(state,
    5489              :                             "Water Heater Off Cycle Parasitic Electricity Energy",
    5490              :                             Constant::Units::J,
    5491            0 :                             state.dataWaterThermalTanks->WaterHeaterDesuperheater(this->DesuperheaterNum).OffCycParaFuelEnergy,
    5492              :                             OutputProcessor::TimeStepType::System,
    5493              :                             OutputProcessor::StoreType::Sum,
    5494            0 :                             state.dataWaterThermalTanks->WaterHeaterDesuperheater(this->DesuperheaterNum).Name,
    5495              :                             Constant::eResource::Electricity,
    5496              :                             OutputProcessor::Group::Plant,
    5497              :                             OutputProcessor::EndUseCat::WaterSystem, // DHW
    5498              :                             "Water Heater Parasitic");
    5499            0 :         SetupOutputVariable(state,
    5500              :                             "Water Heater Heat Reclaim Efficiency Modifier Multiplier",
    5501              :                             Constant::Units::None,
    5502            0 :                             state.dataWaterThermalTanks->WaterHeaterDesuperheater(this->DesuperheaterNum).HEffFTempOutput,
    5503              :                             OutputProcessor::TimeStepType::System,
    5504              :                             OutputProcessor::StoreType::Average,
    5505            0 :                             state.dataWaterThermalTanks->WaterHeaterDesuperheater(this->DesuperheaterNum).Name);
    5506            0 :         SetupOutputVariable(state,
    5507              :                             "Water Heater Pump Electricity Rate",
    5508              :                             Constant::Units::W,
    5509            0 :                             state.dataWaterThermalTanks->WaterHeaterDesuperheater(this->DesuperheaterNum).PumpPower,
    5510              :                             OutputProcessor::TimeStepType::System,
    5511              :                             OutputProcessor::StoreType::Average,
    5512            0 :                             state.dataWaterThermalTanks->WaterHeaterDesuperheater(this->DesuperheaterNum).Name);
    5513            0 :         SetupOutputVariable(state,
    5514              :                             "Water Heater Pump Electricity Energy",
    5515              :                             Constant::Units::J,
    5516            0 :                             state.dataWaterThermalTanks->WaterHeaterDesuperheater(this->DesuperheaterNum).PumpEnergy,
    5517              :                             OutputProcessor::TimeStepType::System,
    5518              :                             OutputProcessor::StoreType::Sum,
    5519            0 :                             state.dataWaterThermalTanks->WaterHeaterDesuperheater(this->DesuperheaterNum).Name,
    5520              :                             Constant::eResource::Electricity,
    5521              :                             OutputProcessor::Group::Plant,
    5522              :                             OutputProcessor::EndUseCat::WaterSystem, // DHW
    5523              :                             "Desuperheater Pump");
    5524            0 :         SetupOutputVariable(state,
    5525              :                             "Water Heater Heating Rate",
    5526              :                             Constant::Units::W,
    5527            0 :                             state.dataWaterThermalTanks->WaterHeaterDesuperheater(this->DesuperheaterNum).HeaterRate,
    5528              :                             OutputProcessor::TimeStepType::System,
    5529              :                             OutputProcessor::StoreType::Average,
    5530            0 :                             state.dataWaterThermalTanks->WaterHeaterDesuperheater(this->DesuperheaterNum).Name);
    5531            0 :         SetupOutputVariable(state,
    5532              :                             "Water Heater Heating Energy",
    5533              :                             Constant::Units::J,
    5534            0 :                             state.dataWaterThermalTanks->WaterHeaterDesuperheater(this->DesuperheaterNum).HeaterEnergy,
    5535              :                             OutputProcessor::TimeStepType::System,
    5536              :                             OutputProcessor::StoreType::Sum,
    5537            0 :                             state.dataWaterThermalTanks->WaterHeaterDesuperheater(this->DesuperheaterNum).Name,
    5538              :                             Constant::eResource::EnergyTransfer,
    5539              :                             OutputProcessor::Group::Plant,
    5540              :                             OutputProcessor::EndUseCat::WaterSystem, // DHW
    5541              :                             "Water Heater");
    5542              :     }
    5543              : 
    5544              :     // Setup report variables for WaterHeater:Stratified
    5545              :     // CurrentModuleObject='WaterHeater:Stratified'
    5546            1 :     if (this->WaterThermalTankType == DataPlant::PlantEquipmentType::WtrHeaterStratified) {
    5547              : 
    5548            0 :         SetupOutputVariable(state,
    5549              :                             "Water Heater Heater 1 Heating Rate",
    5550              :                             Constant::Units::W,
    5551            0 :                             this->HeaterRate1,
    5552              :                             OutputProcessor::TimeStepType::System,
    5553              :                             OutputProcessor::StoreType::Average,
    5554            0 :                             this->Name);
    5555            0 :         SetupOutputVariable(state,
    5556              :                             "Water Heater Heater 2 Heating Rate",
    5557              :                             Constant::Units::W,
    5558            0 :                             this->HeaterRate2,
    5559              :                             OutputProcessor::TimeStepType::System,
    5560              :                             OutputProcessor::StoreType::Average,
    5561            0 :                             this->Name);
    5562              : 
    5563            0 :         SetupOutputVariable(state,
    5564              :                             "Water Heater Heater 1 Heating Energy",
    5565              :                             Constant::Units::J,
    5566            0 :                             this->HeaterEnergy1,
    5567              :                             OutputProcessor::TimeStepType::System,
    5568              :                             OutputProcessor::StoreType::Sum,
    5569            0 :                             this->Name);
    5570            0 :         SetupOutputVariable(state,
    5571              :                             "Water Heater Heater 2 Heating Energy",
    5572              :                             Constant::Units::J,
    5573            0 :                             this->HeaterEnergy2,
    5574              :                             OutputProcessor::TimeStepType::System,
    5575              :                             OutputProcessor::StoreType::Sum,
    5576            0 :                             this->Name);
    5577              : 
    5578            0 :         SetupOutputVariable(state,
    5579              :                             "Water Heater Heater 1 Cycle On Count",
    5580              :                             Constant::Units::None,
    5581            0 :                             this->CycleOnCount1,
    5582              :                             OutputProcessor::TimeStepType::System,
    5583              :                             OutputProcessor::StoreType::Sum,
    5584            0 :                             this->Name);
    5585            0 :         SetupOutputVariable(state,
    5586              :                             "Water Heater Heater 2 Cycle On Count",
    5587              :                             Constant::Units::None,
    5588            0 :                             this->CycleOnCount2,
    5589              :                             OutputProcessor::TimeStepType::System,
    5590              :                             OutputProcessor::StoreType::Sum,
    5591            0 :                             this->Name);
    5592              : 
    5593            0 :         SetupOutputVariable(state,
    5594              :                             "Water Heater Heater 1 Runtime Fraction",
    5595              :                             Constant::Units::None,
    5596            0 :                             this->RuntimeFraction1,
    5597              :                             OutputProcessor::TimeStepType::System,
    5598              :                             OutputProcessor::StoreType::Average,
    5599            0 :                             this->Name);
    5600            0 :         SetupOutputVariable(state,
    5601              :                             "Water Heater Heater 2 Runtime Fraction",
    5602              :                             Constant::Units::None,
    5603            0 :                             this->RuntimeFraction2,
    5604              :                             OutputProcessor::TimeStepType::System,
    5605              :                             OutputProcessor::StoreType::Average,
    5606            0 :                             this->Name);
    5607              : 
    5608            0 :         for (int NodeNum = 1; NodeNum <= this->Nodes; ++NodeNum) {
    5609            0 :             SetupOutputVariable(state,
    5610            0 :                                 format("Water Heater Temperature Node {}", NodeNum),
    5611              :                                 Constant::Units::C,
    5612            0 :                                 this->Node(NodeNum).TempAvg,
    5613              :                                 OutputProcessor::TimeStepType::System,
    5614              :                                 OutputProcessor::StoreType::Average,
    5615            0 :                                 this->Name);
    5616              :         }
    5617              : 
    5618            0 :         for (int NodeNum = 1; NodeNum <= this->Nodes; ++NodeNum) {
    5619            0 :             SetupOutputVariable(state,
    5620            0 :                                 format("Water Heater Final Temperature Node {}", NodeNum),
    5621              :                                 Constant::Units::C,
    5622            0 :                                 this->Node(NodeNum).Temp,
    5623              :                                 OutputProcessor::TimeStepType::System,
    5624              :                                 OutputProcessor::StoreType::Average,
    5625            0 :                                 this->Name);
    5626              :         }
    5627              :     }
    5628              : 
    5629            1 :     if (this->WaterThermalTankType == DataPlant::PlantEquipmentType::WtrHeaterStratified) {
    5630              : 
    5631            0 :         for (int NodeNum = 1; NodeNum <= this->Nodes; ++NodeNum) {
    5632              :             static constexpr std::string_view Format_723("Water Heater Stratified Node Information,{},{:.4T},{:.4T},{:.3T},{:.4T},{:.4T},{},{}\n");
    5633            0 :             print(state.files.eio,
    5634              :                   Format_723,
    5635              :                   NodeNum,
    5636            0 :                   this->Node(NodeNum).Height,
    5637            0 :                   this->Node(NodeNum).Volume,
    5638            0 :                   this->Node(NodeNum).MaxCapacity,
    5639            0 :                   this->Node(NodeNum).OffCycLossCoeff,
    5640            0 :                   this->Node(NodeNum).OnCycLossCoeff,
    5641            0 :                   this->Node(NodeNum).Inlets,
    5642            0 :                   this->Node(NodeNum).Outlets);
    5643              :         }
    5644              :     }
    5645            1 : }
    5646              : 
    5647            0 : void WaterThermalTankData::ValidatePLFCurve(EnergyPlusData &state, int const CurveIndex, bool &IsValid)
    5648              : {
    5649              : 
    5650              :     // SUBROUTINE INFORMATION:
    5651              :     //       AUTHOR         Peter Graham Ellis
    5652              :     //       DATE WRITTEN   February 2005
    5653              :     //       MODIFIED       na
    5654              :     //       RE-ENGINEERED  na
    5655              : 
    5656              :     // PURPOSE OF THIS SUBROUTINE:
    5657              :     // Validates the Part Load Factor curve by making sure it can never be less than or equal to zero
    5658              :     // over the domain of Part Load Ratio inputs from 0 to 1.
    5659              : 
    5660              :     // METHODOLOGY EMPLOYED:
    5661              :     // Currently can only check 0 and 1.  Need changes in CurveManager to be able to check minimums and
    5662              :     // maximums.
    5663              : 
    5664            0 :     IsValid = true;
    5665              : 
    5666              :     // Check 0 and 1
    5667            0 :     if (Curve::CurveValue(state, CurveIndex, 0.0) <= 0) IsValid = false;
    5668            0 :     if (Curve::CurveValue(state, CurveIndex, 1.0) <= 0) IsValid = false;
    5669            0 : }
    5670              : 
    5671           17 : void WaterThermalTankData::SetupStratifiedNodes(EnergyPlusData &state)
    5672              : {
    5673              : 
    5674              :     // SUBROUTINE INFORMATION:
    5675              :     //       AUTHOR         Peter Graham Ellis
    5676              :     //       DATE WRITTEN   January 2007
    5677              :     //       MODIFIED       na
    5678              :     //       RE-ENGINEERED  na
    5679              : 
    5680              :     // PURPOSE OF THIS SUBROUTINE:
    5681              :     // Sets up node properties based on the tank shape, i.e., vertical cylinder, horizontal cylinder, or other.
    5682              :     // Node height, skin area, vertical conduction area, and loss coefficients are calculated and assigned.
    5683              :     // Heating elements, parasitics, and fluid inlet and outlet flows are assigned according to node height.
    5684              : 
    5685              :     // METHODOLOGY EMPLOYED:
    5686              :     // Tank is divided into nodes of equal mass.  For horizontal cylinders, node heights are calculated using
    5687              :     // the Newton-Raphson iterative method.  For vertical cylinders and other shapes, the node heights are calculated
    5688              :     // using basic geometry.
    5689              : 
    5690              :     static constexpr std::string_view RoutineName("GetWaterThermalTankInput");
    5691              : 
    5692           17 :     constexpr Real64 Tolerance(1.0e-8); // Tolerance for Newton-Raphson solution
    5693           17 :     constexpr Real64 FluidCond(0.6);    // Conductivity of water (W/m-K)
    5694              : 
    5695           17 :     int NumNodes = this->Nodes;
    5696           17 :     this->Node.allocate(NumNodes);
    5697              :     Real64 rho;
    5698           17 :     if ((this->UseSidePlantLoc.loopNum > 0) && allocated(state.dataPlnt->PlantLoop)) {
    5699            0 :         rho = state.dataPlnt->PlantLoop(this->UseSidePlantLoc.loopNum).glycol->getDensity(state, Constant::InitConvTemp, RoutineName);
    5700              :     } else {
    5701           17 :         rho = this->water->getDensity(state, Constant::InitConvTemp, RoutineName);
    5702              :     }
    5703              : 
    5704           17 :     Real64 NodeMass = this->Volume * rho / NumNodes;
    5705              :     Real64 TankHeight;
    5706              : 
    5707              :     // Mixing rate set to 50% of the max value for dt = 1.0
    5708           17 :     this->InversionMixingRate = NodeMass * 0.5 * 1.0;
    5709              : 
    5710           17 :     if ((this->Shape == TankShape::VertCylinder) || (this->Shape == TankShape::Other)) {
    5711           17 :         TankHeight = this->Height;
    5712           17 :         Real64 EndArea = this->Volume / TankHeight;
    5713           17 :         Real64 NodeHeight = TankHeight / NumNodes;
    5714           17 :         Real64 CondCoeff = (FluidCond + this->AdditionalCond) * EndArea / NodeHeight;
    5715              : 
    5716              :         Real64 Perimeter_loc;
    5717           17 :         if (this->Shape == TankShape::VertCylinder) {
    5718           17 :             Real64 Radius = std::sqrt(EndArea / Constant::Pi);
    5719           17 :             Perimeter_loc = 2.0 * Constant::Pi * Radius;
    5720              :         } else { // TankShapeOther
    5721            0 :             Perimeter_loc = this->Perimeter;
    5722              :         }
    5723              : 
    5724          187 :         for (int NodeNum = 1; NodeNum <= NumNodes; ++NodeNum) {
    5725          170 :             this->Node(NodeNum).Mass = NodeMass;
    5726          170 :             this->Node(NodeNum).Volume = this->Volume / NumNodes;
    5727          170 :             this->Node(NodeNum).Height = NodeHeight;
    5728          170 :             this->Node(NodeNum).CondCoeffUp = CondCoeff;
    5729          170 :             this->Node(NodeNum).CondCoeffDn = CondCoeff;
    5730              : 
    5731              :             Real64 SkinArea;
    5732          170 :             if ((NodeNum == 1) || (NodeNum == NumNodes)) {
    5733           34 :                 SkinArea = Perimeter_loc * NodeHeight + EndArea;
    5734              :             } else {
    5735          136 :                 SkinArea = Perimeter_loc * NodeHeight;
    5736              :             }
    5737              : 
    5738          170 :             this->Node(NodeNum).OnCycLossCoeff = this->SkinLossCoeff * SkinArea + this->AdditionalLossCoeff(NodeNum);
    5739              : 
    5740          170 :             this->Node(NodeNum).OffCycLossCoeff = this->Node(NodeNum).OnCycLossCoeff + this->OffCycFlueLossCoeff;
    5741              : 
    5742              :         } // NodeNum
    5743              : 
    5744           17 :         this->Node(1).CondCoeffUp = 0.0;
    5745           17 :         this->Node(NumNodes).CondCoeffDn = 0.0;
    5746              : 
    5747           17 :     } else {                              // Tank%Shape == TankShapeHorizCylinder
    5748            0 :         Real64 TankLength = this->Height; // Height is the length in the axial direction
    5749            0 :         Real64 EndArea = this->Volume / TankLength;
    5750            0 :         Real64 Radius = std::sqrt(EndArea / Constant::Pi);
    5751            0 :         TankHeight = 2.0 * Radius; // Actual vertical height
    5752            0 :         Real64 NodeEndArea = EndArea / NumNodes;
    5753              : 
    5754            0 :         Real64 R = Radius;
    5755            0 :         Real64 H0 = 0.0;
    5756            0 :         Real64 ChordLength = 0.0;
    5757            0 :         for (int NodeNum = 1; NodeNum <= NumNodes; ++NodeNum) {
    5758            0 :             this->Node(NodeNum).Mass = NodeMass;
    5759            0 :             this->Node(NodeNum).Volume = this->Volume / NumNodes;
    5760              :             Real64 H;
    5761            0 :             if (NodeNum == NumNodes) {
    5762            0 :                 H = TankHeight;
    5763              :             } else {
    5764              :                 // Use the Newton-Raphson method to solve the nonlinear algebraic equation for node height
    5765            0 :                 H = H0 + TankHeight / NumNodes; // Initial guess
    5766              : 
    5767              :                 while (true) {
    5768            0 :                     Real64 a = std::sqrt(H);
    5769            0 :                     Real64 b = std::sqrt(2.0 * R - H);
    5770            0 :                     Real64 c = 2.0 * R * R * std::atan(a / b) - (2.0 * R * R - 3.0 * H * R + H * H) * (a / b);
    5771              :                     Real64 c0;
    5772            0 :                     if (H0 > 0.0) {
    5773            0 :                         Real64 a0 = std::sqrt(H0);
    5774            0 :                         Real64 b0 = std::sqrt(2.0 * R - H0);
    5775            0 :                         c0 = 2.0 * R * R * std::atan(a0 / b0) - (2.0 * R * R - 3.0 * H0 * R + H0 * H0) * (a0 / b0);
    5776              :                     } else {
    5777            0 :                         c0 = 0.0;
    5778              :                     }
    5779              : 
    5780            0 :                     Real64 ApproxEndArea = c - c0;          // Area approximated by iteration
    5781            0 :                     Real64 G = ApproxEndArea - NodeEndArea; // G is the function that should converge to zero
    5782              : 
    5783            0 :                     if (std::abs(G) < Tolerance) {
    5784            0 :                         break; // Converged !!!
    5785              :                     } else {
    5786            0 :                         H -= G / (2.0 * a * b); // Calculate next guess:  H = Hprev - G/G'
    5787              :                     }
    5788            0 :                 } // Newton-Raphson
    5789              :             }
    5790              : 
    5791            0 :             this->Node(NodeNum).Height = H - H0;
    5792              : 
    5793            0 :             if (NodeNum > 1) {
    5794            0 :                 Real64 CrossArea = 2.0 * ChordLength * TankLength; // Use old ChordLength from previous node
    5795            0 :                 Real64 CondCoeff = (FluidCond + this->AdditionalCond) * CrossArea / (0.5 * (H - H0) + 0.5 * this->Node(NodeNum - 1).Height);
    5796            0 :                 this->Node(NodeNum - 1).CondCoeffUp = CondCoeff; // Set for previous node
    5797            0 :                 this->Node(NodeNum).CondCoeffDn = CondCoeff;     // Set for this node
    5798              :             }
    5799              : 
    5800            0 :             ChordLength = std::sqrt(2.0 * R * H - H * H); // Calc new ChordLength to be used with next node
    5801              : 
    5802            0 :             Real64 Perimeter_loc = 2.0 * R * (std::acos((R - H) / R) - std::acos((R - H0) / R)); // Segments of circular perimeter
    5803            0 :             Real64 SkinArea = Perimeter_loc * TankLength + 2.0 * NodeEndArea;
    5804              : 
    5805            0 :             this->Node(NodeNum).OnCycLossCoeff = this->SkinLossCoeff * SkinArea + this->AdditionalLossCoeff(NodeNum);
    5806              : 
    5807            0 :             this->Node(NodeNum).OffCycLossCoeff = this->Node(NodeNum).OnCycLossCoeff + this->OffCycFlueLossCoeff;
    5808              :             // Although it doesn't make much sense to have a flue in a horizontal tank, keep it in anyway
    5809              : 
    5810            0 :             H0 = H;
    5811              :         } // NodeNum
    5812              : 
    5813            0 :         this->Node(1).CondCoeffUp = 0.0;
    5814            0 :         this->Node(NumNodes).CondCoeffDn = 0.0;
    5815              :     }
    5816              : 
    5817              :     // Loop through nodes again (from top to bottom this time) and assign heating elements, parasitics, flow inlets/outlets
    5818              :     // according to their vertical heights in the tank
    5819           17 :     Real64 H0 = TankHeight;
    5820          187 :     for (int NodeNum = 1; NodeNum <= NumNodes; ++NodeNum) {
    5821              :         Real64 H;
    5822          170 :         if (NodeNum == NumNodes) {
    5823           17 :             H = -1.0; // Avoids rounding errors and ensures that anything at height 0.0 goes into the bottom node
    5824              :         } else {
    5825          153 :             H = H0 - this->Node(NodeNum).Height;
    5826              :         }
    5827              : 
    5828              :         // Assign heater elements to the nodes at the specified heights
    5829          170 :         if ((this->HeaterHeight1 <= H0) && (this->HeaterHeight1 > H)) {
    5830              :             //       sensor node will not get set if user enters 0 for this heater capacity
    5831              :             //       (Tank%MaxCapacity > 0.0d0)) THEN
    5832           17 :             this->HeaterNode1 = NodeNum;
    5833           17 :             this->Node(NodeNum).MaxCapacity = this->MaxCapacity;
    5834              :         }
    5835              : 
    5836          170 :         if ((this->HeaterHeight2 <= H0) && (this->HeaterHeight2 > H)) {
    5837              :             //       sensor node will not get set if user enters 0 for this heater capacity
    5838              :             //      .AND. (Tank%MaxCapacity2 > 0.0d0)) THEN
    5839           17 :             this->HeaterNode2 = NodeNum;
    5840              : 
    5841           17 :             if ((NodeNum == this->HeaterNode1) && (this->StratifiedControlMode == PriorityControlMode::Simultaneous)) {
    5842            0 :                 this->Node(NodeNum).MaxCapacity += this->MaxCapacity2;
    5843              :             } else {
    5844           17 :                 this->Node(NodeNum).MaxCapacity = this->MaxCapacity2;
    5845              :             }
    5846              :         }
    5847              : 
    5848              :         // Assign parasitic heat gains to the nodes at the specified heights
    5849          170 :         if ((this->OffCycParaHeight <= H0) && (this->OffCycParaHeight > H)) {
    5850           17 :             this->Node(NodeNum).OffCycParaLoad = this->OffCycParaFracToTank * this->OffCycParaLoad;
    5851              :         }
    5852              : 
    5853          170 :         if ((this->OnCycParaHeight <= H0) && (this->OnCycParaHeight > H)) {
    5854           17 :             this->Node(NodeNum).OnCycParaLoad = this->OnCycParaFracToTank * this->OnCycParaLoad;
    5855              :         }
    5856              : 
    5857              :         // Assign inlets and outlets to the nodes at the specified heights
    5858          170 :         if ((this->UseInletHeight <= H0) && (this->UseInletHeight > H)) {
    5859           17 :             this->UseInletStratNode = NodeNum;
    5860              : 
    5861           17 :             if ((this->UseInletNode > 0) || (this->MassFlowRateMax > 0.0)) ++this->Node(NodeNum).Inlets;
    5862              :         }
    5863              : 
    5864          170 :         if ((this->UseOutletHeight <= H0) && (this->UseOutletHeight > H)) {
    5865           17 :             this->UseOutletStratNode = NodeNum;
    5866              : 
    5867           17 :             if ((this->UseOutletNode > 0) || (this->MassFlowRateMax > 0.0)) ++this->Node(NodeNum).Outlets;
    5868              :         }
    5869              : 
    5870          170 :         if ((this->SourceInletHeight <= H0) && (this->SourceInletHeight > H) && (this->SourceInletNode > 0)) {
    5871              : 
    5872            5 :             this->SourceInletStratNode = NodeNum;
    5873            5 :             ++this->Node(NodeNum).Inlets;
    5874              :         }
    5875              : 
    5876          170 :         if ((this->SourceOutletHeight <= H0) && (this->SourceOutletHeight > H) && (this->SourceOutletNode > 0)) {
    5877              : 
    5878            5 :             this->SourceOutletStratNode = NodeNum;
    5879            5 :             ++this->Node(NodeNum).Outlets;
    5880              :         }
    5881              : 
    5882          170 :         H0 = H;
    5883              :     } // NodeNum
    5884           17 : }
    5885              : 
    5886           11 : void WaterThermalTankData::initialize(EnergyPlusData &state, bool const FirstHVACIteration)
    5887              : {
    5888              : 
    5889              :     // SUBROUTINE INFORMATION:
    5890              :     //       AUTHOR         Peter Graham Ellis
    5891              :     //       DATE WRITTEN   February 2004
    5892              :     //       MODIFIED       FSEC, July 2005
    5893              :     //                      Brent Griffith, October 2007 indirect fired water heater
    5894              :     //                        B. Shen 12/2014, add air-source variable-speed heat pump water heating
    5895              :     //       RE-ENGINEERED  na
    5896              : 
    5897              :     // PURPOSE OF THIS SUBROUTINE:
    5898              :     // Initialize the water heater, heat pump water heater, or desuperheater heating coil objects during the simulation.
    5899              :     // determine flow rates thru use side and source side plant connections (if any)
    5900              : 
    5901              :     // METHODOLOGY EMPLOYED:
    5902              :     // Inlet and outlet nodes are initialized.  Scheduled values are retrieved for the current timestep.
    5903              : 
    5904           11 :     auto &ZoneEqSizing = state.dataSize->ZoneEqSizing;
    5905              : 
    5906              :     static constexpr std::string_view RoutineName("InitWaterThermalTank");
    5907              :     static constexpr std::string_view GetWaterThermalTankInput("GetWaterThermalTankInput");
    5908              :     static constexpr std::string_view SizeTankForDemand("SizeTankForDemandSide");
    5909              : 
    5910           11 :     if (this->scanPlantLoopsFlag && allocated(state.dataPlnt->PlantLoop)) {
    5911            2 :         if ((this->UseInletNode > 0) && (this->HeatPumpNum == 0)) {
    5912            0 :             bool errFlag = false;
    5913            0 :             PlantUtilities::ScanPlantLoopsForObject(
    5914            0 :                 state, this->Name, this->WaterThermalTankType, this->UseSidePlantLoc, errFlag, _, _, _, this->UseInletNode, _);
    5915            0 :             if (errFlag) {
    5916            0 :                 ShowFatalError(state, "InitWaterThermalTank: Program terminated due to previous condition(s).");
    5917              :             }
    5918              :         }
    5919            2 :         if ((this->UseInletNode > 0) && (this->HeatPumpNum > 0)) {
    5920              :             // this is a heat pump water heater, need a separate block because TypeOf_HeatPumpWtrHeater shows up on Branch
    5921              :             //  (input should probably have been the associated tank )
    5922            0 :             bool errFlag = false;
    5923            0 :             PlantUtilities::ScanPlantLoopsForObject(state,
    5924            0 :                                                     state.dataWaterThermalTanks->HPWaterHeater(this->HeatPumpNum).Name,
    5925            0 :                                                     state.dataWaterThermalTanks->HPWaterHeater(this->HeatPumpNum).HPWHType,
    5926            0 :                                                     this->UseSidePlantLoc,
    5927              :                                                     errFlag,
    5928              :                                                     _,
    5929              :                                                     _,
    5930              :                                                     _,
    5931            0 :                                                     this->UseInletNode,
    5932              :                                                     _);
    5933            0 :             if (errFlag) {
    5934            0 :                 ShowFatalError(state, "InitWaterThermalTank: Program terminated due to previous condition(s).");
    5935              :             }
    5936              :         }
    5937            2 :         if ((this->SourceInletNode > 0) && (this->DesuperheaterNum == 0) && (this->HeatPumpNum == 0)) {
    5938            1 :             bool errFlag = false;
    5939            3 :             PlantUtilities::ScanPlantLoopsForObject(
    5940            2 :                 state, this->Name, this->WaterThermalTankType, this->SrcSidePlantLoc, errFlag, _, _, _, this->SourceInletNode, _);
    5941            1 :             if (this->UseInletNode > 0) {
    5942            0 :                 PlantUtilities::InterConnectTwoPlantLoopSides(state, this->UseSidePlantLoc, this->SrcSidePlantLoc, this->WaterThermalTankType, true);
    5943              :             }
    5944            1 :             if (errFlag) {
    5945            0 :                 ShowFatalError(state, "InitWaterThermalTank: Program terminated due to previous condition(s).");
    5946              :             }
    5947              :         }
    5948            2 :         this->scanPlantLoopsFlag = false;
    5949              :     }
    5950              : 
    5951           11 :     if (this->SetLoopIndexFlag && allocated(state.dataPlnt->PlantLoop)) {
    5952            2 :         if ((this->UseInletNode > 0) && (this->HeatPumpNum == 0)) {
    5953              :             Real64 rho =
    5954            0 :                 state.dataPlnt->PlantLoop(this->UseSidePlantLoc.loopNum).glycol->getDensity(state, Constant::InitConvTemp, GetWaterThermalTankInput);
    5955            0 :             this->PlantUseMassFlowRateMax = this->UseDesignVolFlowRate * rho;
    5956            0 :             this->Mass = this->Volume * rho;
    5957            0 :             this->UseSidePlantSizNum = state.dataPlnt->PlantLoop(this->UseSidePlantLoc.loopNum).PlantSizNum;
    5958            0 :             if ((this->UseDesignVolFlowRateWasAutoSized) && (this->UseSidePlantSizNum == 0)) {
    5959            0 :                 ShowSevereError(state,
    5960            0 :                                 format("InitWaterThermalTank: Did not find Sizing:Plant object for use side of plant thermal tank = {}", this->Name));
    5961            0 :                 ShowFatalError(state, "InitWaterThermalTank: Program terminated due to previous condition(s).");
    5962              :             }
    5963              :         }
    5964            2 :         if ((this->UseInletNode > 0) && (this->HeatPumpNum > 0)) {
    5965              :             Real64 rho =
    5966            0 :                 state.dataPlnt->PlantLoop(this->UseSidePlantLoc.loopNum).glycol->getDensity(state, Constant::InitConvTemp, GetWaterThermalTankInput);
    5967            0 :             this->PlantUseMassFlowRateMax = this->UseDesignVolFlowRate * rho;
    5968            0 :             this->Mass = this->Volume * rho;
    5969            0 :             this->UseSidePlantSizNum = state.dataPlnt->PlantLoop(this->UseSidePlantLoc.loopNum).PlantSizNum;
    5970            0 :             if ((this->UseDesignVolFlowRateWasAutoSized) && (this->UseSidePlantSizNum == 0)) {
    5971            0 :                 ShowSevereError(state,
    5972            0 :                                 format("InitWaterThermalTank: Did not find Sizing:Plant object for use side of plant thermal tank = {}", this->Name));
    5973            0 :                 ShowFatalError(state, "InitWaterThermalTank: Program terminated due to previous condition(s).");
    5974              :             }
    5975              :         }
    5976            2 :         if ((this->SourceInletNode > 0) && (this->DesuperheaterNum == 0) && (this->HeatPumpNum == 0)) {
    5977              :             Real64 rho =
    5978            1 :                 state.dataPlnt->PlantLoop(this->SrcSidePlantLoc.loopNum).glycol->getDensity(state, Constant::InitConvTemp, GetWaterThermalTankInput);
    5979            1 :             this->PlantSourceMassFlowRateMax = this->SourceDesignVolFlowRate * rho;
    5980            1 :             this->SourceSidePlantSizNum = state.dataPlnt->PlantLoop(this->SrcSidePlantLoc.loopNum).PlantSizNum;
    5981            1 :             if ((this->SourceDesignVolFlowRateWasAutoSized) && (this->SourceSidePlantSizNum == 0)) {
    5982            0 :                 ShowSevereError(
    5983            0 :                     state, format("InitWaterThermalTank: Did not find Sizing:Plant object for source side of plant thermal tank = {}", this->Name));
    5984            0 :                 ShowFatalError(state, "InitWaterThermalTank: Program terminated due to previous condition(s).");
    5985              :             }
    5986              :         }
    5987            2 :         if (((this->SourceInletNode > 0) && (this->DesuperheaterNum > 0)) || (this->HeatPumpNum > 0)) {
    5988            1 :             this->SetLoopIndexFlag = false;
    5989              :         }
    5990            2 :         if (state.dataPlnt->PlantFirstSizesOkayToFinalize) this->SetLoopIndexFlag = false;
    5991            2 :         if (this->StandAlone) {
    5992            0 :             this->SizeStandAloneWaterHeater(state);
    5993            0 :             this->SetLoopIndexFlag = false;
    5994              :         }
    5995            9 :     } else if (this->SetLoopIndexFlag && !state.dataGlobal->AnyPlantInModel) {
    5996            5 :         if (this->StandAlone) {
    5997            0 :             this->SizeStandAloneWaterHeater(state);
    5998              :         }
    5999            5 :         this->SetLoopIndexFlag = false;
    6000              :     }
    6001              : 
    6002           11 :     if (state.dataGlobal->BeginEnvrnFlag && this->MyEnvrnFlag && !this->SetLoopIndexFlag) {
    6003              : 
    6004            2 :         if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
    6005              : 
    6006            0 :             if (this->ControlType == HeaterControlMode::Cycle) {
    6007            0 :                 this->MinCapacity = this->MaxCapacity;
    6008              :             }
    6009              : 
    6010              :             // check for sizing issues that model can not support
    6011              : 
    6012              :             // if stratified tank model, ensure that nominal change over rate is greater than one minute, avoid numerical problems.
    6013              : 
    6014            0 :             if ((this->WaterThermalTankType == DataPlant::PlantEquipmentType::WtrHeaterStratified) ||
    6015            0 :                 (this->WaterThermalTankType == DataPlant::PlantEquipmentType::ChilledWaterTankStratified)) {
    6016            0 :                 Real64 MaxSideVolFlow = max(this->UseDesignVolFlowRate, this->SourceDesignVolFlowRate);
    6017              : 
    6018            0 :                 if (MaxSideVolFlow > 0.0) { // protect div by zero
    6019            0 :                     Real64 TankChangeRateScale = this->Volume / MaxSideVolFlow;
    6020            0 :                     if (TankChangeRateScale < 60.0) { // nominal change over in less than one minute
    6021            0 :                         ShowSevereError(state, "InitWaterThermalTank: Detected problem for stratified tank model.  Model cannot be applied.");
    6022            0 :                         ShowContinueError(state, format("Occurs for stratified tank name = {}", this->Name));
    6023            0 :                         ShowContinueError(state, format("Tank volume = {:.4R} [m3]", this->Volume));
    6024            0 :                         ShowContinueError(state, format("Tank use side volume flow rate = {:.4R} [m3/s]", this->UseDesignVolFlowRate));
    6025            0 :                         ShowContinueError(state, format("Tank source side volume flow rate = {:.4R} [m3/s]", this->SourceDesignVolFlowRate));
    6026            0 :                         ShowContinueError(state, format("Nominal tank change over rate = {:.2R} [s]", TankChangeRateScale));
    6027            0 :                         ShowContinueError(
    6028              :                             state, "Change over rate is too fast, increase tank volume, decrease connection flow rates or use mixed tank model");
    6029              : 
    6030            0 :                         ShowFatalError(state, "InitWaterThermalTank: Simulation halted because of sizing problem in stratified tank model.");
    6031              :                     }
    6032              :                 }
    6033              :             }
    6034              :         }
    6035              : 
    6036              :         // Clear node initial conditions
    6037            2 :         if (this->UseInletNode > 0 && this->UseOutletNode > 0) {
    6038            0 :             state.dataLoopNodes->Node(this->UseInletNode).Temp = 0.0;
    6039              :             Real64 rho =
    6040            0 :                 state.dataPlnt->PlantLoop(this->UseSidePlantLoc.loopNum).glycol->getDensity(state, Constant::InitConvTemp, GetWaterThermalTankInput);
    6041            0 :             this->MassFlowRateMin = this->VolFlowRateMin * rho;
    6042            0 :             this->PlantUseMassFlowRateMax = this->UseDesignVolFlowRate * rho;
    6043            0 :             PlantUtilities::InitComponentNodes(state, this->MassFlowRateMin, this->PlantUseMassFlowRateMax, this->UseInletNode, this->UseOutletNode);
    6044            0 :             this->UseOutletTemp = 0.0;
    6045            0 :             this->UseMassFlowRate = 0.0;
    6046            0 :             this->SavedUseOutletTemp = 0.0;
    6047              : 
    6048            0 :             this->Mass = this->Volume * rho;
    6049            0 :             this->UseBranchControlType = DataPlant::CompData::getPlantComponent(state, this->UseSidePlantLoc).FlowCtrl;
    6050              :         }
    6051              : 
    6052            2 :         if ((this->SourceInletNode > 0) && (this->DesuperheaterNum == 0) && (this->HeatPumpNum == 0)) {
    6053              :             Real64 rho =
    6054            0 :                 state.dataPlnt->PlantLoop(this->SrcSidePlantLoc.loopNum).glycol->getDensity(state, Constant::InitConvTemp, GetWaterThermalTankInput);
    6055            0 :             this->PlantSourceMassFlowRateMax = this->SourceDesignVolFlowRate * rho;
    6056            0 :             PlantUtilities::InitComponentNodes(state, 0.0, this->PlantSourceMassFlowRateMax, this->SourceInletNode, this->SourceOutletNode);
    6057              : 
    6058            0 :             this->SourceOutletTemp = 0.0;
    6059            0 :             this->SourceMassFlowRate = 0.0;
    6060            0 :             this->SavedSourceOutletTemp = 0.0;
    6061              : 
    6062            0 :             this->SourceBranchControlType = DataPlant::CompData::getPlantComponent(state, this->SrcSidePlantLoc).FlowCtrl;
    6063              :         }
    6064              : 
    6065            2 :         if ((this->SourceInletNode > 0) && ((this->DesuperheaterNum > 0) || (this->HeatPumpNum > 0))) {
    6066            2 :             state.dataLoopNodes->Node(this->SourceInletNode).Temp = 0.0;
    6067            2 :             this->SourceOutletTemp = 0.0;
    6068            2 :             this->SourceMassFlowRate = 0.0;
    6069            2 :             this->SavedSourceOutletTemp = 0.0;
    6070            2 :             Real64 rho = this->water->getDensity(state, Constant::InitConvTemp, SizeTankForDemand);
    6071            2 :             this->PlantSourceMassFlowRateMax = this->SourceDesignVolFlowRate * rho;
    6072              :         }
    6073              : 
    6074              :         // Initialize tank temperature to setpoint of first hour of warm up period
    6075              :         // (use HPWH or Desuperheater heating coil set point if applicable)
    6076            2 :         Sched::Schedule *sched = nullptr;
    6077            2 :         if (this->HeatPumpNum > 0) {
    6078            0 :             state.dataWaterThermalTanks->HPWaterHeater(this->HeatPumpNum).Mode = TankOperatingMode::Floating;
    6079            0 :             state.dataWaterThermalTanks->HPWaterHeater(this->HeatPumpNum).SaveMode = TankOperatingMode::Floating;
    6080            0 :             state.dataWaterThermalTanks->HPWaterHeater(this->HeatPumpNum).SaveWHMode = TankOperatingMode::Floating;
    6081            0 :             sched = state.dataWaterThermalTanks->HPWaterHeater(this->HeatPumpNum).setptTempSched;
    6082            2 :         } else if (this->DesuperheaterNum > 0) {
    6083            2 :             state.dataWaterThermalTanks->WaterHeaterDesuperheater(this->DesuperheaterNum).Mode = TankOperatingMode::Floating;
    6084            2 :             sched = state.dataWaterThermalTanks->WaterHeaterDesuperheater(this->DesuperheaterNum).setptTempSched;
    6085              :         } else {
    6086            0 :             sched = this->setptTempSched;
    6087              :         }
    6088              : 
    6089            2 :         if (sched != nullptr) {
    6090            2 :             this->TankTemp = sched->getCurrentVal();
    6091            2 :             this->SavedTankTemp = this->TankTemp;
    6092              : 
    6093            2 :             if (this->Nodes > 0) {
    6094           26 :                 for (auto &e : this->Node) {
    6095           24 :                     e.Temp = e.SavedTemp = this->TankTemp;
    6096              :                 }
    6097              :             }
    6098              :         } else {
    6099            0 :             this->TankTemp = 20.0;
    6100            0 :             this->SavedTankTemp = this->TankTemp;
    6101              : 
    6102            0 :             if (this->Nodes > 0) {
    6103            0 :                 for (auto &e : this->Node) {
    6104            0 :                     e.Temp = e.SavedTemp = this->TankTemp;
    6105              :                 }
    6106              :             }
    6107              :         }
    6108            2 :         this->SourceOutletTemp = this->SavedTankTemp;
    6109            2 :         this->SavedSourceOutletTemp = this->SavedTankTemp;
    6110            2 :         this->UseOutletTemp = this->SavedTankTemp;
    6111            2 :         this->SavedUseOutletTemp = this->SavedTankTemp;
    6112            2 :         this->TankTempAvg = this->SavedTankTemp;
    6113              : 
    6114            2 :         this->SavedHeaterOn1 = false;
    6115            2 :         this->SavedHeaterOn2 = false;
    6116            2 :         this->Mode = TankOperatingMode::Floating;
    6117            2 :         this->SavedMode = TankOperatingMode::Floating;
    6118            2 :         this->FirstRecoveryDone = false;
    6119            2 :         this->FirstRecoveryFuel = 0.0;
    6120            2 :         this->UnmetEnergy = 0.0;
    6121            2 :         this->LossEnergy = 0.0;
    6122            2 :         this->FlueLossEnergy = 0.0;
    6123            2 :         this->UseEnergy = 0.0;
    6124            2 :         this->TotalDemandEnergy = 0.0;
    6125            2 :         this->SourceEnergy = 0.0;
    6126            2 :         this->HeaterEnergy = 0.0;
    6127            2 :         this->HeaterEnergy1 = 0.0;
    6128            2 :         this->HeaterEnergy2 = 0.0;
    6129            2 :         this->FuelEnergy = 0.0;
    6130            2 :         this->FuelEnergy1 = 0.0;
    6131            2 :         this->FuelEnergy2 = 0.0;
    6132            2 :         this->VentEnergy = 0.0;
    6133            2 :         this->OffCycParaFuelEnergy = 0.0;
    6134            2 :         this->OffCycParaEnergyToTank = 0.0;
    6135            2 :         this->OnCycParaFuelEnergy = 0.0;
    6136            2 :         this->OnCycParaEnergyToTank = 0.0;
    6137            2 :         this->NetHeatTransferEnergy = 0.0;
    6138              :     }
    6139              : 
    6140           11 :     if (!state.dataGlobal->BeginEnvrnFlag) this->MyEnvrnFlag = true;
    6141              : 
    6142           11 :     if (this->WarmupFlag && (!state.dataGlobal->WarmupFlag)) {
    6143              :         // reInitialize tank temperature to setpoint of first hour (use HPWH or Desuperheater heating coil set point if applicable)
    6144              :         // BG's interpretation here is that its better to reset initial condition to setpoint once warm up is over.
    6145              :         // (otherwise with a dynamic storage model it is difficult for the user to see the initial performance if it isn't periodic.)
    6146            1 :         Sched::Schedule *sched = nullptr;
    6147            1 :         if (this->HeatPumpNum > 0) {
    6148            1 :             state.dataWaterThermalTanks->HPWaterHeater(this->HeatPumpNum).Mode = TankOperatingMode::Floating;
    6149            1 :             sched = state.dataWaterThermalTanks->HPWaterHeater(this->HeatPumpNum).setptTempSched;
    6150            0 :         } else if (this->DesuperheaterNum > 0) {
    6151            0 :             state.dataWaterThermalTanks->WaterHeaterDesuperheater(this->DesuperheaterNum).Mode = TankOperatingMode::Floating;
    6152            0 :             sched = state.dataWaterThermalTanks->WaterHeaterDesuperheater(this->DesuperheaterNum).setptTempSched;
    6153              :         } else {
    6154            0 :             sched = this->setptTempSched;
    6155              :         }
    6156              : 
    6157            1 :         if (sched != nullptr) {
    6158            1 :             this->TankTemp = sched->getCurrentVal();
    6159            1 :             this->SavedTankTemp = this->TankTemp;
    6160              : 
    6161            1 :             if (this->Nodes > 0) {
    6162            0 :                 for (auto &e : this->Node) {
    6163            0 :                     e.Temp = e.SavedTemp = this->TankTemp;
    6164              :                 }
    6165              :             }
    6166              :         } else {
    6167            0 :             this->TankTemp = 20.0;
    6168            0 :             this->SavedTankTemp = this->TankTemp;
    6169              : 
    6170            0 :             if (this->Nodes > 0) {
    6171            0 :                 for (auto &e : this->Node) {
    6172            0 :                     e.Temp = e.SavedTemp = this->TankTemp;
    6173              :                 }
    6174              :             }
    6175              :         }
    6176            1 :         this->SourceOutletTemp = this->SavedTankTemp;
    6177            1 :         this->SavedSourceOutletTemp = this->SavedTankTemp;
    6178            1 :         this->UseOutletTemp = this->SavedTankTemp;
    6179            1 :         this->SavedUseOutletTemp = this->SavedTankTemp;
    6180            1 :         this->SavedHeaterOn1 = false;
    6181            1 :         this->SavedHeaterOn2 = false;
    6182            1 :         this->Mode = TankOperatingMode::Floating;
    6183            1 :         this->SavedMode = TankOperatingMode::Floating;
    6184            1 :         this->WarmupFlag = false;
    6185              :     }
    6186           11 :     if (state.dataGlobal->WarmupFlag) this->WarmupFlag = true;
    6187              : 
    6188           11 :     if (FirstHVACIteration) {
    6189              :         // Get all scheduled values
    6190            8 :         this->SetPointTemp = this->setptTempSched->getCurrentVal();
    6191              : 
    6192            8 :         if (!this->IsChilledWaterTank) {
    6193            8 :             if (this->SetPointTemp > this->TankTempLimit) {
    6194              :                 // Setpoint temperature scheduled higher than maximum tank temperature limit
    6195            0 :                 this->SetPointTemp = this->TankTempLimit - 1.0;
    6196              : 
    6197            0 :                 if (this->ShowSetPointWarning) {
    6198            0 :                     ShowSevereError(
    6199              :                         state,
    6200            0 :                         format("Water heater = {}:  Water heater tank set point temperature is greater than the maximum tank temperature limit.",
    6201            0 :                                this->Name));
    6202            0 :                     ShowContinueErrorTimeStamp(state,
    6203            0 :                                                format("Water heater tank set point temperature is reset to Tank Temperature Limit minus 1 C "
    6204              :                                                       "({:.2T}) and simulation continues.",
    6205            0 :                                                       this->SetPointTemp));
    6206            0 :                     this->ShowSetPointWarning = false;
    6207              :                 }
    6208              :             }
    6209              :         } else {
    6210            0 :             if (this->SetPointTemp < this->TankTempLimit) {
    6211              :                 // Setpoint temperature scheduled lower than minimum tank temperature limit
    6212            0 :                 this->SetPointTemp = this->TankTempLimit + 1.0;
    6213              : 
    6214            0 :                 if (this->ShowSetPointWarning) {
    6215            0 :                     ShowSevereError(
    6216              :                         state,
    6217            0 :                         format("Chilled Water Tank = {}:  Water heater tank set point temperature is lower than the minimum tank temperature limit.",
    6218            0 :                                this->Name));
    6219            0 :                     ShowContinueErrorTimeStamp(state,
    6220            0 :                                                format("Chilled water tank set point temperature is reset to Tank Temperature Limit plus 1 C "
    6221              :                                                       "({:.2T}) and simulation continues.",
    6222            0 :                                                       this->SetPointTemp));
    6223            0 :                     this->ShowSetPointWarning = false;
    6224              :                 }
    6225              :             }
    6226              :         }
    6227              : 
    6228            8 :         if (this->setptTemp2Sched != nullptr) {
    6229            1 :             this->SetPointTemp2 = this->setptTemp2Sched->getCurrentVal();
    6230              :         }
    6231              : 
    6232            8 :         switch (this->AmbientTempIndicator) {
    6233            7 :         case WTTAmbientTemp::Schedule: {
    6234            7 :             this->AmbientTemp = this->ambientTempSched->getCurrentVal();
    6235            7 :         } break;
    6236              : 
    6237            1 :         case WTTAmbientTemp::TempZone: {
    6238            1 :             this->AmbientTemp = state.dataZoneTempPredictorCorrector->zoneHeatBalance(this->AmbientTempZone).MAT;
    6239              : 
    6240            1 :             break;
    6241              :         }
    6242            0 :         case WTTAmbientTemp::OutsideAir: {
    6243            0 :             this->AmbientTemp = state.dataLoopNodes->Node(this->AmbientTempOutsideAirNode).Temp;
    6244            0 :             break;
    6245              :         }
    6246            0 :         default:
    6247            0 :             break;
    6248              :         }
    6249              : 
    6250            8 :         if (this->UseInletNode == 0) { // Stand-alone operation
    6251              : 
    6252            4 :             this->UseInletTemp = (this->useInletTempSched != nullptr) ? this->useInletTempSched->getCurrentVal() : state.dataEnvrn->WaterMainsTemp;
    6253              : 
    6254            4 :             this->UseMassFlowRate = this->MassFlowRateMax;
    6255            4 :             if (this->flowRateSched != nullptr) this->UseMassFlowRate *= this->flowRateSched->getCurrentVal();
    6256            4 :             this->VolFlowRate = this->UseMassFlowRate / Psychrometrics::RhoH2O(Constant::InitConvTemp);
    6257              :         }
    6258              : 
    6259            8 :         if (this->HeatPumpNum > 0) {
    6260            4 :             state.dataWaterThermalTanks->HPWaterHeater(this->HeatPumpNum).SetPointTemp =
    6261            4 :                 state.dataWaterThermalTanks->HPWaterHeater(this->HeatPumpNum).setptTempSched->getCurrentVal();
    6262            4 :             if (state.dataWaterThermalTanks->HPWaterHeater(this->HeatPumpNum).SetPointTemp >= this->TankTempLimit) {
    6263              :                 // HP setpoint temperature scheduled equal to or higher than tank temperature limit
    6264            0 :                 state.dataWaterThermalTanks->HPWaterHeater(this->HeatPumpNum).SetPointTemp = this->TankTempLimit - 1.0;
    6265              : 
    6266            0 :                 if (state.dataWaterThermalTanks->HPWaterHeater(this->HeatPumpNum).ShowSetPointWarning) {
    6267            0 :                     ShowSevereError(state,
    6268            0 :                                     format("Heat Pump Water Heater = {}:  Heat Pump water heater set point temperature is equal to or greater than "
    6269              :                                            "the maximum tank temperature limit.",
    6270            0 :                                            state.dataWaterThermalTanks->HPWaterHeater(this->HeatPumpNum).Name));
    6271            0 :                     ShowContinueErrorTimeStamp(state,
    6272            0 :                                                format("Heat Pump water heater tank set point temperature is reset to Tank Temperature Limit "
    6273              :                                                       "minus 1 C ({:.2T}) and simulation continues.",
    6274            0 :                                                       state.dataWaterThermalTanks->HPWaterHeater(this->HeatPumpNum).SetPointTemp));
    6275            0 :                     state.dataWaterThermalTanks->HPWaterHeater(this->HeatPumpNum).ShowSetPointWarning = false;
    6276              :                 }
    6277              :             }
    6278              :         }
    6279              : 
    6280            8 :         if (this->DesuperheaterNum > 0) {
    6281            1 :             state.dataWaterThermalTanks->WaterHeaterDesuperheater(this->DesuperheaterNum).SetPointTemp =
    6282            1 :                 state.dataWaterThermalTanks->WaterHeaterDesuperheater(this->DesuperheaterNum).setptTempSched->getCurrentVal();
    6283              :         }
    6284              : 
    6285              :     } // first HVAC Iteration
    6286              : 
    6287           11 :     if (this->UseInletNode > 0 && !this->SetLoopIndexFlag) { // setup mass flows for plant connections
    6288              :         Real64 DeadBandTemp;
    6289            5 :         if (this->IsChilledWaterTank) {
    6290            0 :             DeadBandTemp = this->SetPointTemp + this->DeadBandDeltaTemp;
    6291              :         } else {
    6292            5 :             DeadBandTemp = this->SetPointTemp - this->DeadBandDeltaTemp;
    6293              :         }
    6294              : 
    6295           10 :         Real64 mdotUse = this->PlantMassFlowRatesFunc(state,
    6296              :                                                       this->UseInletNode,
    6297              :                                                       FirstHVACIteration,
    6298              :                                                       WaterHeaterSide::Use,
    6299              :                                                       this->UseSidePlantLoc.loopSideNum,
    6300            5 :                                                       this->UseSideSeries,
    6301              :                                                       this->UseBranchControlType,
    6302              :                                                       this->SavedUseOutletTemp,
    6303              :                                                       DeadBandTemp,
    6304            5 :                                                       this->SetPointTemp);
    6305            5 :         PlantUtilities::SetComponentFlowRate(state, mdotUse, this->UseInletNode, this->UseOutletNode, this->UseSidePlantLoc);
    6306              : 
    6307            5 :         this->UseInletTemp = state.dataLoopNodes->Node(this->UseInletNode).Temp;
    6308            5 :         this->UseMassFlowRate = mdotUse;
    6309              :     }
    6310              : 
    6311           11 :     if (this->SourceInletNode > 0 && !this->SetLoopIndexFlag) { // setup mass flows for plant connections
    6312              :         Real64 DeadBandTemp;
    6313           11 :         if (this->IsChilledWaterTank) {
    6314            0 :             DeadBandTemp = this->SetPointTemp + this->DeadBandDeltaTemp;
    6315              :         } else {
    6316           11 :             DeadBandTemp = this->SetPointTemp - this->DeadBandDeltaTemp;
    6317              :         }
    6318              : 
    6319              :         Real64 sensedTemp;
    6320           11 :         if (this->WaterThermalTankType == DataPlant::PlantEquipmentType::ChilledWaterTankStratified) {
    6321            0 :             int tmpNodeNum = this->HeaterNode1;
    6322            0 :             sensedTemp = this->Node(tmpNodeNum).SavedTemp;
    6323              :         } else {
    6324           11 :             sensedTemp = this->SavedSourceOutletTemp;
    6325              :         }
    6326              : 
    6327           22 :         Real64 mdotSource = this->PlantMassFlowRatesFunc(state,
    6328              :                                                          this->SourceInletNode,
    6329              :                                                          FirstHVACIteration,
    6330              :                                                          WaterHeaterSide::Source,
    6331              :                                                          this->SrcSidePlantLoc.loopSideNum,
    6332           11 :                                                          this->SourceSideSeries,
    6333              :                                                          this->SourceBranchControlType,
    6334              :                                                          sensedTemp,
    6335              :                                                          DeadBandTemp,
    6336           11 :                                                          this->SetPointTemp);
    6337           11 :         if (this->SrcSidePlantLoc.loopNum > 0) {
    6338            1 :             PlantUtilities::SetComponentFlowRate(state, mdotSource, this->SourceInletNode, this->SourceOutletNode, this->SrcSidePlantLoc);
    6339              :         } else { // not really plant connected (desuperheater or heat pump)
    6340           10 :             state.dataLoopNodes->Node(this->SourceInletNode).MassFlowRate = mdotSource;
    6341           10 :             state.dataLoopNodes->Node(this->SourceOutletNode).MassFlowRate = mdotSource;
    6342              :         }
    6343              : 
    6344           11 :         this->SourceInletTemp = state.dataLoopNodes->Node(this->SourceInletNode).Temp;
    6345           11 :         this->SourceMassFlowRate = mdotSource;
    6346              :     }
    6347              : 
    6348              :     // initialize HPWHs each iteration
    6349           11 :     if (this->HeatPumpNum > 0) {
    6350              : 
    6351            5 :         int HPNum = this->HeatPumpNum;
    6352              : 
    6353            5 :         if (this->MyHPSizeFlag) {
    6354              :             //     autosize info must be calculated in GetWaterThermalTankInputFlag for use in StandardRating procedure
    6355              :             //       (called at end of GetWaterThermalTankInputFlag)
    6356              :             //     report autosizing information here (must be done after GetWaterThermalTankInputFlag is complete)
    6357            6 :             if (state.dataWaterThermalTanks->HPWaterHeater(HPNum).WaterFlowRateAutoSized &&
    6358            3 :                 (state.dataPlnt->PlantFirstSizesOkayToReport || !state.dataGlobal->AnyPlantInModel || this->AlreadyRated)) {
    6359            6 :                 BaseSizer::reportSizerOutput(state,
    6360            3 :                                              state.dataWaterThermalTanks->HPWaterHeater(HPNum).Type,
    6361            3 :                                              state.dataWaterThermalTanks->HPWaterHeater(HPNum).Name,
    6362              :                                              "Condenser water flow rate [m3/s]",
    6363            3 :                                              state.dataWaterThermalTanks->HPWaterHeater(HPNum).OperatingWaterFlowRate);
    6364              :             }
    6365            6 :             if (state.dataWaterThermalTanks->HPWaterHeater(HPNum).AirFlowRateAutoSized &&
    6366            3 :                 (state.dataPlnt->PlantFirstSizesOkayToReport || !state.dataGlobal->AnyPlantInModel || this->AlreadyRated)) {
    6367            6 :                 BaseSizer::reportSizerOutput(state,
    6368            3 :                                              state.dataWaterThermalTanks->HPWaterHeater(HPNum).Type,
    6369            3 :                                              state.dataWaterThermalTanks->HPWaterHeater(HPNum).Name,
    6370              :                                              "Evaporator air flow rate [m3/s]",
    6371            3 :                                              state.dataWaterThermalTanks->HPWaterHeater(HPNum).OperatingAirFlowRate);
    6372              :             }
    6373            3 :             state.dataSize->DataNonZoneNonAirloopValue = state.dataWaterThermalTanks->HPWaterHeater(HPNum).OperatingAirFlowRate;
    6374            3 :             state.dataWaterThermalTanks->HPWaterHeater(HPNum).OperatingAirMassFlowRate =
    6375            3 :                 state.dataWaterThermalTanks->HPWaterHeater(HPNum).OperatingAirFlowRate * state.dataEnvrn->StdRhoAir;
    6376            3 :             if (state.dataSize->CurZoneEqNum > 0) {
    6377            0 :                 ZoneEqSizing(state.dataSize->CurZoneEqNum).CoolingAirFlow = true;
    6378            0 :                 ZoneEqSizing(state.dataSize->CurZoneEqNum).CoolingAirVolFlow = state.dataSize->DataNonZoneNonAirloopValue;
    6379              :             }
    6380            3 :             if (state.dataPlnt->PlantFirstSizesOkayToReport || !state.dataGlobal->AnyPlantInModel || this->AlreadyRated) this->MyHPSizeFlag = false;
    6381              :         }
    6382              : 
    6383            5 :         int HPAirInletNode = state.dataWaterThermalTanks->HPWaterHeater(HPNum).HeatPumpAirInletNode;
    6384            5 :         int HPAirOutletNode = state.dataWaterThermalTanks->HPWaterHeater(HPNum).HeatPumpAirOutletNode;
    6385            5 :         int OutdoorAirNode = state.dataWaterThermalTanks->HPWaterHeater(HPNum).OutsideAirNode;
    6386            5 :         int ExhaustAirNode = state.dataWaterThermalTanks->HPWaterHeater(HPNum).ExhaustAirNode;
    6387            5 :         int HPWaterInletNode = state.dataWaterThermalTanks->HPWaterHeater(HPNum).CondWaterInletNode;
    6388            5 :         int HPWaterOutletNode = state.dataWaterThermalTanks->HPWaterHeater(HPNum).CondWaterOutletNode;
    6389            5 :         int InletAirMixerNode = state.dataWaterThermalTanks->HPWaterHeater(HPNum).InletAirMixerNode;
    6390            5 :         int OutletAirSplitterNode = state.dataWaterThermalTanks->HPWaterHeater(HPNum).OutletAirSplitterNode;
    6391              : 
    6392            5 :         switch (state.dataWaterThermalTanks->HPWaterHeater(HPNum).CrankcaseTempIndicator) {
    6393            1 :         case CrankcaseHeaterControlTemp::Zone: {
    6394            2 :             state.dataHVACGlobal->HPWHCrankcaseDBTemp =
    6395            1 :                 state.dataZoneTempPredictorCorrector->zoneHeatBalance(state.dataWaterThermalTanks->HPWaterHeater(HPNum).AmbientTempZone).MAT;
    6396            1 :             break;
    6397              :         }
    6398            4 :         case CrankcaseHeaterControlTemp::Outdoors: {
    6399            4 :             state.dataHVACGlobal->HPWHCrankcaseDBTemp = state.dataEnvrn->OutDryBulbTemp;
    6400            4 :             break;
    6401              :         }
    6402            0 :         case CrankcaseHeaterControlTemp::Schedule: {
    6403            0 :             state.dataHVACGlobal->HPWHCrankcaseDBTemp = state.dataWaterThermalTanks->HPWaterHeater(HPNum).crankcaseTempSched->getCurrentVal();
    6404            0 :             break;
    6405              :         }
    6406            0 :         default:
    6407            0 :             break;
    6408              :         }
    6409              : 
    6410              :         //   initialize HPWH report variables to 0 and set tank inlet node equal to outlet node
    6411            5 :         state.dataWaterThermalTanks->HPWaterHeater(HPNum).HPWaterHeaterSensibleCapacity = 0.0;
    6412            5 :         state.dataWaterThermalTanks->HPWaterHeater(HPNum).HPWaterHeaterLatentCapacity = 0.0;
    6413            5 :         this->SourceMassFlowRate = 0.0;
    6414            5 :         state.dataWaterThermalTanks->HPWaterHeater(HPNum).HeatingPLR = 0.0;
    6415            5 :         this->SourceInletTemp = this->SourceOutletTemp;
    6416              : 
    6417              :         //   determine HPWH inlet air conditions based on inlet air configuration (Zone, ZoneAndOA, OutdoorAir, or Schedule)
    6418            5 :         Real64 HPInletDryBulbTemp = 0.0;
    6419            5 :         Real64 HPInletHumRat = 0.0;
    6420              :         Real64 HPInletRelHum;
    6421            5 :         switch (state.dataWaterThermalTanks->HPWaterHeater(HPNum).InletAirConfiguration) {
    6422            1 :         case WTTAmbientTemp::TempZone: {
    6423            1 :             state.dataWaterThermalTanks->mixerInletAirSchedule = 0.0;
    6424            1 :             HPInletDryBulbTemp = state.dataLoopNodes->Node(HPAirInletNode).Temp;
    6425            1 :             HPInletHumRat = state.dataLoopNodes->Node(HPAirInletNode).HumRat;
    6426            1 :             break;
    6427              :         }
    6428            0 :         case WTTAmbientTemp::ZoneAndOA: {
    6429            0 :             if (state.dataWaterThermalTanks->HPWaterHeater(HPNum).inletAirMixerSched != nullptr) {
    6430              :                 //         schedule values are checked for boundary of 0 and 1 in GetWaterThermalTankInputFlag
    6431            0 :                 state.dataWaterThermalTanks->mixerInletAirSchedule =
    6432            0 :                     state.dataWaterThermalTanks->HPWaterHeater(HPNum).inletAirMixerSched->getCurrentVal();
    6433              :             } else {
    6434            0 :                 state.dataWaterThermalTanks->mixerInletAirSchedule = 0.0;
    6435              :             }
    6436            0 :             HPInletDryBulbTemp = state.dataWaterThermalTanks->mixerInletAirSchedule * state.dataLoopNodes->Node(OutdoorAirNode).Temp +
    6437            0 :                                  (1.0 - state.dataWaterThermalTanks->mixerInletAirSchedule) * state.dataLoopNodes->Node(HPAirInletNode).Temp;
    6438            0 :             HPInletHumRat = state.dataWaterThermalTanks->mixerInletAirSchedule * state.dataLoopNodes->Node(OutdoorAirNode).HumRat +
    6439            0 :                             (1.0 - state.dataWaterThermalTanks->mixerInletAirSchedule) * state.dataLoopNodes->Node(HPAirInletNode).HumRat;
    6440            0 :             break;
    6441              :         }
    6442            4 :         case WTTAmbientTemp::OutsideAir: {
    6443            4 :             state.dataWaterThermalTanks->mixerInletAirSchedule = 1.0;
    6444            4 :             HPInletDryBulbTemp = state.dataLoopNodes->Node(OutdoorAirNode).Temp;
    6445            4 :             HPInletHumRat = state.dataLoopNodes->Node(OutdoorAirNode).HumRat;
    6446              : 
    6447            4 :             break;
    6448              :         }
    6449            0 :         case WTTAmbientTemp::Schedule: {
    6450            0 :             HPInletDryBulbTemp = state.dataWaterThermalTanks->HPWaterHeater(HPNum).ambientTempSched->getCurrentVal();
    6451            0 :             HPInletRelHum = state.dataWaterThermalTanks->HPWaterHeater(HPNum).ambientRHSched->getCurrentVal();
    6452            0 :             HPInletHumRat = Psychrometrics::PsyWFnTdbRhPb(state, HPInletDryBulbTemp, HPInletRelHum, state.dataEnvrn->OutBaroPress, RoutineName);
    6453            0 :             state.dataLoopNodes->Node(HPAirInletNode).Temp = HPInletDryBulbTemp;
    6454            0 :             state.dataLoopNodes->Node(HPAirInletNode).HumRat = HPInletHumRat;
    6455            0 :             state.dataLoopNodes->Node(HPAirInletNode).Enthalpy = Psychrometrics::PsyHFnTdbW(HPInletDryBulbTemp, HPInletHumRat);
    6456            0 :             state.dataLoopNodes->Node(HPAirInletNode).Press = state.dataEnvrn->OutBaroPress;
    6457              : 
    6458            0 :             break;
    6459              :         }
    6460            0 :         default:
    6461            0 :             assert(false);
    6462              :             break;
    6463              :         }
    6464              : 
    6465            5 :         state.dataWaterThermalTanks->mdotAir = state.dataWaterThermalTanks->HPWaterHeater(HPNum).OperatingAirMassFlowRate;
    6466              : 
    6467              :         //   set up initial conditions on nodes
    6468            5 :         if (InletAirMixerNode > 0) {
    6469            0 :             state.dataLoopNodes->Node(InletAirMixerNode).MassFlowRate = 0.0;
    6470            0 :             state.dataLoopNodes->Node(InletAirMixerNode).MassFlowRateMax = state.dataWaterThermalTanks->mdotAir;
    6471            0 :             state.dataLoopNodes->Node(InletAirMixerNode).MassFlowRateMaxAvail = state.dataWaterThermalTanks->mdotAir;
    6472            0 :             state.dataLoopNodes->Node(InletAirMixerNode).Temp = HPInletDryBulbTemp;
    6473            0 :             state.dataLoopNodes->Node(InletAirMixerNode).HumRat = HPInletHumRat;
    6474            0 :             state.dataLoopNodes->Node(InletAirMixerNode).Enthalpy = Psychrometrics::PsyHFnTdbW(HPInletDryBulbTemp, HPInletHumRat);
    6475            0 :             state.dataLoopNodes->Node(HPAirInletNode).MassFlowRate = 0.0;
    6476            0 :             state.dataLoopNodes->Node(HPAirOutletNode).MassFlowRate = 0.0;
    6477            0 :             state.dataLoopNodes->Node(OutdoorAirNode).MassFlowRate = 0.0;
    6478            0 :             state.dataLoopNodes->Node(ExhaustAirNode).MassFlowRate = 0.0;
    6479              :         } else {
    6480            5 :             if (OutdoorAirNode == 0) {
    6481            1 :                 state.dataLoopNodes->Node(HPAirInletNode).MassFlowRate = 0.0;
    6482            1 :                 state.dataLoopNodes->Node(HPAirInletNode).MassFlowRateMax = state.dataWaterThermalTanks->mdotAir;
    6483            1 :                 state.dataLoopNodes->Node(HPAirInletNode).MassFlowRateMaxAvail = state.dataWaterThermalTanks->mdotAir;
    6484            1 :                 state.dataLoopNodes->Node(HPAirOutletNode).MassFlowRate = 0.0;
    6485              :             } else {
    6486            4 :                 state.dataLoopNodes->Node(OutdoorAirNode).MassFlowRate = 0.0;
    6487            4 :                 state.dataLoopNodes->Node(OutdoorAirNode).MassFlowRateMax = state.dataWaterThermalTanks->mdotAir;
    6488            4 :                 state.dataLoopNodes->Node(OutdoorAirNode).MassFlowRateMaxAvail = state.dataWaterThermalTanks->mdotAir;
    6489            4 :                 state.dataLoopNodes->Node(ExhaustAirNode).MassFlowRate = 0.0;
    6490              :             }
    6491              :         }
    6492              : 
    6493            5 :         if (OutletAirSplitterNode > 0) state.dataLoopNodes->Node(OutletAirSplitterNode).MassFlowRate = 0.0;
    6494              :         // these are water nodes are not managed by plant. the HP connects
    6495              :         // directly to the WH without using plant.
    6496            5 :         if (state.dataWaterThermalTanks->HPWaterHeater(HPNum).HPWHType == DataPlant::PlantEquipmentType::HeatPumpWtrHeaterPumped) {
    6497            5 :             state.dataLoopNodes->Node(HPWaterInletNode).MassFlowRate = 0.0;
    6498            5 :             state.dataLoopNodes->Node(HPWaterOutletNode).MassFlowRate = 0.0;
    6499              :         }
    6500              : 
    6501              :         //   set the max mass flow rate for outdoor fans
    6502            5 :         state.dataLoopNodes->Node(state.dataWaterThermalTanks->HPWaterHeater(HPNum).FanOutletNode).MassFlowRateMax =
    6503            5 :             state.dataWaterThermalTanks->mdotAir;
    6504              : 
    6505              :         //   Curve objects in DXCoils::CalcHPWHDXCoil will use inlet conditions to HPWH not inlet air conditions to DX Coil
    6506              :         //   HPWHInletDBTemp and HPWHInletWBTemp are DataHVACGlobals to pass info to HPWHDXCoil
    6507            5 :         state.dataHVACGlobal->HPWHInletDBTemp = HPInletDryBulbTemp;
    6508           10 :         state.dataHVACGlobal->HPWHInletWBTemp =
    6509            5 :             Psychrometrics::PsyTwbFnTdbWPb(state, state.dataHVACGlobal->HPWHInletDBTemp, HPInletHumRat, state.dataEnvrn->OutBaroPress);
    6510              : 
    6511              :         // initialize flow rates at speed levels for variable-speed HPWH
    6512            5 :         if ((state.dataWaterThermalTanks->HPWaterHeater(HPNum).bIsIHP) &&
    6513            0 :             (0 == state.dataWaterThermalTanks->HPWaterHeater(HPNum).NumofSpeed)) // use SCWH coil represents
    6514              :         {
    6515            0 :             IntegratedHeatPump::SizeIHP(state, state.dataWaterThermalTanks->HPWaterHeater(HPNum).DXCoilNum); //
    6516              :             // IntegratedHeatPump::SimIHP(modBlankString, HPWaterHeater(HPNum).DXCoilNum,
    6517              :             //    0, EMP1, EMP2, EMP3, 0, 0.0, 1, 0.0, 0.0, 0.0, false, 0.0); //conduct the sizing operation in the IHP
    6518            0 :             int VSCoilID = state.dataIntegratedHP->IntegratedHeatPumps(state.dataWaterThermalTanks->HPWaterHeater(HPNum).DXCoilNum).SCWHCoilIndex;
    6519            0 :             state.dataWaterThermalTanks->HPWaterHeater(HPNum).NumofSpeed = state.dataVariableSpeedCoils->VarSpeedCoil(VSCoilID).NumOfSpeeds;
    6520              : 
    6521            5 :         } else if (Util::SameString(state.dataWaterThermalTanks->HPWaterHeater(HPNum).DXCoilType,
    6522            5 :                                     "Coil:WaterHeating:AirToWaterHeatPump:VariableSpeed") &&
    6523            0 :                    (state.dataWaterThermalTanks->HPWaterHeater(HPNum).NumofSpeed == 0)) {
    6524            0 :             VariableSpeedCoils::SimVariableSpeedCoils(state,
    6525            0 :                                                       std::string(),
    6526            0 :                                                       state.dataWaterThermalTanks->HPWaterHeater(HPNum).DXCoilNum,
    6527              :                                                       HVAC::FanOp::Invalid, // Invalid instead of off?
    6528              :                                                       HVAC::CompressorOp::Off,
    6529              :                                                       0.0,
    6530              :                                                       1,
    6531              :                                                       0.0,
    6532              :                                                       0.0,
    6533              :                                                       0.0,
    6534              :                                                       0.0); // conduct the sizing operation in the VS WSHP
    6535            0 :             int VSCoilID = state.dataWaterThermalTanks->HPWaterHeater(HPNum).DXCoilNum;
    6536            0 :             state.dataWaterThermalTanks->HPWaterHeater(HPNum).NumofSpeed = state.dataVariableSpeedCoils->VarSpeedCoil(VSCoilID).NumOfSpeeds;
    6537              :             // below pass the flow rates from the VS coil to the water heater object
    6538              :         }
    6539              : 
    6540            5 :         if (state.dataWaterThermalTanks->HPWaterHeater(HPNum).NumofSpeed > 0) {
    6541              :             int VSCoilID;
    6542            0 :             if (state.dataWaterThermalTanks->HPWaterHeater(HPNum).bIsIHP)
    6543            0 :                 VSCoilID = state.dataIntegratedHP->IntegratedHeatPumps(state.dataWaterThermalTanks->HPWaterHeater(HPNum).DXCoilNum).SCWHCoilIndex;
    6544              :             else
    6545            0 :                 VSCoilID = state.dataWaterThermalTanks->HPWaterHeater(HPNum).DXCoilNum;
    6546              : 
    6547              :             // scale air flow rates
    6548            0 :             Real64 MulSpeedFlowScale = state.dataVariableSpeedCoils->VarSpeedCoil(VSCoilID).RatedAirVolFlowRate /
    6549            0 :                                        state.dataVariableSpeedCoils->VarSpeedCoil(VSCoilID).MSRatedAirVolFlowRate(
    6550            0 :                                            state.dataVariableSpeedCoils->VarSpeedCoil(VSCoilID).NormSpedLevel);
    6551            0 :             for (int Iter = 1; Iter <= state.dataWaterThermalTanks->HPWaterHeater(HPNum).NumofSpeed; ++Iter) {
    6552            0 :                 state.dataWaterThermalTanks->HPWaterHeater(HPNum).HPWHAirVolFlowRate(Iter) =
    6553            0 :                     state.dataVariableSpeedCoils->VarSpeedCoil(VSCoilID).MSRatedAirVolFlowRate(Iter) * MulSpeedFlowScale;
    6554              :             }
    6555              : 
    6556              :             // check fan flow rate, should be larger than the max flow rate of the VS coil
    6557            0 :             Real64 FanVolFlow = state.dataFans->fans(state.dataWaterThermalTanks->HPWaterHeater(HPNum).FanNum)->maxAirFlowRate;
    6558              : 
    6559            0 :             if (FanVolFlow < state.dataWaterThermalTanks->HPWaterHeater(HPNum).HPWHAirVolFlowRate(
    6560            0 :                                  state.dataWaterThermalTanks->HPWaterHeater(HPNum).NumofSpeed)) { // but this is the not the scaled mas flow
    6561              :                 // if ( FanVolFlow  < HPWaterHeater( HPNum ).HPWHAirVolFlowRate( HPWaterHeater( HPNum ).NumofSpeed ) ) {
    6562              : 
    6563            0 :                 ShowWarningError(state,
    6564            0 :                                  format("InitWaterThermalTank: -air flow rate = {:.7T} in fan object  is less than the MSHP system air flow rate "
    6565              :                                         "when waterheating is required({:.7T}).",
    6566              :                                         FanVolFlow,
    6567            0 :                                         state.dataWaterThermalTanks->HPWaterHeater(HPNum).HPWHAirVolFlowRate(
    6568            0 :                                             state.dataWaterThermalTanks->HPWaterHeater(HPNum).NumofSpeed)));
    6569            0 :                 ShowContinueError(state,
    6570              :                                   " The MSHP system flow rate when waterheating is required is reset to the"
    6571              :                                   " fan flow rate and the simulation continues.");
    6572            0 :                 ShowContinueError(state, format(" Occurs in {}", state.dataWaterThermalTanks->HPWaterHeater(HPNum).Name));
    6573            0 :                 state.dataWaterThermalTanks->HPWaterHeater(HPNum).HPWHAirVolFlowRate(state.dataWaterThermalTanks->HPWaterHeater(HPNum).NumofSpeed) =
    6574              :                     FanVolFlow;
    6575              :                 // Check flow rates in other speeds and ensure flow rates are not above the max flow rate
    6576            0 :                 for (int Iter = state.dataWaterThermalTanks->HPWaterHeater(HPNum).NumofSpeed - 1; Iter >= 1; --Iter) {
    6577            0 :                     if (state.dataWaterThermalTanks->HPWaterHeater(HPNum).HPWHAirVolFlowRate(Iter) >
    6578            0 :                         state.dataWaterThermalTanks->HPWaterHeater(HPNum).HPWHAirVolFlowRate(Iter + 1)) {
    6579            0 :                         ShowContinueError(state,
    6580            0 :                                           format(" The MSHP system flow rate when waterheating is required is reset to the flow rate at higher "
    6581              :                                                  "speed and the simulation continues at Speed{}.",
    6582              :                                                  Iter));
    6583            0 :                         ShowContinueError(state, format(" Occurs in {}", state.dataWaterThermalTanks->HPWaterHeater(HPNum).Name));
    6584            0 :                         state.dataWaterThermalTanks->HPWaterHeater(HPNum).HPWHAirVolFlowRate(Iter) =
    6585            0 :                             state.dataWaterThermalTanks->HPWaterHeater(HPNum).HPWHAirVolFlowRate(Iter + 1);
    6586              :                     }
    6587              :                 }
    6588              :             }
    6589              : 
    6590            0 :             for (int Iter = 1; Iter <= state.dataWaterThermalTanks->HPWaterHeater(HPNum).NumofSpeed; ++Iter) {
    6591            0 :                 state.dataWaterThermalTanks->HPWaterHeater(HPNum).MSAirSpeedRatio(Iter) =
    6592            0 :                     state.dataWaterThermalTanks->HPWaterHeater(HPNum).HPWHAirVolFlowRate(Iter) /
    6593            0 :                     state.dataWaterThermalTanks->HPWaterHeater(HPNum).HPWHAirVolFlowRate(
    6594            0 :                         state.dataWaterThermalTanks->HPWaterHeater(HPNum).NumofSpeed);
    6595              :             }
    6596              : 
    6597              :             // scale water flow rates
    6598            0 :             MulSpeedFlowScale = state.dataVariableSpeedCoils->VarSpeedCoil(VSCoilID).RatedWaterVolFlowRate /
    6599            0 :                                 state.dataVariableSpeedCoils->VarSpeedCoil(VSCoilID).MSRatedWaterVolFlowRate(
    6600            0 :                                     state.dataVariableSpeedCoils->VarSpeedCoil(VSCoilID).NormSpedLevel);
    6601            0 :             for (int Iter = 1; Iter <= state.dataWaterThermalTanks->HPWaterHeater(HPNum).NumofSpeed; ++Iter) {
    6602            0 :                 state.dataWaterThermalTanks->HPWaterHeater(HPNum).HPWHWaterVolFlowRate(Iter) =
    6603            0 :                     state.dataVariableSpeedCoils->VarSpeedCoil(VSCoilID).MSRatedWaterVolFlowRate(Iter) * MulSpeedFlowScale;
    6604            0 :                 state.dataWaterThermalTanks->HPWaterHeater(HPNum).HPWHWaterMassFlowRate(Iter) =
    6605            0 :                     state.dataVariableSpeedCoils->VarSpeedCoil(VSCoilID).MSRatedWaterMassFlowRate(Iter) * MulSpeedFlowScale;
    6606            0 :                 state.dataWaterThermalTanks->HPWaterHeater(HPNum).MSWaterSpeedRatio(Iter) =
    6607            0 :                     state.dataVariableSpeedCoils->VarSpeedCoil(VSCoilID).MSRatedWaterVolFlowRate(Iter) /
    6608            0 :                     state.dataVariableSpeedCoils->VarSpeedCoil(VSCoilID).MSRatedWaterVolFlowRate(
    6609            0 :                         state.dataWaterThermalTanks->HPWaterHeater(HPNum).NumofSpeed);
    6610              :             }
    6611              : 
    6612            0 :             Real64 rhoAir = Psychrometrics::PsyRhoAirFnPbTdbW(state, state.dataEnvrn->OutBaroPress, HPInletDryBulbTemp, HPInletHumRat);
    6613              : 
    6614            0 :             for (int Iter = 1; Iter <= state.dataWaterThermalTanks->HPWaterHeater(HPNum).NumofSpeed; ++Iter) {
    6615            0 :                 state.dataWaterThermalTanks->HPWaterHeater(HPNum).HPWHAirMassFlowRate(Iter) =
    6616            0 :                     state.dataWaterThermalTanks->HPWaterHeater(HPNum).HPWHAirVolFlowRate(Iter) * rhoAir;
    6617              :             }
    6618              : 
    6619              :             //   set the max mass flow rate for outdoor fans
    6620            0 :             state.dataLoopNodes->Node(state.dataWaterThermalTanks->HPWaterHeater(HPNum).FanOutletNode).MassFlowRateMax =
    6621            0 :                 state.dataWaterThermalTanks->HPWaterHeater(HPNum).HPWHAirMassFlowRate(state.dataWaterThermalTanks->HPWaterHeater(HPNum).NumofSpeed);
    6622              :         }
    6623              : 
    6624              :     } //  IF(WaterThermalTank(WaterThermalTankNum)%HeatPumpNum .GT. 0)THEN
    6625              : 
    6626              :     // calling CalcStandardRatings early bypasses fan sizing since DataSizing::DataNonZoneNonAirloopValue has not been set yet
    6627           11 :     if (!this->AlreadyRated) {
    6628            7 :         if (this->IsChilledWaterTank) {
    6629            0 :             this->AlreadyRated = true;
    6630              :         } else {
    6631            7 :             if (!state.dataGlobal->AnyPlantInModel || state.dataPlnt->PlantFirstSizesOkayToReport || this->MaxCapacity > 0.0 ||
    6632            0 :                 this->HeatPumpNum > 0) {
    6633            7 :                 this->CalcStandardRatings(state);
    6634              :             }
    6635              :         }
    6636              :     }
    6637           11 : }
    6638              : 
    6639          359 : void WaterThermalTankData::CalcWaterThermalTankMixed(EnergyPlusData &state) // Water Heater being simulated
    6640              : {
    6641              : 
    6642              :     // SUBROUTINE INFORMATION:
    6643              :     //       AUTHOR         Peter Graham Ellis
    6644              :     //       DATE WRITTEN   January 2005
    6645              :     //       MODIFIED       na
    6646              :     //       RE-ENGINEERED  na
    6647              : 
    6648              :     // PURPOSE OF THIS SUBROUTINE:
    6649              :     // Simulates a well-mixed, single node water heater tank.
    6650              : 
    6651              :     // METHODOLOGY EMPLOYED:
    6652              :     // This model uses analytical calculations based on the differential equation describing the tank energy
    6653              :     // balance.  The model operates in three different modes:  heating, floating, and venting.  Temperatures and
    6654              :     // energies change dynamically over the timestep.  The final reported tank temperature is the average over
    6655              :     // the timestep.  The final reported heat rates are averages based on the total energy transfer over the
    6656              :     // timestep.
    6657              : 
    6658              :     static constexpr std::string_view RoutineName("CalcWaterThermalTankMixed");
    6659              : 
    6660              :     Real64 TimeElapsed_loc =
    6661          359 :         state.dataGlobal->HourOfDay + state.dataGlobal->TimeStep * state.dataGlobal->TimeStepZone + state.dataHVACGlobal->SysTimeElapsed;
    6662              : 
    6663          359 :     if (this->TimeElapsed != TimeElapsed_loc) {
    6664              :         // The simulation has advanced to the next system DataGlobals::TimeStep.  Save conditions from the end of the previous system
    6665              :         // DataGlobals::TimeStep for use as the initial conditions of each iteration that does not advance the system DataGlobals::TimeStep.
    6666           11 :         this->SavedTankTemp = this->TankTemp;
    6667           11 :         this->SavedMode = this->Mode;
    6668              : 
    6669              :         // Save outlet temperatures for demand-side flow control
    6670           11 :         this->SavedUseOutletTemp = this->UseOutletTemp;
    6671           11 :         this->SavedSourceOutletTemp = this->SourceOutletTemp;
    6672              : 
    6673           11 :         this->TimeElapsed = TimeElapsed_loc;
    6674              :     }
    6675              : 
    6676          359 :     Real64 TankTemp_loc = this->SavedTankTemp;
    6677          359 :     TankOperatingMode Mode_loc = this->SavedMode;
    6678              : 
    6679          359 :     Real64 Qmaxcap = this->MaxCapacity;
    6680          359 :     Real64 Qmincap = this->MinCapacity;
    6681          359 :     Real64 Qoffcycfuel = this->OffCycParaLoad;
    6682          359 :     Real64 Qoffcycheat = Qoffcycfuel * this->OffCycParaFracToTank;
    6683          359 :     Real64 Qoncycfuel = this->OnCycParaLoad;
    6684          359 :     Real64 Qoncycheat = Qoncycfuel * this->OnCycParaFracToTank;
    6685              : 
    6686          359 :     Real64 SetPointTemp_loc = this->SetPointTemp;
    6687          359 :     Real64 DeadBandTemp = this->getDeadBandTemp();
    6688          359 :     Real64 MaxTemp = this->TankTempLimit;
    6689          359 :     Real64 AmbientTemp_loc = this->AmbientTemp;
    6690              : 
    6691          359 :     Real64 UseInletTemp_loc = this->UseInletTemp;
    6692          359 :     Real64 UseMassFlowRate_loc = this->UseMassFlowRate * this->UseEffectiveness;
    6693          359 :     Real64 SourceInletTemp_loc = this->SourceInletTemp;
    6694          359 :     Real64 SourceMassFlowRate_loc = this->SourceMassFlowRate * this->SourceEffectiveness;
    6695              : 
    6696              :     Real64 rho;
    6697          359 :     if (this->UseSidePlantLoc.loopNum > 0) {
    6698            0 :         rho = state.dataPlnt->PlantLoop(this->UseSidePlantLoc.loopNum).glycol->getDensity(state, TankTemp_loc, RoutineName);
    6699              :     } else {
    6700          359 :         rho = this->water->getDensity(state, TankTemp_loc, RoutineName);
    6701              :     }
    6702              : 
    6703          359 :     Real64 TankMass = rho * this->Volume;
    6704              : 
    6705              :     Real64 Cp;
    6706          359 :     if (this->UseSidePlantLoc.loopNum > 0) {
    6707            0 :         Cp = state.dataPlnt->PlantLoop(this->UseSidePlantLoc.loopNum).glycol->getSpecificHeat(state, TankTemp_loc, RoutineName);
    6708              :     } else {
    6709          359 :         Cp = this->water->getSpecificHeat(state, TankTemp_loc, RoutineName);
    6710              :     }
    6711              : 
    6712          359 :     Real64 SecInTimeStep = state.dataHVACGlobal->TimeStepSysSec;
    6713          359 :     Real64 TimeRemaining = SecInTimeStep;
    6714          359 :     int CycleOnCount_loc = 0;
    6715          359 :     int MaxCycles = SecInTimeStep;
    6716          359 :     Real64 Runtime = 0.0;
    6717          359 :     bool SetPointRecovered = false;
    6718              : 
    6719          359 :     Real64 Tsum = 0.0;
    6720          359 :     Real64 Eloss = 0.0;
    6721          359 :     Real64 Elosszone = 0.0;
    6722          359 :     Real64 Euse = 0.0;
    6723          359 :     Real64 Esource = 0.0;
    6724          359 :     Real64 Eheater = 0.0;
    6725          359 :     Real64 Event = 0.0;
    6726          359 :     Real64 Eneeded = 0.0;
    6727          359 :     Real64 Eunmet = 0.0;
    6728          359 :     Real64 Efuel = 0.0;
    6729          359 :     Real64 Eoncycfuel = 0.0;
    6730          359 :     Real64 Eoffcycfuel = 0.0;
    6731          359 :     Real64 PLR = 0.0;
    6732          359 :     Real64 PLRsum = 0.0;
    6733              : 
    6734          359 :     Real64 Qheat = 0.0;
    6735          359 :     Real64 Qheater = 0.0;
    6736          359 :     Real64 Qvent = 0.0;
    6737          359 :     Real64 Qneeded = 0.0;
    6738          359 :     Real64 Qunmet = 0.0;
    6739          359 :     Real64 Qfuel = 0.0;
    6740              : 
    6741              :     // Calculate the heating rate from the heat pump.
    6742          359 :     Real64 HPWHCondenserDeltaT = 0.0;
    6743              : 
    6744          359 :     if (this->HeatPumpNum > 0) {
    6745           94 :         HeatPumpWaterHeaterData const &HeatPump = state.dataWaterThermalTanks->HPWaterHeater(this->HeatPumpNum);
    6746           94 :         DataLoopNode::NodeData const &HPWHCondWaterInletNode = state.dataLoopNodes->Node(HeatPump.CondWaterInletNode);
    6747           94 :         DataLoopNode::NodeData const &HPWHCondWaterOutletNode = state.dataLoopNodes->Node(HeatPump.CondWaterOutletNode);
    6748           94 :         HPWHCondenserDeltaT = HPWHCondWaterOutletNode.Temp - HPWHCondWaterInletNode.Temp;
    6749              :     }
    6750          359 :     assert(HPWHCondenserDeltaT >= 0);
    6751              : 
    6752              :     Real64 Qheatpump;
    6753              :     Real64 Qsource;
    6754          359 :     EnergyPlus::WaterThermalTanks::WaterThermalTankData::CalcMixedTankSourceSideHeatTransferRate(
    6755              :         HPWHCondenserDeltaT, SourceInletTemp_loc, Cp, SetPointTemp_loc, SourceMassFlowRate_loc, Qheatpump, Qsource);
    6756              : 
    6757              :     // Calculate steady-state use heat rate.
    6758          359 :     Real64 Quse = UseMassFlowRate_loc * Cp * (UseInletTemp_loc - SetPointTemp_loc);
    6759          359 :     Real64 Qloss = 0.0, PLF = 0.0;
    6760              : 
    6761          941 :     while (TimeRemaining > 0.0) {
    6762              : 
    6763          582 :         Real64 TimeNeeded = 0.0;
    6764              : 
    6765          582 :         Real64 NewTankTemp = TankTemp_loc;
    6766          582 :         Real64 LossCoeff_loc = 0.0;
    6767          582 :         Real64 LossFracToZone = 0.0;
    6768              : 
    6769          582 :         switch (Mode_loc) {
    6770              : 
    6771          170 :         case TankOperatingMode::Heating: // Heater is on
    6772              : 
    6773              :             // Calculate heat rate needed to maintain the setpoint at steady-state conditions
    6774          170 :             LossCoeff_loc = this->OnCycLossCoeff;
    6775          170 :             LossFracToZone = this->OnCycLossFracToZone;
    6776          170 :             Qloss = LossCoeff_loc * (AmbientTemp_loc - SetPointTemp_loc);
    6777          170 :             Qneeded = -Quse - Qsource - Qloss - Qoncycheat;
    6778              : 
    6779          170 :             if (TankTemp_loc > SetPointTemp_loc) {
    6780              :                 // Heater is not needed after all, possibly due to step change in scheduled SetPointTemp
    6781              : 
    6782           17 :                 Qheater = 0.0;
    6783           17 :                 Qunmet = 0.0;
    6784           17 :                 Mode_loc = TankOperatingMode::Floating;
    6785           17 :                 continue;
    6786              : 
    6787          153 :             } else if (TankTemp_loc < SetPointTemp_loc) {
    6788              :                 // Attempt to recover to the setpoint as quickly as possible by using maximum heater capacity
    6789              : 
    6790              :                 // Qneeded is calculated above
    6791              :                 // Qneeded does not account for the extra energy needed to recover to the setpoint
    6792           88 :                 Qheater = Qmaxcap;
    6793           88 :                 Qunmet = max(Qneeded - Qheater, 0.0);
    6794           88 :                 Qheat = Qoncycheat + Qheater + Qheatpump;
    6795              : 
    6796              :                 // Calculate time needed to recover to the setpoint at maximum heater capacity
    6797           88 :                 TimeNeeded = EnergyPlus::WaterThermalTanks::WaterThermalTankData::CalcTimeNeeded(TankTemp_loc,
    6798              :                                                                                                  SetPointTemp_loc,
    6799              :                                                                                                  AmbientTemp_loc,
    6800              :                                                                                                  UseInletTemp_loc,
    6801              :                                                                                                  SourceInletTemp_loc,
    6802              :                                                                                                  TankMass,
    6803              :                                                                                                  Cp,
    6804              :                                                                                                  UseMassFlowRate_loc,
    6805              :                                                                                                  SourceMassFlowRate_loc,
    6806              :                                                                                                  LossCoeff_loc,
    6807              :                                                                                                  Qheat);
    6808              : 
    6809           88 :                 if (TimeNeeded > TimeRemaining) {
    6810              :                     // Heater is at maximum capacity and heats for all of the remaining time
    6811              :                     // Setpoint temperature WILL NOT be recovered
    6812              : 
    6813           23 :                     TimeNeeded = TimeRemaining;
    6814              : 
    6815           23 :                     NewTankTemp = EnergyPlus::WaterThermalTanks::WaterThermalTankData::CalcTankTemp(TankTemp_loc,
    6816              :                                                                                                     AmbientTemp_loc,
    6817              :                                                                                                     UseInletTemp_loc,
    6818              :                                                                                                     SourceInletTemp_loc,
    6819              :                                                                                                     TankMass,
    6820              :                                                                                                     Cp,
    6821              :                                                                                                     UseMassFlowRate_loc,
    6822              :                                                                                                     SourceMassFlowRate_loc,
    6823              :                                                                                                     LossCoeff_loc,
    6824              :                                                                                                     Qheat,
    6825              :                                                                                                     TimeNeeded);
    6826              : 
    6827              :                 } else { // TimeNeeded <= TimeRemaining
    6828              :                     // Heater is at maximum capacity but will not heat for all of the remaining time (at maximum anyway)
    6829              :                     // Setpoint temperature WILL be recovered
    6830              : 
    6831           65 :                     NewTankTemp = SetPointTemp_loc;
    6832              : 
    6833           65 :                     SetPointRecovered = true;
    6834              : 
    6835              :                 } // TimeNeeded > TimeRemaining
    6836              : 
    6837              :             } else { // TankTemp == SetPointTemp
    6838              :                 // Attempt to maintain the setpoint by using the needed heater capacity (modulating, if allowed)
    6839              : 
    6840           65 :                 if (Qneeded <= 0.0) {
    6841              :                     // Heater is not needed
    6842              : 
    6843            2 :                     Qneeded = 0.0;
    6844            2 :                     Qheater = 0.0;
    6845            2 :                     Qunmet = 0.0;
    6846            2 :                     Mode_loc = TankOperatingMode::Floating;
    6847            2 :                     continue;
    6848              : 
    6849           63 :                 } else if (Qneeded < Qmincap) {
    6850              :                     // Heater is required at less than the minimum capacity
    6851              :                     // If cycling, Qmincap = Qmaxcap.  Once the setpoint is reached, heater will almost always be shut off here
    6852              : 
    6853           63 :                     if (this->ControlType == HeaterControlMode::Cycle) {
    6854              :                         // Control will cycle on and off based on DeadBandTemp
    6855           63 :                         Qheater = 0.0;
    6856           63 :                         Qunmet = 0.0;
    6857           63 :                         Mode_loc = TankOperatingMode::Floating;
    6858           63 :                         continue;
    6859              : 
    6860            0 :                     } else if (this->ControlType == HeaterControlMode::Modulate) {
    6861              :                         // Control will cycle on and off based on DeadBandTemp until Qneeded > Qmincap again
    6862            0 :                         Qheater = 0.0;
    6863            0 :                         Qunmet = Qneeded;
    6864            0 :                         Mode_loc = TankOperatingMode::Floating;
    6865            0 :                         continue;
    6866              : 
    6867              :                         // CASE (ControlTypeModulateWithOverheat)  ! Not yet implemented
    6868              :                         // Calculate time to reach steady-state temp; check for venting at MaxTemp limit
    6869              :                         // Qheater = Qmincap
    6870              : 
    6871              :                         // CASE (ControlTypeModulateWithUnderheat)  ! Not yet implemented
    6872              :                         // Heater must not come back on until Qneeded >= Qmincap
    6873              :                         // Mode = modfloatMode
    6874              :                     }
    6875              : 
    6876            0 :                 } else if (Qneeded <= Qmaxcap) {
    6877              :                     // Heater can exactly meet the needed heat rate (usually by modulating) and heats for all of the remaining time
    6878              :                     // Setpoint temperature WILL be maintained
    6879              : 
    6880            0 :                     TimeNeeded = TimeRemaining;
    6881              : 
    6882            0 :                     Qheater = Qneeded;
    6883            0 :                     Qunmet = 0.0;
    6884              : 
    6885            0 :                     NewTankTemp = SetPointTemp_loc;
    6886              : 
    6887              :                 } else { // Qneeded > Qmaxcap
    6888              :                     // Heater is at maximum capacity and heats for all of the remaining time
    6889              :                     // Setpoint temperature WILL NOT be maintained
    6890              : 
    6891            0 :                     TimeNeeded = TimeRemaining;
    6892              : 
    6893            0 :                     Qheater = Qmaxcap;
    6894            0 :                     Qunmet = Qneeded - Qheater;
    6895            0 :                     Qheat = Qoncycheat + Qheater + Qheatpump;
    6896              : 
    6897            0 :                     NewTankTemp = EnergyPlus::WaterThermalTanks::WaterThermalTankData::CalcTankTemp(TankTemp_loc,
    6898              :                                                                                                     AmbientTemp_loc,
    6899              :                                                                                                     UseInletTemp_loc,
    6900              :                                                                                                     SourceInletTemp_loc,
    6901              :                                                                                                     TankMass,
    6902              :                                                                                                     Cp,
    6903              :                                                                                                     UseMassFlowRate_loc,
    6904              :                                                                                                     SourceMassFlowRate_loc,
    6905              :                                                                                                     LossCoeff_loc,
    6906              :                                                                                                     Qheat,
    6907              :                                                                                                     TimeNeeded);
    6908              : 
    6909              :                 } // Qneeded > Qmaxcap
    6910              : 
    6911              :             } // TankTemp > SetPointTemp
    6912              : 
    6913              :             // Update summed values
    6914           88 :             Eneeded += Qneeded * TimeNeeded;
    6915           88 :             Eheater += Qheater * TimeNeeded;
    6916           88 :             Eunmet += Qunmet * TimeNeeded;
    6917           88 :             Eoncycfuel += Qoncycfuel * TimeNeeded;
    6918              : 
    6919           88 :             if (Qmaxcap > 0.0) PLR = Qheater / Qmaxcap;
    6920           88 :             PLF = this->PartLoadFactor(state, PLR);
    6921           88 :             Efuel += Qheater * TimeNeeded / (PLF * this->Efficiency);
    6922              : 
    6923           88 :             Runtime += TimeNeeded;
    6924           88 :             PLRsum += PLR * TimeNeeded;
    6925              : 
    6926           88 :             if (!this->FirstRecoveryDone) {
    6927           14 :                 this->FirstRecoveryFuel += Efuel + Eoffcycfuel + Eoncycfuel;
    6928           14 :                 if (SetPointRecovered) this->FirstRecoveryDone = true;
    6929              :             }
    6930           88 :             break;
    6931              : 
    6932          412 :         case TankOperatingMode::Floating:
    6933              :         case TankOperatingMode::Cooling: // Heater is off
    6934              : 
    6935              :             // Calculate heat rate needed to maintain the setpoint at steady-state conditions
    6936          412 :             LossCoeff_loc = this->OffCycLossCoeff;
    6937          412 :             LossFracToZone = this->OffCycLossFracToZone;
    6938          412 :             Qloss = LossCoeff_loc * (AmbientTemp_loc - SetPointTemp_loc);
    6939          412 :             Qneeded = -Quse - Qsource - Qloss - Qoffcycheat;
    6940              : 
    6941              :             // This section really needs to work differently depending on ControlType
    6942              :             // CYCLE will look at TankTemp, MODULATE will look at Qneeded
    6943              : 
    6944          412 :             if ((TankTemp_loc < DeadBandTemp) && (!this->IsChilledWaterTank)) {
    6945              :                 // Tank temperature is already below the minimum, possibly due to step change in scheduled SetPointTemp
    6946              : 
    6947           32 :                 Mode_loc = TankOperatingMode::Heating;
    6948           32 :                 ++CycleOnCount_loc;
    6949           32 :                 continue;
    6950              : 
    6951          380 :             } else if ((TankTemp_loc >= DeadBandTemp) && (!this->IsChilledWaterTank)) {
    6952              : 
    6953          380 :                 Qheat = Qoffcycheat + Qheatpump;
    6954              : 
    6955              :                 // Calculate time needed for tank temperature to fall to minimum (setpoint - deadband)
    6956          380 :                 TimeNeeded = EnergyPlus::WaterThermalTanks::WaterThermalTankData::CalcTimeNeeded(TankTemp_loc,
    6957              :                                                                                                  DeadBandTemp,
    6958              :                                                                                                  AmbientTemp_loc,
    6959              :                                                                                                  UseInletTemp_loc,
    6960              :                                                                                                  SourceInletTemp_loc,
    6961              :                                                                                                  TankMass,
    6962              :                                                                                                  Cp,
    6963              :                                                                                                  UseMassFlowRate_loc,
    6964              :                                                                                                  SourceMassFlowRate_loc,
    6965              :                                                                                                  LossCoeff_loc,
    6966              :                                                                                                  Qheat);
    6967              : 
    6968          380 :                 if (TimeNeeded <= TimeRemaining) {
    6969              :                     // Heating will be needed in this DataGlobals::TimeStep
    6970              : 
    6971           44 :                     NewTankTemp = DeadBandTemp;
    6972           44 :                     Mode_loc = TankOperatingMode::Heating;
    6973           44 :                     ++CycleOnCount_loc;
    6974              : 
    6975              :                 } else { // TimeNeeded > TimeRemaining
    6976              :                     // Heating will not be needed for all of the remaining time
    6977              : 
    6978          336 :                     NewTankTemp = EnergyPlus::WaterThermalTanks::WaterThermalTankData::CalcTankTemp(TankTemp_loc,
    6979              :                                                                                                     AmbientTemp_loc,
    6980              :                                                                                                     UseInletTemp_loc,
    6981              :                                                                                                     SourceInletTemp_loc,
    6982              :                                                                                                     TankMass,
    6983              :                                                                                                     Cp,
    6984              :                                                                                                     UseMassFlowRate_loc,
    6985              :                                                                                                     SourceMassFlowRate_loc,
    6986              :                                                                                                     LossCoeff_loc,
    6987              :                                                                                                     Qheat,
    6988              :                                                                                                     TimeRemaining);
    6989              : 
    6990          336 :                     if ((NewTankTemp < MaxTemp) || (this->IsChilledWaterTank)) {
    6991              :                         // Neither heating nor venting is needed for all of the remaining time
    6992              : 
    6993          335 :                         TimeNeeded = TimeRemaining;
    6994              : 
    6995              :                     } else { // NewTankTemp >= MaxTemp
    6996              :                         // Venting will be needed in this DataGlobals::TimeStep
    6997              : 
    6998              :                         // Calculate time needed for tank temperature to rise to the maximum
    6999            1 :                         TimeNeeded = CalcTimeNeeded(TankTemp_loc,
    7000              :                                                     MaxTemp,
    7001              :                                                     AmbientTemp_loc,
    7002              :                                                     UseInletTemp_loc,
    7003              :                                                     SourceInletTemp_loc,
    7004              :                                                     TankMass,
    7005              :                                                     Cp,
    7006              :                                                     UseMassFlowRate_loc,
    7007              :                                                     SourceMassFlowRate_loc,
    7008              :                                                     LossCoeff_loc,
    7009              :                                                     Qheat);
    7010              : 
    7011              :                         // if limit NewTankTemp >= MaxTemp
    7012            1 :                         if (TankTemp_loc >= MaxTemp) {
    7013            1 :                             TimeNeeded = TimeRemaining;
    7014              :                         }
    7015            1 :                         NewTankTemp = MaxTemp;
    7016            1 :                         Mode_loc = TankOperatingMode::Venting;
    7017              : 
    7018              :                     } // NewTankTemp >= MaxTemp
    7019              : 
    7020              :                 } // TimeNeeded <= TimeRemaining
    7021              : 
    7022            0 :             } else if ((TankTemp_loc > DeadBandTemp) && (this->IsChilledWaterTank)) {
    7023            0 :                 Mode_loc = TankOperatingMode::Cooling;
    7024            0 :                 Qheat = Qheatpump;
    7025              : 
    7026            0 :                 NewTankTemp = EnergyPlus::WaterThermalTanks::WaterThermalTankData::CalcTankTemp(TankTemp_loc,
    7027              :                                                                                                 AmbientTemp_loc,
    7028              :                                                                                                 UseInletTemp_loc,
    7029              :                                                                                                 SourceInletTemp_loc,
    7030              :                                                                                                 TankMass,
    7031              :                                                                                                 Cp,
    7032              :                                                                                                 UseMassFlowRate_loc,
    7033              :                                                                                                 SourceMassFlowRate_loc,
    7034              :                                                                                                 LossCoeff_loc,
    7035              :                                                                                                 Qheat,
    7036              :                                                                                                 TimeRemaining);
    7037            0 :                 TimeNeeded = TimeRemaining;
    7038            0 :             } else if ((TankTemp_loc <= DeadBandTemp) && (this->IsChilledWaterTank)) {
    7039              : 
    7040            0 :                 if (TankTemp_loc < SetPointTemp_loc) Mode_loc = TankOperatingMode::Floating;
    7041              : 
    7042            0 :                 Qheat = Qheatpump;
    7043              : 
    7044            0 :                 NewTankTemp = EnergyPlus::WaterThermalTanks::WaterThermalTankData::CalcTankTemp(TankTemp_loc,
    7045              :                                                                                                 AmbientTemp_loc,
    7046              :                                                                                                 UseInletTemp_loc,
    7047              :                                                                                                 SourceInletTemp_loc,
    7048              :                                                                                                 TankMass,
    7049              :                                                                                                 Cp,
    7050              :                                                                                                 UseMassFlowRate_loc,
    7051              :                                                                                                 SourceMassFlowRate_loc,
    7052              :                                                                                                 LossCoeff_loc,
    7053              :                                                                                                 Qheat,
    7054              :                                                                                                 TimeRemaining);
    7055            0 :                 TimeNeeded = TimeRemaining;
    7056              :             } // TankTemp vs DeadBandTemp for heaters and chilled water tanks
    7057              : 
    7058              :             // Update summed values
    7059          380 :             Eneeded += Qneeded * TimeNeeded;
    7060          380 :             Eunmet += Qunmet * TimeNeeded; // Qunmet may be propagated thru from the previous iteration
    7061          380 :             Eoffcycfuel += Qoffcycfuel * TimeNeeded;
    7062          380 :             break;
    7063              : 
    7064            0 :         case TankOperatingMode::Venting: // Excess heat is vented
    7065              : 
    7066            0 :             LossCoeff_loc = this->OffCycLossCoeff;
    7067            0 :             LossFracToZone = this->OffCycLossFracToZone;
    7068            0 :             Qheat = Qoffcycheat + Qheatpump;
    7069              : 
    7070            0 :             NewTankTemp = EnergyPlus::WaterThermalTanks::WaterThermalTankData::CalcTankTemp(TankTemp_loc,
    7071              :                                                                                             AmbientTemp_loc,
    7072              :                                                                                             UseInletTemp_loc,
    7073              :                                                                                             SourceInletTemp_loc,
    7074              :                                                                                             TankMass,
    7075              :                                                                                             Cp,
    7076              :                                                                                             UseMassFlowRate_loc,
    7077              :                                                                                             SourceMassFlowRate_loc,
    7078              :                                                                                             LossCoeff_loc,
    7079              :                                                                                             Qheat,
    7080              :                                                                                             TimeRemaining);
    7081              : 
    7082            0 :             if (NewTankTemp < MaxTemp) {
    7083              :                 // Venting is no longer needed because conditions have changed
    7084              : 
    7085            0 :                 Mode_loc = TankOperatingMode::Floating;
    7086            0 :                 continue;
    7087              : 
    7088              :             } else { // NewTankTemp >= MaxTemp
    7089              : 
    7090            0 :                 TimeNeeded = TimeRemaining;
    7091              : 
    7092              :                 // Calculate the steady-state venting rate needed to maintain the tank at maximum temperature
    7093            0 :                 Real64 Qloss = LossCoeff_loc * (AmbientTemp_loc - MaxTemp);
    7094            0 :                 Quse = UseMassFlowRate_loc * Cp * (UseInletTemp_loc - MaxTemp);
    7095            0 :                 Qsource = SourceMassFlowRate_loc * Cp * (SourceInletTemp_loc - MaxTemp);
    7096            0 :                 Qvent = -Quse - Qsource - Qloss - Qoffcycheat;
    7097              : 
    7098            0 :                 NewTankTemp = MaxTemp;
    7099              : 
    7100              :             } // NewTankTemp < MaxTemp
    7101              : 
    7102              :             // Update summed values
    7103            0 :             Event += Qvent * TimeNeeded;
    7104            0 :             Eoffcycfuel += Qoffcycfuel * TimeNeeded;
    7105            0 :             break;
    7106            0 :         default:
    7107            0 :             assert(false); // should never get here
    7108              :         }
    7109              : 
    7110          468 :         Real64 deltaTsum = EnergyPlus::WaterThermalTanks::WaterThermalTankData::CalcTempIntegral(TankTemp_loc,
    7111              :                                                                                                  NewTankTemp,
    7112              :                                                                                                  AmbientTemp_loc,
    7113              :                                                                                                  UseInletTemp_loc,
    7114              :                                                                                                  SourceInletTemp_loc,
    7115              :                                                                                                  TankMass,
    7116              :                                                                                                  Cp,
    7117              :                                                                                                  UseMassFlowRate_loc,
    7118              :                                                                                                  SourceMassFlowRate_loc,
    7119              :                                                                                                  LossCoeff_loc,
    7120              :                                                                                                  Qheat,
    7121              :                                                                                                  TimeNeeded);
    7122              : 
    7123              :         // Update summed values
    7124          468 :         Tsum += deltaTsum;
    7125          468 :         Eloss += LossCoeff_loc * (AmbientTemp_loc * TimeNeeded - deltaTsum);
    7126          468 :         Elosszone += LossFracToZone * LossCoeff_loc * (AmbientTemp_loc * TimeNeeded - deltaTsum);
    7127          468 :         Euse += UseMassFlowRate_loc * Cp * (UseInletTemp_loc * TimeNeeded - deltaTsum);
    7128          468 :         if (this->HeatPumpNum > 0) {
    7129          132 :             Esource += Qheatpump * TimeNeeded;
    7130              :         } else {
    7131          336 :             Esource += SourceMassFlowRate_loc * Cp * (SourceInletTemp_loc * TimeNeeded - deltaTsum);
    7132              :         }
    7133              : 
    7134          468 :         TankTemp_loc = NewTankTemp; // Update tank temperature
    7135              : 
    7136          468 :         TimeRemaining -= TimeNeeded;
    7137              : 
    7138          468 :         if (CycleOnCount_loc > MaxCycles) {
    7139              : 
    7140            0 :             if (!state.dataGlobal->WarmupFlag) {
    7141            0 :                 if (this->MaxCycleErrorIndex == 0) {
    7142            0 :                     ShowWarningError(state, format("WaterHeater:Mixed = {}:  Heater is cycling on and off more than once per second.", this->Name));
    7143            0 :                     ShowContinueError(state, "Try increasing Deadband Temperature Difference or Tank Volume");
    7144            0 :                     ShowContinueErrorTimeStamp(state, "");
    7145              :                 }
    7146            0 :                 ShowRecurringWarningErrorAtEnd(state,
    7147            0 :                                                "WaterHeater:Mixed = " + this->Name + " Heater is cycling on and off more than once per second:",
    7148            0 :                                                this->MaxCycleErrorIndex);
    7149              :             }
    7150              : 
    7151            0 :             break;
    7152              : 
    7153              :         } // CycleOnCount > MaxCycles
    7154              : 
    7155              :     } // TimeRemaining > 0.0
    7156              : 
    7157              :     // Calculate average values over the DataGlobals::TimeStep based on summed values, Q > 0 is a gain to the tank,  Q < 0 is a loss to the tank
    7158          359 :     Real64 TankTempAvg_loc = Tsum / SecInTimeStep;
    7159          359 :     Qloss = Eloss / SecInTimeStep;
    7160          359 :     Real64 Qlosszone = Elosszone / SecInTimeStep;
    7161          359 :     Quse = Euse / SecInTimeStep;
    7162          359 :     Qsource = Esource / SecInTimeStep;
    7163          359 :     Qheater = Eheater / SecInTimeStep;
    7164          359 :     Qoffcycfuel = Eoffcycfuel / SecInTimeStep;
    7165          359 :     Qoffcycheat = Qoffcycfuel * this->OffCycParaFracToTank;
    7166          359 :     Qoncycfuel = Eoncycfuel / SecInTimeStep;
    7167          359 :     Qoncycheat = Qoncycfuel * this->OnCycParaFracToTank;
    7168          359 :     Qvent = Event / SecInTimeStep;
    7169          359 :     Qneeded = Eneeded / SecInTimeStep;
    7170          359 :     Qunmet = Eunmet / SecInTimeStep;
    7171          359 :     Real64 RTF = Runtime / SecInTimeStep;
    7172          359 :     PLR = PLRsum / SecInTimeStep;
    7173              : 
    7174          359 :     if (this->ControlType == HeaterControlMode::Cycle) {
    7175              :         // Recalculate Part Load Factor and fuel energy based on Runtime Fraction, instead of Part Load Ratio
    7176          359 :         PLF = this->PartLoadFactor(state, RTF);
    7177          359 :         Efuel = Eheater / (PLF * this->Efficiency);
    7178              :     }
    7179              : 
    7180          359 :     Qfuel = Efuel / SecInTimeStep;
    7181              : 
    7182          359 :     this->Mode = Mode_loc;               // Operating mode for carry-over to next DataGlobals::TimeStep
    7183          359 :     this->TankTemp = TankTemp_loc;       // Final tank temperature for carry-over to next DataGlobals::TimeStep
    7184          359 :     this->TankTempAvg = TankTempAvg_loc; // Average tank temperature over the DataGlobals::TimeStep for reporting
    7185              : 
    7186          359 :     if (!state.dataGlobal->WarmupFlag) {
    7187              :         // Warn for potential freezing when avg of final temp over all nodes is below 2°C (nearing 0°C)
    7188          287 :         if (this->TankTemp < 2) {
    7189            1 :             if (this->FreezingErrorIndex == 0) {
    7190            2 :                 ShowWarningError(state,
    7191            2 :                                  format("{}: {} = '{}':  Temperature of tank < 2C indicates of possibility of freeze. Tank Temperature = {:.2R} C.",
    7192              :                                         RoutineName,
    7193            1 :                                         this->Type,
    7194            1 :                                         this->Name,
    7195            1 :                                         this->TankTemp));
    7196            3 :                 ShowContinueErrorTimeStamp(state, "");
    7197              :             }
    7198            8 :             ShowRecurringWarningErrorAtEnd(state,
    7199            2 :                                            this->Type + " = '" + this->Name + "':  Temperature of tank < 2C indicates of possibility of freeze",
    7200            1 :                                            this->FreezingErrorIndex,
    7201            1 :                                            this->TankTemp, // Report Max
    7202            1 :                                            this->TankTemp, // Report Min
    7203              :                                            _,              // Don't report Sum
    7204              :                                            "{C}",          // Max Unit
    7205              :                                            "{C}");         // Min Unit
    7206              :         }
    7207              :     }
    7208          359 :     this->UseOutletTemp = TankTempAvg_loc;    // Because entire tank is at same temperature
    7209          359 :     this->SourceOutletTemp = TankTempAvg_loc; // Because entire tank is at same temperature
    7210          359 :     if (this->HeatPumpNum > 0) {
    7211           94 :         this->SourceInletTemp =
    7212           94 :             TankTempAvg_loc + HPWHCondenserDeltaT; // Update the source inlet temperature to the average over the DataGlobals::TimeStep
    7213              :     }
    7214              : 
    7215          359 :     this->LossRate = Qloss;
    7216          359 :     this->UseRate = Quse;
    7217          359 :     this->SourceRate = Qsource;
    7218          359 :     this->OffCycParaRateToTank = Qoffcycheat;
    7219          359 :     this->OnCycParaRateToTank = Qoncycheat;
    7220          359 :     this->TotalDemandRate = -Quse - Qsource - Qloss - Qoffcycheat - Qoncycheat;
    7221          359 :     this->HeaterRate = Qheater;
    7222          359 :     this->UnmetRate = Qunmet;
    7223          359 :     this->VentRate = Qvent;
    7224          359 :     this->NetHeatTransferRate = Quse + Qsource + Qloss + Qoffcycheat + Qoncycheat + Qheater + Qvent;
    7225              : 
    7226          359 :     this->CycleOnCount = CycleOnCount_loc;
    7227          359 :     this->RuntimeFraction = RTF;
    7228          359 :     this->PartLoadRatio = PLR;
    7229              : 
    7230          359 :     this->FuelRate = Qfuel;
    7231          359 :     this->OffCycParaFuelRate = Qoffcycfuel;
    7232          359 :     this->OnCycParaFuelRate = Qoncycfuel;
    7233              : 
    7234              :     // Add water heater skin losses and venting losses to ambient zone, if specified
    7235          359 :     if (this->AmbientTempZone > 0) this->AmbientZoneGain = -Qlosszone - Qvent;
    7236          359 : }
    7237              : 
    7238          361 : void WaterThermalTankData::CalcMixedTankSourceSideHeatTransferRate(
    7239              :     Real64 HPWHCondenserDeltaT, // input, The temperature difference (C) across the heat pump, zero if
    7240              :                                 // there is no heat pump or if the heat pump is off
    7241              :     Real64 SourceInletTemp,     // input, Source inlet temperature (C)
    7242              :     Real64 Cp,                  // Specific heat of fluid (J/kg deltaC)
    7243              :     Real64 SetPointTemp,        // input, Mixed tank set point temperature
    7244              :     Real64 &SourceMassFlowRate, // source mass flow rate (kg/s)
    7245              :     Real64 &Qheatpump,          // heat transfer rate from heat pump
    7246              :     Real64 &Qsource             // steady state heat transfer rate from a constant temperature source side flow
    7247              : )
    7248              : {
    7249              :     // Function Information:
    7250              :     //        Author: Noel Merket
    7251              :     //        Date Written: January 2015
    7252              :     //        Modified: na
    7253              :     //        Re-engineered: na
    7254              : 
    7255              :     // Purpose of this function:
    7256              :     // Determines if the source side heat transfer is coming from a heat pump.
    7257              :     // If so it treats the source side heat transfer as a constant heat source
    7258              :     // If it is not coming from a heat pump it treats the source side heat transfer
    7259              :     // as a constant temperature.
    7260              : 
    7261              :     // Determine if the source side heating is coming from a heat pump.
    7262          361 :     Qheatpump = SourceMassFlowRate * Cp * HPWHCondenserDeltaT;
    7263          361 :     if (Qheatpump > 0.0) {
    7264           12 :         SourceMassFlowRate = 0.0; // Handle this heating as a constant heat source
    7265           12 :         Qsource = Qheatpump;
    7266              :     } else {
    7267          349 :         Qsource = SourceMassFlowRate * Cp * (SourceInletTemp - SetPointTemp);
    7268              :     }
    7269          361 : }
    7270              : 
    7271          469 : Real64 WaterThermalTankData::CalcTimeNeeded(Real64 const Ti, // Initial tank temperature (C)
    7272              :                                             Real64 const Tf, // Final tank temperature (C)
    7273              :                                             Real64 const Ta, // Ambient environment temperature (C)
    7274              :                                             Real64 const T1, // Temperature of flow 1 (C)
    7275              :                                             Real64 const T2, // Temperature of flow 2 (C)
    7276              :                                             Real64 const m,  // Mass of tank fluid (kg)
    7277              :                                             Real64 const Cp, // Specific heat of fluid (J/kg deltaC)
    7278              :                                             Real64 const m1, // Mass flow rate 1 (kg/s)
    7279              :                                             Real64 const m2, // Mass flow rate 2 (kg/s)
    7280              :                                             Real64 const UA, // Heat loss coefficient to ambient environment (W/deltaC)
    7281              :                                             Real64 const Q   // Net heating rate for non-temp dependent sources, i.e. heater and parasitics (W)
    7282              : )
    7283              : {
    7284              : 
    7285              :     // SUBROUTINE INFORMATION:
    7286              :     //       AUTHOR         Peter Graham Ellis
    7287              :     //       DATE WRITTEN   February 2005
    7288              :     //       MODIFIED       na
    7289              :     //       RE-ENGINEERED  na
    7290              : 
    7291              :     // PURPOSE OF THIS SUBROUTINE:
    7292              :     // Calculates the time needed for the tank temperature to change from Ti to Tf given heat loss,
    7293              :     // mass flow rates and temperatures, and net heat transfer due to heater and parasitics.
    7294              : 
    7295              :     // METHODOLOGY EMPLOYED:
    7296              :     // Equations are derived by solving the differential equation governing the tank energy balance.
    7297              :     // Special cases which cause the natural logarithm to blow up are trapped and interpreted as
    7298              :     // requiring an infinite amount of time because Tf can never be reached under the given conditions.
    7299              : 
    7300              :     // Return value
    7301              :     Real64 CalcTimeNeeded;
    7302              : 
    7303              :     // SUBROUTINE PARAMETER DEFINITIONS:
    7304          469 :     Real64 constexpr Infinity(99999999.9); // A time interval much larger than any single DataGlobals::TimeStep (s)
    7305              : 
    7306              :     Real64 t; // Time elapsed from Ti to Tf (s)
    7307              : 
    7308          469 :     if (Tf == Ti) {
    7309              :         // Already at Tf; no time is needed
    7310            0 :         t = 0.0;
    7311              : 
    7312              :     } else {
    7313              :         Real64 a;        // Intermediate variable
    7314              :         Real64 b;        // Intermediate variable
    7315              :         Real64 Tm;       // Mixed temperature after an infinite amount of time has passed (C)
    7316              :         Real64 quotient; // Intermediate variable
    7317              : 
    7318          469 :         if (UA / Cp + m1 + m2 == 0.0) {
    7319              : 
    7320           55 :             if (Q == 0.0) {
    7321              :                 // With no mass flow and no heat flow and Tf<>Ti, then Tf can never be reached
    7322           42 :                 t = Infinity;
    7323              : 
    7324              :             } else {
    7325           13 :                 a = Q / (m * Cp);
    7326              : 
    7327           13 :                 t = (Tf - Ti) / a;
    7328              :             }
    7329              : 
    7330              :         } else {
    7331          414 :             a = (Q / Cp + UA * Ta / Cp + m1 * T1 + m2 * T2) / m;
    7332          414 :             b = -(UA / Cp + m1 + m2) / m;
    7333              : 
    7334              :             // Calculate the mixed temperature Tm of the tank after an infinite amount of time has passed
    7335          414 :             Tm = -a / b;
    7336              : 
    7337          414 :             if (Tm == Ti) {
    7338              :                 // Mixed temperature is the same as Ti; if Tf<>Ti, then Tf can never be reached
    7339            2 :                 t = Infinity;
    7340              : 
    7341          412 :             } else if (Tm == Tf) {
    7342              :                 // Tf only approaches Tm; it can never actually get there in finite time (also avoids divide by zero error)
    7343            0 :                 t = Infinity;
    7344              : 
    7345              :             } else {
    7346          412 :                 quotient = (Tf - Tm) / (Ti - Tm);
    7347              : 
    7348          412 :                 if (quotient <= 0.0) { // Autodesk:Num Changed < to <= to elim poss floating point error in LOG call
    7349              :                     // Tm is in between Ti and Tf; Tf can never be reached
    7350            7 :                     t = Infinity;
    7351              : 
    7352              :                 } else {
    7353          405 :                     t = std::log(quotient) / b;
    7354              :                 }
    7355              :             }
    7356              :         }
    7357              : 
    7358          469 :         if (t < 0.0) t = Infinity; // If negative time, Tf can never be reached in the future
    7359              :     }
    7360              : 
    7361          469 :     CalcTimeNeeded = t;
    7362              : 
    7363          469 :     return CalcTimeNeeded;
    7364              : }
    7365              : 
    7366          359 : Real64 WaterThermalTankData::CalcTankTemp(Real64 const Ti, // Initial tank temperature (C)
    7367              :                                           Real64 const Ta, // Ambient environment temperature (C)
    7368              :                                           Real64 const T1, // Temperature of flow 1 (C)
    7369              :                                           Real64 const T2, // Temperature of flow 2 (C)
    7370              :                                           Real64 const m,  // Mass of tank fluid (kg)
    7371              :                                           Real64 const Cp, // Specific heat of fluid (J/kg deltaC)
    7372              :                                           Real64 const m1, // Mass flow rate 1 (kg/s)
    7373              :                                           Real64 const m2, // Mass flow rate 2 (kg/s)
    7374              :                                           Real64 const UA, // Heat loss coefficient to ambient environment (W/deltaC)
    7375              :                                           Real64 const Q,  // Net heating rate for non-temp dependent sources, i.e. heater and parasitics (W)
    7376              :                                           Real64 const t   // Time elapsed from Ti to Tf (s)
    7377              : )
    7378              : {
    7379              : 
    7380              :     // SUBROUTINE INFORMATION:
    7381              :     //       AUTHOR         Peter Graham Ellis
    7382              :     //       DATE WRITTEN   February 2005
    7383              :     //       MODIFIED       na
    7384              :     //       RE-ENGINEERED  na
    7385              : 
    7386              :     // PURPOSE OF THIS SUBROUTINE:
    7387              :     // Calculates the final tank temperature Tf after time t has elapsed given heat loss,
    7388              :     // mass flow rates and temperatures, and net heat transfer due to heater and parasitics.
    7389              : 
    7390              :     // METHODOLOGY EMPLOYED:
    7391              :     // Equations are derived by solving the differential equation governing the tank energy balance.
    7392              : 
    7393              :     // Return value
    7394              :     Real64 CalcTankTemp;
    7395              : 
    7396              :     // Locals
    7397              :     // SUBROUTINE ARGUMENT DEFINITIONS:
    7398              : 
    7399              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    7400              :     Real64 a;  // Intermediate variable
    7401              :     Real64 b;  // Intermediate variable
    7402              :     Real64 Tf; // Final tank temperature (C)
    7403              : 
    7404          359 :     if (UA / Cp + m1 + m2 == 0.0) {
    7405           53 :         a = Q / (m * Cp);
    7406              : 
    7407           53 :         Tf = a * t + Ti;
    7408              : 
    7409              :     } else {
    7410          306 :         a = (Q / Cp + UA * Ta / Cp + m1 * T1 + m2 * T2) / m;
    7411          306 :         b = -(UA / Cp + m1 + m2) / m;
    7412              : 
    7413          306 :         Tf = (a / b + Ti) * std::exp(b * t) - a / b;
    7414              :     }
    7415              : 
    7416          359 :     CalcTankTemp = Tf;
    7417              : 
    7418          359 :     return CalcTankTemp;
    7419              : }
    7420              : 
    7421          473 : Real64 WaterThermalTankData::CalcTempIntegral(Real64 const Ti, // Initial tank temperature (C)
    7422              :                                               Real64 const Tf, // Final tank temperature (C)
    7423              :                                               Real64 const Ta, // Ambient environment temperature (C)
    7424              :                                               Real64 const T1, // Temperature of flow 1 (C)
    7425              :                                               Real64 const T2, // Temperature of flow 2 (C)
    7426              :                                               Real64 const m,  // Mass of tank fluid (kg)
    7427              :                                               Real64 const Cp, // Specific heat of fluid (J/kg deltaC)
    7428              :                                               Real64 const m1, // Mass flow rate 1 (kg/s)
    7429              :                                               Real64 const m2, // Mass flow rate 2 (kg/s)
    7430              :                                               Real64 const UA, // Heat loss coefficient to ambient environment (W/deltaC)
    7431              :                                               Real64 const Q,  // Net heating rate for non-temp dependent sources, i.e. heater and parasitics (W)
    7432              :                                               Real64 const t   // Time elapsed from Ti to Tf (s)
    7433              : )
    7434              : {
    7435              : 
    7436              :     // SUBROUTINE INFORMATION:
    7437              :     //       AUTHOR         Peter Graham Ellis
    7438              :     //       DATE WRITTEN   February 2005
    7439              :     //       MODIFIED       na
    7440              :     //       RE-ENGINEERED  na
    7441              : 
    7442              :     // PURPOSE OF THIS SUBROUTINE:
    7443              :     // Calculates the integral of the tank temperature from Ti to Tf.  The integral is added to a sum which is
    7444              :     // later divided by the elapsed time to yield the average tank temperature over the DataGlobals::TimeStep.
    7445              : 
    7446              :     // METHODOLOGY EMPLOYED:
    7447              :     // Equations are the mathematical integrals of the governing differential equations.
    7448              : 
    7449              :     // Return value
    7450              :     Real64 CalcTempIntegral;
    7451              : 
    7452              :     // Locals
    7453              :     // SUBROUTINE ARGUMENT DEFINITIONS:
    7454              : 
    7455              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    7456              :     Real64 a;     // Intermediate variable
    7457              :     Real64 b;     // Intermediate variable
    7458              :     Real64 dTsum; // Integral of tank temperature (C s)
    7459              : 
    7460          473 :     if (t == 0.0) {
    7461            1 :         dTsum = 0.0;
    7462              : 
    7463          472 :     } else if (Tf == Ti) { // Steady-state conditions
    7464           45 :         dTsum = Tf * t;
    7465              : 
    7466          427 :     } else if (UA / Cp + m1 + m2 == 0.0) {
    7467           14 :         a = Q / (m * Cp);
    7468              : 
    7469              :         // Integral of T(t) = a * t + Ti, evaluated from 0 to t
    7470           14 :         dTsum = 0.5 * a * t * t + Ti * t;
    7471              : 
    7472              :     } else {
    7473          413 :         a = (Q / Cp + UA * Ta / Cp + m1 * T1 + m2 * T2) / m;
    7474          413 :         b = -(UA / Cp + m1 + m2) / m;
    7475              : 
    7476              :         // Integral of T(t) = (a / b + Ti) * EXP(b * t) - a / b, evaluated from 0 to t
    7477          413 :         dTsum = (a / b + Ti) * (std::exp(b * t) - 1.0) / b - a * t / b;
    7478              :     }
    7479              : 
    7480          473 :     CalcTempIntegral = dTsum;
    7481              : 
    7482          473 :     return CalcTempIntegral;
    7483              : }
    7484              : 
    7485          447 : Real64 WaterThermalTankData::PartLoadFactor(EnergyPlusData &state, Real64 const PartLoadRatio_loc)
    7486              : {
    7487              : 
    7488              :     // SUBROUTINE INFORMATION:
    7489              :     //       AUTHOR         Peter Graham Ellis
    7490              :     //       DATE WRITTEN   January 2005
    7491              :     //       MODIFIED       na
    7492              :     //       RE-ENGINEERED  na
    7493              : 
    7494              :     // PURPOSE OF THIS SUBROUTINE:
    7495              :     // Calculates the Part Load Factor (PLF) based on a curve correlated to Part Load Ratio, if Heater Control Type
    7496              :     // is MODULATE, or correlated to Runtime Fraction, if Heater Control Type is CYCLE.
    7497              : 
    7498          447 :     if (this->PLFCurve > 0) {
    7499          103 :         return max(Curve::CurveValue(state, this->PLFCurve, PartLoadRatio_loc), 0.1);
    7500              :     } else {
    7501          344 :         return 1.0;
    7502              :     }
    7503              : }
    7504              : 
    7505         1462 : void WaterThermalTankData::CalcWaterThermalTankStratified(EnergyPlusData &state)
    7506              : {
    7507              :     // SUBROUTINE INFORMATION:
    7508              :     //       AUTHOR         Noel Merket, originally by Peter Graham Ellis
    7509              :     //       DATE WRITTEN   January 2007
    7510              :     //       MODIFIED       Nov 2011, BAN; modified the use and source outlet temperature calculation
    7511              :     //       RE-ENGINEERED  Noel Merket, November 2018
    7512              : 
    7513              :     // PURPOSE OF THIS SUBROUTINE:
    7514              :     // Simulates a stratified, multi-node water heater tank with up to two heating elements.
    7515              : 
    7516              :     // METHODOLOGY EMPLOYED:
    7517              :     // This model uses a numerical calculation based on an analytical solution of the ODE dT/dt = a*T + b.
    7518              :     // A heat balance is calculated for each node.
    7519              :     // Temperatures and energies change dynamically over the system time step.
    7520              :     // Final node temperatures are reported as final instantaneous values as well as averages over the
    7521              :     // time step.  Heat transfer rates are averages over the time step.
    7522              : 
    7523              :     static constexpr std::string_view RoutineName("CalcWaterThermalTankStratified");
    7524         1462 :     constexpr Real64 TemperatureConvergenceCriteria = 0.0001;
    7525         1462 :     constexpr Real64 SubTimestepMax = 60.0 * 10.0; // seconds
    7526         1462 :     constexpr Real64 SubTimestepMin = 10.0;        // seconds
    7527              :     Real64 dt;
    7528              : 
    7529              :     // Tank object reference
    7530         1462 :     const Real64 &nTankNodes = this->Nodes;
    7531              : 
    7532              :     // Fraction of the current hour that has elapsed (h)
    7533              :     const Real64 TimeElapsed_loc =
    7534         1462 :         state.dataGlobal->HourOfDay + state.dataGlobal->TimeStep * state.dataGlobal->TimeStepZone + state.dataHVACGlobal->SysTimeElapsed;
    7535              : 
    7536              :     // Seconds in one DataGlobals::TimeStep (s)
    7537         1462 :     const Real64 SecInTimeStep = state.dataHVACGlobal->TimeStepSysSec;
    7538              : 
    7539              :     // Advance tank simulation to the next system DataGlobals::TimeStep, if applicable
    7540         1462 :     if (this->TimeElapsed != TimeElapsed_loc) {
    7541              :         // The simulation has advanced to the next system DataGlobals::TimeStep.  Save conditions from the end of the previous system
    7542              :         // DataGlobals::TimeStep for use as the initial conditions of each iteration that does not advance the system DataGlobals::TimeStep.
    7543           57 :         for (auto &e : this->Node)
    7544           52 :             e.SavedTemp = e.Temp;
    7545              : 
    7546            5 :         this->SavedHeaterOn1 = this->HeaterOn1;
    7547            5 :         this->SavedHeaterOn2 = this->HeaterOn2;
    7548              : 
    7549              :         // Save outlet temperatures for demand-side flow control
    7550            5 :         this->SavedUseOutletTemp = this->UseOutletTemp;
    7551            5 :         this->SavedSourceOutletTemp = this->SourceOutletTemp;
    7552              : 
    7553            5 :         this->TimeElapsed = TimeElapsed_loc;
    7554              :     }
    7555              : 
    7556              :     // Reset node temperatures to what they were at the beginning of the system DataGlobals::TimeStep.
    7557        18996 :     for (auto &e : this->Node)
    7558        17534 :         e.Temp = e.SavedTemp;
    7559              : 
    7560         1462 :     this->HeaterOn1 = this->SavedHeaterOn1;
    7561         1462 :     this->HeaterOn2 = this->SavedHeaterOn2;
    7562              : 
    7563              :     // Condenser configuration of heat pump water heater
    7564              :     const DataPlant::PlantEquipmentType HPWHCondenserConfig =
    7565         1462 :         this->HeatPumpNum > 0 ? state.dataWaterThermalTanks->HPWaterHeater(this->HeatPumpNum).HPWHType : DataPlant::PlantEquipmentType::Invalid;
    7566              : 
    7567              :     // Heat rate from the heat pump (W)
    7568            0 :     const Real64 Qheatpump = [&, this] { // BLB
    7569         1462 :         if (this->HeatPumpNum == 0) return 0.0;
    7570            9 :         HeatPumpWaterHeaterData const &HPWH = state.dataWaterThermalTanks->HPWaterHeater(this->HeatPumpNum);
    7571              :         Real64 CoilTotalHeatingEnergyRate;
    7572            9 :         if (HPWH.NumofSpeed > 0) {
    7573              :             // VSHPWH
    7574            0 :             VariableSpeedCoils::VariableSpeedCoilData const &Coil = state.dataVariableSpeedCoils->VarSpeedCoil(HPWH.DXCoilNum);
    7575            0 :             CoilTotalHeatingEnergyRate = Coil.TotalHeatingEnergyRate;
    7576              :         } else {
    7577              :             // Single speed HPWH
    7578            9 :             DXCoils::DXCoilData const &Coil = state.dataDXCoils->DXCoil(HPWH.DXCoilNum);
    7579            9 :             CoilTotalHeatingEnergyRate = Coil.TotalHeatingEnergyRate;
    7580              :         }
    7581            9 :         return CoilTotalHeatingEnergyRate * this->SourceEffectiveness;
    7582         1462 :     }();
    7583              : 
    7584              :     // Minimum tank temperatures
    7585         1462 :     const Real64 MinTemp1 = this->SetPointTemp - this->DeadBandDeltaTemp;
    7586         1462 :     const Real64 MinTemp2 = this->SetPointTemp2 - this->DeadBandDeltaTemp2;
    7587              : 
    7588              :     // Specific Heat of water (J/kg K)
    7589            0 :     const Real64 Cp = [&] {
    7590         1462 :         if (this->UseSidePlantLoc.loopNum > 0) {
    7591            0 :             return state.dataPlnt->PlantLoop(this->UseSidePlantLoc.loopNum).glycol->getSpecificHeat(state, this->TankTemp, RoutineName);
    7592              :         } else {
    7593         1462 :             return this->water->getSpecificHeat(state, this->TankTemp, RoutineName);
    7594              :         }
    7595         1462 :     }();
    7596              : 
    7597         1462 :     Real64 Eloss = 0.0;             // Energy change due to ambient losses over the DataGlobals::TimeStep (J)
    7598         1462 :     Real64 Euse = 0.0;              // Energy change due to use side mass flow over the DataGlobals::TimeStep (J)
    7599         1462 :     Real64 Esource = 0.0;           // Energy change due to source side mass flow over the DataGlobals::TimeStep (J)
    7600         1462 :     Real64 Eheater1 = 0.0;          // Energy change due to heater 1 over the DataGlobals::TimeStep (J)
    7601         1462 :     Real64 Eheater2 = 0.0;          // Energy change due to heater 2 over the DataGlobals::TimeStep (J)
    7602         1462 :     Real64 Eunmet = 0.0;            // Energy change unmet over the DataGlobals::TimeStep (J)
    7603         1462 :     Real64 Event = 0.0;             // Energy change due to venting over the DataGlobals::TimeStep (J)
    7604         1462 :     int CycleOnCount1_loc = 0;      // Number of times heater 1 cycles on in the current time step
    7605         1462 :     int CycleOnCount2_loc = 0;      // Number of times heater 2 cycles on in the current time step
    7606         1462 :     Real64 Runtime = 0.0;           // Time that either heater is running (s)
    7607         1462 :     Real64 Runtime1 = 0.0;          // Time that heater 1 is running (s)
    7608         1462 :     Real64 Runtime2 = 0.0;          // Time that heater 2 is running (s)
    7609         1462 :     bool SetPointRecovered = false; // Flag to indicate when set point is recovered for the first time
    7610              :     // Added three variables for desuperheater sourceinlet temperature update
    7611              :     Real64 MdotDesuperheaterWater;        // mass flow rate of desuperheater source side water, kg/s
    7612         1462 :     Real64 DesuperheaterPLR = 0.0;        // Desuperheater part load ratio
    7613         1462 :     Real64 DesuperheaterHeaterRate = 0.0; // Desuperheater heater rate (W)
    7614         1462 :     Real64 SourceInletTempSum = 0.0;      // Sum the source inlet temperature in sub time step to calculate average tempearature
    7615              :     Real64 Qheater1;                      // Heating rate of burner or electric heating element 1 (W)
    7616              :     Real64 Qheater2;                      // Heating rate of burner or electric heating element 2 (W)
    7617              : 
    7618         1462 :     if (this->InletMode == InletPositionMode::Fixed) CalcNodeMassFlows(InletPositionMode::Fixed);
    7619              : 
    7620              :     // Time remaining in the current DataGlobals::TimeStep (s)
    7621         1462 :     Real64 TimeRemaining = SecInTimeStep;
    7622              : 
    7623              :     // Diff Eq. Coefficients for each node
    7624         1462 :     std::vector<Real64> A;
    7625         1462 :     A.resize(nTankNodes);
    7626         1462 :     std::vector<Real64> B;
    7627         1462 :     B.resize(nTankNodes);
    7628              : 
    7629              :     // Temperature at the end of the internal DataGlobals::TimeStep
    7630         1462 :     std::vector<Real64> Tfinal;
    7631         1462 :     Tfinal.resize(nTankNodes);
    7632              : 
    7633              :     // Average temperature of each node over the internal DataGlobals::TimeStep
    7634         1462 :     std::vector<Real64> Tavg;
    7635         1462 :     Tavg.resize(nTankNodes);
    7636              : 
    7637         1462 :     int SubTimestepCount = 0;
    7638              : 
    7639         4895 :     while (TimeRemaining > 0.0) {
    7640              : 
    7641         3433 :         ++SubTimestepCount;
    7642              : 
    7643         3433 :         bool PrevHeaterOn1 = this->HeaterOn1;
    7644         3433 :         bool PrevHeaterOn2 = this->HeaterOn2;
    7645              : 
    7646         3433 :         if (this->InletMode == InletPositionMode::Seeking) CalcNodeMassFlows(InletPositionMode::Seeking);
    7647              : 
    7648              :         // Heater control logic
    7649         3433 :         if (this->IsChilledWaterTank) {
    7650              :             // Chilled Water Tank, no heating
    7651           21 :             Qheater1 = 0.0;
    7652           21 :             Qheater2 = 0.0;
    7653              :         } else {
    7654              :             // Control the first heater element (master)
    7655         3412 :             if (this->MaxCapacity > 0.0) {
    7656         3408 :                 const Real64 &NodeTemp = this->Node(this->HeaterNode1).Temp;
    7657              : 
    7658         3408 :                 if (this->HeaterOn1) {
    7659           30 :                     if (NodeTemp >= this->SetPointTemp) {
    7660            1 :                         this->HeaterOn1 = false;
    7661            1 :                         SetPointRecovered = true;
    7662              :                     }
    7663              :                 } else { // Heater is off
    7664         3378 :                     if (NodeTemp < MinTemp1) {
    7665            2 :                         this->HeaterOn1 = true;
    7666            2 :                         ++CycleOnCount1_loc;
    7667              :                     }
    7668              :                 }
    7669              :             }
    7670              : 
    7671         3412 :             if (this->HeaterOn1) {
    7672           31 :                 Qheater1 = this->MaxCapacity;
    7673              :             } else {
    7674         3381 :                 Qheater1 = 0.0;
    7675              :             }
    7676              : 
    7677              :             // Control the second heater element (slave)
    7678         3412 :             if (this->MaxCapacity2 > 0.0) {
    7679         3410 :                 if ((this->StratifiedControlMode == PriorityControlMode::MasterSlave) && this->HeaterOn1) {
    7680           31 :                     this->HeaterOn2 = false;
    7681              : 
    7682              :                 } else {
    7683         3379 :                     const Real64 &NodeTemp = this->Node(this->HeaterNode2).Temp;
    7684              : 
    7685         3379 :                     if (this->HeaterOn2) {
    7686          755 :                         if (NodeTemp >= this->SetPointTemp2) {
    7687           19 :                             this->HeaterOn2 = false;
    7688           19 :                             SetPointRecovered = true;
    7689              :                         }
    7690              :                     } else { // Heater is off
    7691         2624 :                         if (NodeTemp < MinTemp2) {
    7692           20 :                             this->HeaterOn2 = true;
    7693           20 :                             ++CycleOnCount2_loc;
    7694              :                         }
    7695              :                     }
    7696              :                 }
    7697              :             }
    7698              : 
    7699         3412 :             if (this->HeaterOn2) {
    7700          756 :                 Qheater2 = this->MaxCapacity2;
    7701              :             } else {
    7702         2656 :                 Qheater2 = 0.0;
    7703              :             }
    7704              :         }
    7705              : 
    7706         3433 :         if (SubTimestepCount == 1) {
    7707         1462 :             dt = SubTimestepMin;
    7708              :         } else {
    7709              : 
    7710              :             // Set the maximum tank temperature change allowed
    7711         1971 :             Real64 dT_max = std::numeric_limits<Real64>::max();
    7712         1971 :             if (this->HeaterOn1) {
    7713           31 :                 if (this->Node(this->HeaterNode1).Temp < this->SetPointTemp) {
    7714              :                     // Node temperature is less than setpoint and heater is on
    7715           31 :                     dT_max = min(dT_max, this->SetPointTemp - this->Node(this->HeaterNode1).Temp);
    7716              :                 } else {
    7717              :                     // Node temperature is greater than or equal to setpoint and heater is on
    7718              :                     // Heater will turn off next time around, calculate assuming that
    7719            0 :                     dT_max = min(dT_max, this->Node(this->HeaterNode1).Temp - MinTemp1);
    7720              :                 }
    7721              :             } else { // Heater off
    7722         1940 :                 if (this->Node(this->HeaterNode1).Temp >= MinTemp1) {
    7723              :                     // Node temperature is greater than or equal to cut in temperature and heater is off
    7724         1940 :                     dT_max = min(dT_max, this->Node(this->HeaterNode1).Temp - MinTemp1);
    7725              :                 } else {
    7726              :                     // Heater will turn on next time around, calculate to setpoint
    7727            0 :                     dT_max = min(dT_max, this->SetPointTemp - this->Node(this->HeaterNode1).Temp);
    7728              :                 }
    7729              :             }
    7730         1971 :             if (this->HeaterOn2) {
    7731          590 :                 if (this->Node(this->HeaterNode2).Temp < this->SetPointTemp2) {
    7732              :                     // Node temperature is less than setpoint and heater is on
    7733          590 :                     dT_max = min(dT_max, this->SetPointTemp2 - this->Node(this->HeaterNode2).Temp);
    7734              :                 } else {
    7735              :                     // Node temperature is greater than or equal to setpoint and heater is on
    7736              :                     // Heater will turn off next time around, calculate assuming that
    7737            0 :                     dT_max = min(dT_max, this->Node(this->HeaterNode2).Temp - MinTemp2);
    7738              :                 }
    7739              :             } else { // Heater off
    7740         1381 :                 if (this->Node(this->HeaterNode2).Temp >= MinTemp2) {
    7741              :                     // Node temperature is greater than or equal to cut in temperature and heater is off
    7742         1338 :                     dT_max = min(dT_max, this->Node(this->HeaterNode2).Temp - MinTemp2);
    7743              :                 } else {
    7744              :                     // Heater will turn on next time around, calculate to setpoint
    7745           43 :                     dT_max = min(dT_max, this->SetPointTemp2 - this->Node(this->HeaterNode2).Temp);
    7746              :                 }
    7747              :             }
    7748              : 
    7749              :             // Make adjustments to A and B to account for heaters being on or off now
    7750         1971 :             if (this->HeaterOn1 && !PrevHeaterOn1) {
    7751              :                 // If heater 1 is on now and wasn't before add the heat rate to the B term
    7752            2 :                 B[this->HeaterNode1 - 1] += Qheater1 / (this->Node(this->HeaterNode1).Mass * Cp);
    7753         1969 :             } else if (!this->HeaterOn1 && PrevHeaterOn1) {
    7754              :                 // If heater 1 is off now and was on before, remove the heat rate from the B term
    7755            1 :                 B[this->HeaterNode1 - 1] -= this->MaxCapacity / (this->Node(this->HeaterNode1).Mass * Cp);
    7756              :             }
    7757         1971 :             if (this->HeaterOn2 && !PrevHeaterOn2) {
    7758              :                 // If heater 2 is on now and wasn't before add the heat rate to the B term
    7759           20 :                 B[this->HeaterNode2 - 1] += Qheater2 / (this->Node(this->HeaterNode2).Mass * Cp);
    7760         1951 :             } else if (!this->HeaterOn2 && PrevHeaterOn2) {
    7761              :                 // If heater 1 is off now and was on before, remove the heat rate from the B term
    7762           19 :                 B[this->HeaterNode2 - 1] -= this->MaxCapacity / (this->Node(this->HeaterNode2).Mass * Cp);
    7763              :             }
    7764              : 
    7765         1971 :             if ((this->HeaterOn1 || this->HeaterOn2) && !(PrevHeaterOn1 || PrevHeaterOn2)) {
    7766              :                 // Remove off cycle loads
    7767              :                 // Apply on cycle loads
    7768          273 :                 for (int i = 0; i < nTankNodes; i++) {
    7769          252 :                     auto const &node = this->Node[i];
    7770          252 :                     Real64 NodeCapacitance = node.Mass * Cp;
    7771          252 :                     A[i] += (node.OffCycLossCoeff - node.OnCycLossCoeff) / NodeCapacitance;
    7772          252 :                     B[i] += (-node.OffCycParaLoad + node.OnCycParaLoad + (node.OnCycLossCoeff - node.OffCycLossCoeff) * this->AmbientTemp) /
    7773              :                             NodeCapacitance;
    7774              :                 }
    7775         1971 :             } else if (!(this->HeaterOn1 || this->HeaterOn2) && (PrevHeaterOn1 || PrevHeaterOn2)) {
    7776              :                 // Remove on cycle loads
    7777              :                 // Apply off cycle loads
    7778          247 :                 for (int i = 0; i < nTankNodes; i++) {
    7779          228 :                     auto const &node = this->Node[i];
    7780          228 :                     Real64 NodeCapacitance = node.Mass * Cp;
    7781          228 :                     A[i] -= (node.OffCycLossCoeff - node.OnCycLossCoeff) / NodeCapacitance;
    7782          228 :                     B[i] -= (-node.OffCycParaLoad + node.OnCycParaLoad + (node.OnCycLossCoeff - node.OffCycLossCoeff) * this->AmbientTemp) /
    7783              :                             NodeCapacitance;
    7784              :                 }
    7785              :             }
    7786              : 
    7787              :             // Set the sub DataGlobals::TimeStep (dt)
    7788         1971 :             dt = TimeRemaining;
    7789        25499 :             for (int i = 0; i < nTankNodes; ++i) {
    7790        23528 :                 const Real64 Denominator = fabs(A[i] * Tavg[i] + B[i]);
    7791        23528 :                 if (Denominator != 0.0) dt = min(dt, dT_max / Denominator);
    7792              :             }
    7793         1971 :             dt = max(min(SubTimestepMin, TimeRemaining), dt);
    7794         1971 :             dt = min(SubTimestepMax, dt);
    7795              :         }
    7796              : 
    7797              :         // Make initial guess that average and final temperatures over the DataGlobals::TimeStep are equal to the starting temperatures
    7798        44495 :         for (int i = 0; i < nTankNodes; i++) {
    7799        41062 :             const auto &NodeTemp = this->Node[i].Temp;
    7800        41062 :             Tfinal[i] = NodeTemp;
    7801        41062 :             Tavg[i] = NodeTemp;
    7802              :         }
    7803              : 
    7804         7686 :         for (int ConvergenceCounter = 1; ConvergenceCounter <= 10; ConvergenceCounter++) {
    7805              : 
    7806         7684 :             std::fill(A.begin(), A.end(), 0.0);
    7807         7684 :             std::fill(B.begin(), B.end(), 0.0);
    7808              : 
    7809              :             // Heater Coefficients
    7810         7684 :             B[this->HeaterNode1 - 1] += Qheater1;
    7811         7684 :             B[this->HeaterNode2 - 1] += Qheater2;
    7812              : 
    7813        99620 :             for (int i = 0; i < nTankNodes; i++) {
    7814        91936 :                 const int NodeNum = i + 1;
    7815        91936 :                 const auto &tank_node = this->Node(NodeNum);
    7816              : 
    7817              :                 // Parasitic Loads and Losses to Ambient
    7818        91936 :                 if (this->HeaterOn1 || this->HeaterOn2) {
    7819              :                     // Parasitic Loads
    7820        27120 :                     B[i] += tank_node.OnCycParaLoad;
    7821              :                     // Losses to Ambient
    7822        27120 :                     A[i] += -tank_node.OnCycLossCoeff;
    7823        27120 :                     B[i] += tank_node.OnCycLossCoeff * this->AmbientTemp;
    7824              :                 } else {
    7825              :                     // Parasitic Loads
    7826        64816 :                     B[i] += tank_node.OffCycParaLoad;
    7827              :                     // Losses to Ambient
    7828        64816 :                     A[i] += -tank_node.OffCycLossCoeff;
    7829        64816 :                     B[i] += tank_node.OffCycLossCoeff * this->AmbientTemp;
    7830              :                 }
    7831              : 
    7832              :                 // Conduction to adjacent nodes
    7833        91936 :                 A[i] += -(tank_node.CondCoeffDn + tank_node.CondCoeffUp);
    7834        91936 :                 if (NodeNum > 1) B[i] += tank_node.CondCoeffUp * Tavg[i - 1];
    7835        91936 :                 if (NodeNum < nTankNodes) B[i] += tank_node.CondCoeffDn * Tavg[i + 1];
    7836              : 
    7837              :                 // Use side plant connection
    7838        91936 :                 const Real64 use_e_mdot_cp = tank_node.UseMassFlowRate * Cp;
    7839        91936 :                 A[i] += -use_e_mdot_cp;
    7840        91936 :                 B[i] += use_e_mdot_cp * this->UseInletTemp;
    7841              : 
    7842              :                 // Source side heat transfer rate
    7843        91936 :                 if ((this->HeatPumpNum > 0) && (HPWHCondenserConfig == DataPlant::PlantEquipmentType::HeatPumpWtrHeaterPumped)) {
    7844              :                     // Pumped Condenser Heat Pump Water Heater
    7845            0 :                     if (tank_node.SourceMassFlowRate > 0.0) B[i] += Qheatpump;
    7846              :                 } else {
    7847              :                     // Source side plant connection (constant temperature)
    7848        91936 :                     const Real64 src_e_mdot_cp = tank_node.SourceMassFlowRate * Cp;
    7849        91936 :                     A[i] += -src_e_mdot_cp;
    7850        91936 :                     B[i] += src_e_mdot_cp * this->SourceInletTemp;
    7851              :                 }
    7852              : 
    7853              :                 // Wrapped condenser heat pump water heater
    7854        91936 :                 if ((this->HeatPumpNum > 0) && (HPWHCondenserConfig == DataPlant::PlantEquipmentType::HeatPumpWtrHeaterWrapped)) {
    7855          624 :                     B[i] += Qheatpump * tank_node.HPWHWrappedCondenserHeatingFrac;
    7856              :                 }
    7857              : 
    7858              :                 // Internodal flow
    7859        91936 :                 A[i] += -(tank_node.MassFlowFromUpper + tank_node.MassFlowFromLower) * Cp;
    7860        91936 :                 if (NodeNum > 1) B[i] += tank_node.MassFlowFromUpper * Cp * Tavg[i - 1];
    7861        91936 :                 if (NodeNum < nTankNodes) B[i] += tank_node.MassFlowFromLower * Cp * Tavg[i + 1];
    7862              : 
    7863              :                 // Divide by mass and specific heat
    7864              :                 // m * cp * dT/dt = q_net  =>  dT/dt = a * T + b
    7865        91936 :                 A[i] /= tank_node.Mass * Cp;
    7866        91936 :                 B[i] /= tank_node.Mass * Cp;
    7867              : 
    7868              :             } // end for each node
    7869              : 
    7870              :             // Calculate the average and final temperatures over the interval
    7871         7684 :             Real64 TfinalDiff = 0.0;
    7872        99620 :             for (int i = 0; i < nTankNodes; ++i) {
    7873        91936 :                 const Real64 Tstart = this->Node[i].Temp;
    7874        91936 :                 const Real64 b_a = B[i] / A[i];
    7875        91936 :                 const Real64 e_a_dt = exp(A[i] * dt);
    7876        91936 :                 Tavg[i] = (Tstart + b_a) * (e_a_dt - 1.0) / (A[i] * dt) - b_a;
    7877        91936 :                 const Real64 Tfinal_old = Tfinal[i];
    7878        91936 :                 Tfinal[i] = (Tstart + b_a) * e_a_dt - b_a;
    7879        91936 :                 TfinalDiff = max(fabs(Tfinal[i] - Tfinal_old), TfinalDiff);
    7880              :             }
    7881              : 
    7882         7684 :             if (TfinalDiff < TemperatureConvergenceCriteria) break;
    7883              : 
    7884         4253 :             if (this->DesuperheaterNum > 0) {
    7885         3869 :                 DesuperheaterPLR = state.dataWaterThermalTanks->WaterHeaterDesuperheater(this->DesuperheaterNum).DesuperheaterPLR;
    7886         3869 :                 DesuperheaterHeaterRate = state.dataWaterThermalTanks->WaterHeaterDesuperheater(this->DesuperheaterNum).HeaterRate;
    7887         3869 :                 MdotDesuperheaterWater = state.dataWaterThermalTanks->WaterHeaterDesuperheater(this->DesuperheaterNum).OperatingWaterFlowRate *
    7888         3869 :                                          Psychrometrics::RhoH2O(Tavg[this->SourceOutletStratNode - 1]);
    7889         3869 :                 if (DesuperheaterPLR > 0.0 && MdotDesuperheaterWater > 0.0) {
    7890           17 :                     this->SourceInletTemp =
    7891           17 :                         Tavg[this->SourceOutletStratNode - 1] + (DesuperheaterHeaterRate / DesuperheaterPLR) / (MdotDesuperheaterWater * Cp);
    7892              :                 } else {
    7893         3852 :                     this->SourceInletTemp = Tavg[this->SourceOutletStratNode - 1];
    7894              :                 }
    7895              :             }
    7896              :         } // end temperature convergence loop
    7897              : 
    7898              :         // Inversion mixing
    7899              :         bool HasInversion;
    7900         8108 :         do {
    7901         8108 :             HasInversion = false;
    7902              :             // Starting from the top of the tank check if the node below has a temperature inversion.
    7903        56318 :             for (int j = 0; j < nTankNodes - 1; ++j) {
    7904        52885 :                 if (Tfinal[j] < Tfinal[j + 1]) {
    7905              : 
    7906              :                     // Temperature inversion!
    7907         4675 :                     HasInversion = true;
    7908              : 
    7909              :                     // From the node above the inversion, move down calculating a weighted average
    7910              :                     // of node temperatures until the node below the group of mixed nodes isn't hotter
    7911              :                     // or we hit the bottom of the tank.
    7912         4675 :                     Real64 Tmixed = 0.0;
    7913         4675 :                     Real64 MassMixed = 0.0;
    7914              :                     int m;
    7915        32778 :                     for (m = j; m < nTankNodes; ++m) {
    7916        32778 :                         Tmixed += Tfinal[m] * this->Node[m].Mass;
    7917        32778 :                         MassMixed += this->Node[m].Mass;
    7918        32778 :                         if ((m == nTankNodes - 1) || (Tmixed / MassMixed > Tfinal[m + 1])) break;
    7919              :                     }
    7920         4675 :                     Tmixed /= MassMixed;
    7921              : 
    7922              :                     // Now we have a range of nodes (j = top, m = bottom) that are mixed
    7923              :                     // and the mixed temperature (Tmixed).
    7924              :                     // Move through the mixed nodes and set the final temperature to the mixed temperature.
    7925              :                     // Also calculate a corrected average temperature for each node.
    7926        37453 :                     for (int k = j; k <= m; ++k) {
    7927              :                         Real64 FinalFactorMixing;
    7928              :                         Real64 AvgFactorMixing;
    7929        32778 :                         const Real64 NodeCapacitance = this->Node[k].Mass * Cp;
    7930        32778 :                         if (A[k] == 0.0) {
    7931            0 :                             FinalFactorMixing = dt / NodeCapacitance;
    7932            0 :                             AvgFactorMixing = FinalFactorMixing / 2.0;
    7933              :                         } else {
    7934        32778 :                             FinalFactorMixing = (exp(A[k] * dt) - 1.0) / A[k] / NodeCapacitance;
    7935        32778 :                             AvgFactorMixing = ((exp(A[k] * dt) - 1.0) / A[k] / dt - 1.0) / A[k] / NodeCapacitance;
    7936              :                         }
    7937        32778 :                         const Real64 Q_AdiabaticMixing = (Tmixed - Tfinal[k]) / FinalFactorMixing;
    7938        32778 :                         Tfinal[k] = Tmixed;
    7939        32778 :                         Tavg[k] += Q_AdiabaticMixing * AvgFactorMixing;
    7940              :                     }
    7941              : 
    7942              :                     // Since we mixed, get out of here and start from the top to check again for mixing.
    7943         4675 :                     break;
    7944              :                 }
    7945              :             }
    7946              :         } while (HasInversion);
    7947              : 
    7948              :         // Venting
    7949         3433 :         if (!this->IsChilledWaterTank) {
    7950         3412 :             if (Tfinal[0] > this->TankTempLimit) {
    7951           13 :                 for (int i = 0; i < nTankNodes; ++i) {
    7952           12 :                     if (Tfinal[i] > this->TankTempLimit) {
    7953            5 :                         Event += this->Node[i].Mass * Cp * (this->TankTempLimit - Tfinal[i]);
    7954            5 :                         Tfinal[i] = this->TankTempLimit;
    7955              :                     }
    7956              :                 }
    7957              :             }
    7958              :         }
    7959              : 
    7960              :         // Increment to next internal time step
    7961         3433 :         TimeRemaining -= dt;
    7962         3433 :         Real64 Qloss = 0.0;
    7963        44495 :         for (int i = 0; i < nTankNodes; ++i) {
    7964        41062 :             auto &node = this->Node[i];
    7965        41062 :             node.Temp = Tfinal[i];
    7966        41062 :             node.TempSum += Tavg[i] * dt;
    7967              : 
    7968              :             // Bookkeeping for reporting variables, mostly for Qunmet.
    7969        41062 :             Real64 Qloss_node = (this->AmbientTemp - Tavg[i]);
    7970              :             Real64 Qheat_node;
    7971        41062 :             const Real64 Quse_node = node.UseMassFlowRate * Cp * (this->UseInletTemp - Tavg[i]);
    7972       123186 :             const Real64 Qsource_node = [&] {
    7973        41062 :                 if (this->HeatPumpNum > 0) {
    7974          216 :                     if (HPWHCondenserConfig == DataPlant::PlantEquipmentType::HeatPumpWtrHeaterPumped) {
    7975            0 :                         if (node.SourceMassFlowRate > 0.0) {
    7976            0 :                             return Qheatpump;
    7977              :                         } else {
    7978            0 :                             return 0.0;
    7979              :                         }
    7980              :                     } else {
    7981          216 :                         assert(HPWHCondenserConfig == DataPlant::PlantEquipmentType::HeatPumpWtrHeaterWrapped);
    7982          216 :                         return Qheatpump * node.HPWHWrappedCondenserHeatingFrac;
    7983              :                     }
    7984              :                 } else {
    7985        40846 :                     return node.SourceMassFlowRate * Cp * (this->SourceInletTemp - Tavg[i]);
    7986              :                 }
    7987        41062 :             }();
    7988              : 
    7989        41062 :             if (this->HeaterOn1 || this->HeaterOn2) {
    7990         9444 :                 Qloss_node *= node.OnCycLossCoeff;
    7991         9444 :                 Qheat_node = node.OnCycParaLoad * this->OnCycParaFracToTank;
    7992              :             } else {
    7993        31618 :                 Qloss_node *= node.OffCycLossCoeff;
    7994        31618 :                 Qheat_node = node.OffCycParaLoad * this->OffCycParaFracToTank;
    7995              :             }
    7996        41062 :             Qloss += Qloss_node;
    7997        41062 :             const Real64 Qneeded_node = max(-Quse_node - Qsource_node - Qloss_node - Qheat_node, 0.0);
    7998        41062 :             const Real64 Qunmet_node = max(Qneeded_node - Qheater1 - Qheater2, 0.0);
    7999        41062 :             Eunmet += Qunmet_node * dt;
    8000              :         }
    8001         3433 :         SourceInletTempSum += this->SourceInletTemp * dt;
    8002              :         // More bookkeeping for reporting variables
    8003         3433 :         Eloss += Qloss * dt;
    8004         3433 :         const Real64 Quse = (this->UseOutletStratNode > 0)
    8005         3433 :                                 ? this->UseEffectiveness * this->UseMassFlowRate * Cp * (this->UseInletTemp - Tavg[this->UseOutletStratNode - 1])
    8006         3433 :                                 : 0.0;
    8007         3433 :         Euse += Quse * dt;
    8008        10299 :         const Real64 Qsource = [&] {
    8009         3433 :             if (this->HeatPumpNum > 0) {
    8010           18 :                 if (HPWHCondenserConfig == DataPlant::PlantEquipmentType::HeatPumpWtrHeaterPumped) {
    8011            0 :                     return Qheatpump;
    8012              :                 } else {
    8013           18 :                     assert(HPWHCondenserConfig == DataPlant::PlantEquipmentType::HeatPumpWtrHeaterWrapped);
    8014           18 :                     return 0.0;
    8015              :                 }
    8016              :             } else {
    8017         3415 :                 if (this->SourceOutletStratNode > 0) {
    8018         3335 :                     return this->SourceEffectiveness * this->SourceMassFlowRate * Cp *
    8019         3335 :                            (this->SourceInletTemp - Tavg[this->SourceOutletStratNode - 1]);
    8020              :                 } else {
    8021           80 :                     return 0.0;
    8022              :                 }
    8023              :             }
    8024         3433 :         }();
    8025         3433 :         Esource += Qsource * dt;
    8026         3433 :         if (this->HeaterOn1) Runtime1 += dt;
    8027         3433 :         if (this->HeaterOn2) Runtime2 += dt;
    8028         3433 :         if (this->HeaterOn1 || this->HeaterOn2) Runtime += dt;
    8029         3433 :         Eheater1 += Qheater1 * dt;
    8030         3433 :         Eheater2 += Qheater2 * dt;
    8031              : 
    8032              :         // Calculation for standard ratings
    8033         3433 :         if (!this->FirstRecoveryDone) {
    8034              :             Real64 Qrecovery;
    8035          163 :             if (this->HeaterOn1 || this->HeaterOn2) {
    8036           86 :                 Qrecovery = (Qheater1 + Qheater1) / this->Efficiency + this->OnCycParaLoad;
    8037              :             } else {
    8038           77 :                 Qrecovery = this->OffCycParaLoad;
    8039              :             }
    8040          163 :             this->FirstRecoveryFuel += Qrecovery * dt;
    8041          163 :             if (SetPointRecovered) this->FirstRecoveryDone = true;
    8042              :         }
    8043              :     } // end while TimeRemaining > 0.0
    8044              : 
    8045        18996 :     for (auto &e : this->Node) {
    8046        17534 :         e.TempAvg = e.TempSum / SecInTimeStep;
    8047        17534 :         e.TempSum = 0.0;
    8048              :     }
    8049              : 
    8050         1462 :     this->TankTemp = sum(this->Node, &StratifiedNodeData::Temp) / this->Nodes;
    8051         1462 :     this->TankTempAvg = sum(this->Node, &StratifiedNodeData::TempAvg) / this->Nodes;
    8052              : 
    8053         1462 :     if (!state.dataGlobal->WarmupFlag) {
    8054              :         // Warn for potential freezing when avg of final temp over all nodes is below 2°C (nearing 0°C)
    8055         1462 :         if (this->TankTemp < 2) {
    8056            1 :             if (this->FreezingErrorIndex == 0) {
    8057            2 :                 ShowWarningError(state,
    8058            2 :                                  format("{}: {} = '{}':  Temperature of tank < 2C indicates of possibility of freeze. Tank Temperature = {:.2R} C.",
    8059              :                                         RoutineName,
    8060            1 :                                         this->Type,
    8061            1 :                                         this->Name,
    8062            1 :                                         this->TankTemp));
    8063            3 :                 ShowContinueErrorTimeStamp(state, "");
    8064              :             }
    8065            8 :             ShowRecurringWarningErrorAtEnd(state,
    8066            2 :                                            this->Type + " = '" + this->Name + "':  Temperature of tank < 2C indicates of possibility of freeze",
    8067            1 :                                            this->FreezingErrorIndex,
    8068            1 :                                            this->TankTemp, // Report Max
    8069            1 :                                            this->TankTemp, // Report Min
    8070              :                                            _,              // Don't report Sum
    8071              :                                            "{C}",          // Max Unit
    8072              :                                            "{C}");         // Min Unit
    8073              :         }
    8074              :     }
    8075              : 
    8076         1462 :     if (this->UseOutletStratNode > 0) {
    8077         1462 :         this->UseOutletTemp = this->Node(this->UseOutletStratNode).TempAvg;
    8078              :         // Revised use outlet temperature to ensure energy balance. Assumes a constant CP. CR8341/CR8570
    8079         1462 :         if (this->UseMassFlowRate > 0.0) {
    8080           10 :             this->UseOutletTemp = this->UseInletTemp * (1.0 - this->UseEffectiveness) + this->UseOutletTemp * this->UseEffectiveness;
    8081              :         }
    8082              :     }
    8083              : 
    8084         1462 :     if (HPWHCondenserConfig == DataPlant::PlantEquipmentType::HeatPumpWtrHeaterWrapped) {
    8085              :         // If we have a wrapped condenser HPWH, set the source outlet to the weighted average of the node
    8086              :         // temperatures the condenser sees
    8087            9 :         Real64 WeightedAverageSourceOutletTemp(0.0);
    8088          117 :         for (int i = 1; i <= this->Nodes; ++i) {
    8089          108 :             WeightedAverageSourceOutletTemp += this->Node(i).TempAvg * this->Node(i).HPWHWrappedCondenserHeatingFrac;
    8090              :         }
    8091            9 :         this->SourceOutletTemp = WeightedAverageSourceOutletTemp;
    8092         1453 :     } else if (this->SourceOutletStratNode > 0) {
    8093              :         // otherwise set it to the temperature of the source outlet node
    8094         1447 :         this->SourceOutletTemp = this->Node(this->SourceOutletStratNode).TempAvg;
    8095              :         // Output the average inlet temperature for the DataGlobals::TimeStep
    8096         1447 :         this->SourceInletTemp = SourceInletTempSum / SecInTimeStep;
    8097              :     }
    8098         1462 :     if (HPWHCondenserConfig == DataPlant::PlantEquipmentType::HeatPumpWtrHeaterPumped) {
    8099              :         // For pumped condensers, set the source inlet and outlets to match the delta T
    8100              :         // across the water side of the DX coil.
    8101            0 :         HeatPumpWaterHeaterData const &HeatPump = state.dataWaterThermalTanks->HPWaterHeater(this->HeatPumpNum);
    8102            0 :         DataLoopNode::NodeData const &HPWHCondWaterInletNode = state.dataLoopNodes->Node(HeatPump.CondWaterInletNode);
    8103            0 :         DataLoopNode::NodeData const &HPWHCondWaterOutletNode = state.dataLoopNodes->Node(HeatPump.CondWaterOutletNode);
    8104            0 :         Real64 const HPWHCondenserDeltaT = HPWHCondWaterOutletNode.Temp - HPWHCondWaterInletNode.Temp;
    8105            0 :         this->SourceInletTemp = this->SourceOutletTemp + HPWHCondenserDeltaT;
    8106              :     }
    8107              : 
    8108              :     // Revised source outlet temperature to ensure energy balance. Assumes a constant CP. CR8341/CR8570
    8109         1462 :     if (this->SourceOutletStratNode > 0) {
    8110         1447 :         if (this->SourceMassFlowRate > 0.0) {
    8111            5 :             this->SourceOutletTemp = this->SourceInletTemp * (1.0 - this->SourceEffectiveness) + this->SourceOutletTemp * this->SourceEffectiveness;
    8112              :         }
    8113              :     }
    8114              : 
    8115         1462 :     this->LossRate = Eloss / SecInTimeStep;
    8116         1462 :     this->UseRate = Euse / SecInTimeStep;
    8117         1462 :     Real64 WrappedCondenserHeatPumpRate = 0.0;
    8118         1462 :     if ((this->HeatPumpNum > 0) && (HPWHCondenserConfig == DataPlant::PlantEquipmentType::HeatPumpWtrHeaterPumped)) {
    8119            0 :         this->SourceRate = Qheatpump;
    8120              :     } else {
    8121         1462 :         this->SourceRate = Esource / SecInTimeStep;
    8122         1462 :         WrappedCondenserHeatPumpRate = Qheatpump;
    8123              :     }
    8124              : 
    8125         1462 :     this->OffCycParaFuelRate = this->OffCycParaLoad * (SecInTimeStep - Runtime) / SecInTimeStep;
    8126         1462 :     this->OnCycParaFuelRate = this->OnCycParaLoad * Runtime / SecInTimeStep;
    8127         1462 :     this->OffCycParaRateToTank = this->OffCycParaFuelRate * this->OffCycParaFracToTank;
    8128         1462 :     this->OnCycParaRateToTank = this->OnCycParaFuelRate * this->OnCycParaFracToTank;
    8129         1462 :     this->TotalDemandRate =
    8130         1462 :         -this->UseRate - this->SourceRate - this->LossRate - this->OffCycParaRateToTank - this->OnCycParaRateToTank - WrappedCondenserHeatPumpRate;
    8131         1462 :     this->HeaterRate1 = Eheater1 / SecInTimeStep;
    8132         1462 :     this->HeaterRate2 = Eheater2 / SecInTimeStep;
    8133         1462 :     this->HeaterRate = this->HeaterRate1 + this->HeaterRate2;
    8134              : 
    8135         1462 :     this->UnmetRate = Eunmet / SecInTimeStep;
    8136         1462 :     this->VentRate = Event / SecInTimeStep;
    8137         1462 :     this->NetHeatTransferRate = this->UseRate + this->SourceRate + this->LossRate + this->OffCycParaRateToTank + this->OnCycParaRateToTank +
    8138         1462 :                                 this->HeaterRate + this->VentRate + WrappedCondenserHeatPumpRate;
    8139              : 
    8140         1462 :     this->CycleOnCount = CycleOnCount1_loc + CycleOnCount2_loc;
    8141         1462 :     this->CycleOnCount1 = CycleOnCount1_loc;
    8142         1462 :     this->CycleOnCount2 = CycleOnCount2_loc;
    8143              : 
    8144         1462 :     this->RuntimeFraction = Runtime / SecInTimeStep;
    8145         1462 :     this->RuntimeFraction1 = Runtime1 / SecInTimeStep;
    8146         1462 :     this->RuntimeFraction2 = Runtime2 / SecInTimeStep;
    8147              : 
    8148         1462 :     this->FuelRate = (Eheater1 + Eheater2) / this->Efficiency / SecInTimeStep;
    8149              : 
    8150              :     // Add water heater skin losses and venting losses to ambient zone, if specified
    8151         1462 :     if (this->AmbientTempZone > 0) this->AmbientZoneGain = -this->LossRate * this->SkinLossFracToZone - this->VentRate;
    8152         1462 : }
    8153              : 
    8154         1482 : void WaterThermalTankData::CalcNodeMassFlows(InletPositionMode inletMode)
    8155              : {
    8156              : 
    8157              :     // SUBROUTINE INFORMATION:
    8158              :     //       AUTHOR         Peter Graham Ellis
    8159              :     //       DATE WRITTEN   January 2007
    8160              :     //       MODIFIED       na
    8161              :     //       RE-ENGINEERED  na
    8162              : 
    8163              :     // PURPOSE OF THIS SUBROUTINE:
    8164              :     // Determines mass flow rates between nodes according to the locations of the use- and source-side inlet and outlet
    8165              :     // nodes.
    8166              : 
    8167              :     // METHODOLOGY EMPLOYED:
    8168              :     // In 'Seeking' mode, nodes are searched between the user-specified inlet and outlet nodes to find the node closest
    8169              :     // in temperature to the inlet fluid temperature.  In 'Fixed' mode, the user-specified nodes are always used.
    8170              :     // Upward and downward flows are added to each node between an inlet and outlet.  Flows in both directions cancel out
    8171              :     // to leave only the net flow in one direction.
    8172              : 
    8173         1482 :     int useInletStratNod = this->UseInletStratNode;
    8174         1482 :     int useOutletStratNode = this->UseOutletStratNode;
    8175         1482 :     int sourceInletStratNode = this->SourceInletStratNode;
    8176         1482 :     int sourceOutletStratNode = this->SourceOutletStratNode;
    8177              : 
    8178         1482 :     Real64 useMassFlowRate = this->UseMassFlowRate * this->UseEffectiveness;
    8179         1482 :     Real64 sourceMassFlowRate = this->SourceMassFlowRate * this->SourceEffectiveness;
    8180              : 
    8181        19136 :     for (auto &e : this->Node) {
    8182        17654 :         e.UseMassFlowRate = 0.0;
    8183        17654 :         e.SourceMassFlowRate = 0.0;
    8184        17654 :         e.MassFlowFromUpper = 0.0;
    8185        17654 :         e.MassFlowFromLower = 0.0;
    8186        17654 :         e.MassFlowToUpper = 0.0;
    8187        17654 :         e.MassFlowToLower = 0.0;
    8188              :     }
    8189              : 
    8190         1482 :     if (inletMode == InletPositionMode::Seeking) {
    8191              :         // 'Seek' the node with the temperature closest to the inlet temperature
    8192              :         // Start at the user-specified inlet node and search to the user-specified outlet node
    8193              :         int Step;
    8194           21 :         if (useMassFlowRate > 0.0) {
    8195           21 :             if (useInletStratNod > useOutletStratNode) {
    8196            0 :                 Step = -1;
    8197              :             } else {
    8198           21 :                 Step = 1;
    8199              :             }
    8200           21 :             Real64 MinDeltaTemp = 1.0e6; // Some big number
    8201           21 :             int const NodeNum_stop(floop_end(useInletStratNod, useOutletStratNode, Step));
    8202           47 :             for (int NodeNum = useInletStratNod; NodeNum != NodeNum_stop; NodeNum += Step) {
    8203           46 :                 Real64 DeltaTemp = std::abs(this->Node(NodeNum).Temp - this->UseInletTemp);
    8204           46 :                 if (DeltaTemp < MinDeltaTemp) {
    8205           21 :                     MinDeltaTemp = DeltaTemp;
    8206           21 :                     useInletStratNod = NodeNum;
    8207           25 :                 } else if (DeltaTemp > MinDeltaTemp) {
    8208           20 :                     break;
    8209              :                 }
    8210              :             }
    8211              :         }
    8212              : 
    8213           21 :         if (sourceMassFlowRate > 0.0) {
    8214           21 :             if (sourceInletStratNode > sourceOutletStratNode) {
    8215           21 :                 Step = -1;
    8216              :             } else {
    8217            0 :                 Step = 1;
    8218              :             }
    8219           21 :             Real64 MinDeltaTemp = 1.0e6; // Some big number
    8220           21 :             int const NodeNum_stop(floop_end(sourceInletStratNode, sourceOutletStratNode, Step));
    8221           47 :             for (int NodeNum = sourceInletStratNode; NodeNum != NodeNum_stop; NodeNum += Step) {
    8222           46 :                 Real64 DeltaTemp = std::abs(this->Node(NodeNum).Temp - this->SourceInletTemp);
    8223           46 :                 if (DeltaTemp < MinDeltaTemp) {
    8224           21 :                     MinDeltaTemp = DeltaTemp;
    8225           21 :                     sourceInletStratNode = NodeNum;
    8226           25 :                 } else if (DeltaTemp > MinDeltaTemp) {
    8227           20 :                     break;
    8228              :                 }
    8229              :             }
    8230              :         }
    8231              :     }
    8232              : 
    8233         1482 :     if (useInletStratNod > 0) this->Node(useInletStratNod).UseMassFlowRate = useMassFlowRate;
    8234         1482 :     if (sourceInletStratNode > 0) this->Node(sourceInletStratNode).SourceMassFlowRate = sourceMassFlowRate;
    8235              : 
    8236         1482 :     if (useMassFlowRate > 0.0) {
    8237           30 :         if (useOutletStratNode > useInletStratNod) {
    8238              :             // Use-side flow is down
    8239          136 :             for (int NodeNum = useInletStratNod; NodeNum <= useOutletStratNode - 1; ++NodeNum) {
    8240          113 :                 this->Node(NodeNum).MassFlowToLower += useMassFlowRate;
    8241              :             }
    8242          136 :             for (int NodeNum = useInletStratNod + 1; NodeNum <= useOutletStratNode; ++NodeNum) {
    8243          113 :                 this->Node(NodeNum).MassFlowFromUpper += useMassFlowRate;
    8244              :             }
    8245              : 
    8246            7 :         } else if (useOutletStratNode < useInletStratNod) {
    8247              :             // Use-side flow is up
    8248           84 :             for (int NodeNum = useOutletStratNode; NodeNum <= useInletStratNod - 1; ++NodeNum) {
    8249           77 :                 this->Node(NodeNum).MassFlowFromLower += useMassFlowRate;
    8250              :             }
    8251           84 :             for (int NodeNum = useOutletStratNode + 1; NodeNum <= useInletStratNod; ++NodeNum) {
    8252           77 :                 this->Node(NodeNum).MassFlowToUpper += useMassFlowRate;
    8253              :             }
    8254              : 
    8255              :         } else {
    8256              :             // Use-side flow is across the node; no flow to other nodes
    8257              :         }
    8258              :     }
    8259              : 
    8260         1482 :     if (sourceMassFlowRate > 0.0) {
    8261           25 :         if (sourceOutletStratNode > sourceInletStratNode) {
    8262              :             // Source-side flow is down
    8263           41 :             for (int NodeNum = sourceInletStratNode; NodeNum <= sourceOutletStratNode - 1; ++NodeNum) {
    8264           37 :                 this->Node(NodeNum).MassFlowToLower += sourceMassFlowRate;
    8265              :             }
    8266           41 :             for (int NodeNum = sourceInletStratNode + 1; NodeNum <= sourceOutletStratNode; ++NodeNum) {
    8267           37 :                 this->Node(NodeNum).MassFlowFromUpper += sourceMassFlowRate;
    8268              :             }
    8269              : 
    8270           21 :         } else if (sourceOutletStratNode < sourceInletStratNode) {
    8271              :             // Source-side flow is up
    8272          126 :             for (int NodeNum = sourceOutletStratNode; NodeNum <= sourceInletStratNode - 1; ++NodeNum) {
    8273          105 :                 this->Node(NodeNum).MassFlowFromLower += sourceMassFlowRate;
    8274              :             }
    8275          126 :             for (int NodeNum = sourceOutletStratNode + 1; NodeNum <= sourceInletStratNode; ++NodeNum) {
    8276          105 :                 this->Node(NodeNum).MassFlowToUpper += sourceMassFlowRate;
    8277              :             }
    8278              : 
    8279              :         } else {
    8280              :             // Source-side flow is across the node; no flow to other nodes
    8281              :         }
    8282              :     }
    8283              : 
    8284              :     // Cancel out any up and down flows
    8285        19136 :     for (int NodeNum = 1; NodeNum <= this->Nodes; ++NodeNum) {
    8286        17654 :         this->Node(NodeNum).MassFlowFromUpper = max((this->Node(NodeNum).MassFlowFromUpper - this->Node(NodeNum).MassFlowToUpper), 0.0);
    8287        17654 :         this->Node(NodeNum).MassFlowFromLower = max((this->Node(NodeNum).MassFlowFromLower - this->Node(NodeNum).MassFlowToLower), 0.0);
    8288              :     }
    8289         1482 : }
    8290              : 
    8291           11 : void WaterThermalTankData::CalcDesuperheaterWaterHeater(EnergyPlusData &state, bool const FirstHVACIteration)
    8292              : {
    8293              : 
    8294              :     // SUBROUTINE INFORMATION:
    8295              :     //       AUTHOR         Richard Raustad
    8296              :     //       DATE WRITTEN   July 2005
    8297              :     //       MODIFIED       na
    8298              :     //       RE-ENGINEERED  na
    8299              : 
    8300              :     // PURPOSE OF THIS SUBROUTINE:
    8301              :     // Simulates a refrigerant desuperheater to heat water
    8302              : 
    8303              :     // METHODOLOGY EMPLOYED:
    8304              :     // This model uses the rated heat reclaim recovery efficiency, recovery efficiency modifier curve,
    8305              :     // set point temperature, and dead band temperature difference to simulate the desuperheater coil
    8306              :     // and sets up inputs to the tank model associated with the desuperheater coil
    8307              : 
    8308           11 :     int constexpr MaxIte(500); // Maximum number of iterations for RegulaFalsi
    8309              : 
    8310           11 :     auto &DesupHtr = state.dataWaterThermalTanks->WaterHeaterDesuperheater(this->DesuperheaterNum);
    8311              : 
    8312           11 :     int WaterInletNode = DesupHtr.WaterInletNode;
    8313           11 :     int WaterOutletNode = DesupHtr.WaterOutletNode;
    8314              : 
    8315              :     // store first iteration tank temperature and desuperheater mode of operation
    8316           11 :     if (FirstHVACIteration && !state.dataHVACGlobal->ShortenTimeStepSys && DesupHtr.FirstTimeThroughFlag) {
    8317              :         // Save conditions from end of previous system timestep
    8318              :         // Every iteration that does not advance time should reset to these values
    8319            6 :         this->SavedTankTemp = this->TankTemp;
    8320            6 :         this->SavedSourceOutletTemp = this->SourceOutletTemp;
    8321            6 :         DesupHtr.SaveMode = DesupHtr.Mode;
    8322            6 :         DesupHtr.FirstTimeThroughFlag = false;
    8323              :     }
    8324              : 
    8325            5 :     else if (!FirstHVACIteration) {
    8326            4 :         DesupHtr.FirstTimeThroughFlag = true;
    8327              :     }
    8328              : 
    8329              :     // initialize variables before invoking any RETURN statement
    8330           11 :     this->SourceMassFlowRate = 0.0;
    8331              :     // reset tank inlet temp from previous time step
    8332           11 :     this->SourceInletTemp = this->SavedSourceOutletTemp;
    8333           11 :     DesupHtr.DesuperheaterPLR = 0.0;
    8334              : 
    8335           11 :     state.dataLoopNodes->Node(WaterInletNode).MassFlowRate = 0.0;
    8336           11 :     state.dataLoopNodes->Node(WaterOutletNode).MassFlowRate = 0.0;
    8337           11 :     state.dataLoopNodes->Node(WaterOutletNode).Temp = this->SavedSourceOutletTemp;
    8338              : 
    8339           11 :     DesupHtr.DesuperheaterPLR = 0.0;
    8340           11 :     DesupHtr.OnCycParaFuelRate = 0.0;
    8341           11 :     DesupHtr.OnCycParaFuelEnergy = 0.0;
    8342           11 :     DesupHtr.OffCycParaFuelRate = 0.0;
    8343           11 :     DesupHtr.OffCycParaFuelEnergy = 0.0;
    8344           11 :     DesupHtr.HEffFTempOutput = 0.0;
    8345           11 :     DesupHtr.HeaterRate = 0.0;
    8346           11 :     DesupHtr.HeaterEnergy = 0.0;
    8347           11 :     DesupHtr.PumpPower = 0.0;
    8348           11 :     DesupHtr.PumpEnergy = 0.0;
    8349              : 
    8350              :     // simulate only the water heater tank if the desuperheater coil is scheduled off
    8351           11 :     Real64 AvailSchedule = DesupHtr.availSched->getCurrentVal();
    8352           11 :     if (AvailSchedule == 0.0) {
    8353            0 :         DesupHtr.Mode = TankOperatingMode::Floating;
    8354            0 :         this->CalcWaterThermalTank(state);
    8355            1 :         return;
    8356              :     }
    8357              : 
    8358              :     // simulate only the water heater tank if the lowest temperature available from the desuperheater coil
    8359              :     // is less than water inlet temperature if the reclaim source is a refrigeration condenser
    8360           11 :     if (DesupHtr.ValidSourceType) {
    8361           11 :         int SourceID = DesupHtr.ReclaimHeatingSourceIndexNum;
    8362           11 :         if (DesupHtr.ReclaimHeatingSource == ReclaimHeatObjectType::CondenserRefrigeration) {
    8363            0 :             if (state.dataHeatBal->HeatReclaimRefrigCondenser(SourceID).AvailTemperature <= this->SourceInletTemp) {
    8364            0 :                 DesupHtr.Mode = TankOperatingMode::Floating;
    8365            0 :                 this->CalcWaterThermalTank(state);
    8366            0 :                 ShowRecurringWarningErrorAtEnd(state,
    8367            0 :                                                "WaterHeating:Desuperheater " + DesupHtr.Name +
    8368              :                                                    " - Waste heat source temperature was too low to be useful.",
    8369            0 :                                                DesupHtr.InsuffTemperatureWarn);
    8370            0 :                 return;
    8371              :             } // Temp too low
    8372              :         }     // desuperheater source is condenser_refrigeration
    8373              :     }         // validsourcetype
    8374              : 
    8375           11 :     DesupHtr.OffCycParaFuelRate = DesupHtr.OffCycParaLoad;
    8376           11 :     DesupHtr.OffCycParaFuelEnergy = DesupHtr.OffCycParaFuelRate * state.dataHVACGlobal->TimeStepSysSec;
    8377              : 
    8378              :     // check that water heater tank cut-in temp is greater than desuperheater cut-in temp
    8379           11 :     Real64 desupHtrSetPointTemp = DesupHtr.SetPointTemp;
    8380           11 :     Real64 DeadBandTempDiff = DesupHtr.DeadBandTempDiff;
    8381           11 :     if ((desupHtrSetPointTemp - DeadBandTempDiff) <= this->SetPointTemp) {
    8382            0 :         if (!state.dataGlobal->WarmupFlag && !state.dataGlobal->DoingSizing && !state.dataGlobal->KickOffSimulation) {
    8383            0 :             Real64 MinTemp = desupHtrSetPointTemp - DeadBandTempDiff;
    8384            0 :             ++DesupHtr.SetPointError;
    8385            0 :             if (DesupHtr.SetPointError < 5) {
    8386            0 :                 ShowWarningError(state,
    8387            0 :                                  format("{} \"{}\":  Water heater tank set point temperature is greater than or equal to the cut-in temperature of "
    8388              :                                         "the desuperheater. Desuperheater will be disabled.",
    8389            0 :                                         DesupHtr.Type,
    8390            0 :                                         DesupHtr.Name));
    8391            0 :                 ShowContinueErrorTimeStamp(state, format(" ...Desuperheater cut-in temperature = {:.2R}", MinTemp));
    8392              :             } else {
    8393            0 :                 ShowRecurringWarningErrorAtEnd(state,
    8394            0 :                                                DesupHtr.Type + " \"" + DesupHtr.Name +
    8395              :                                                    "\":  Water heater tank set point temperature is greater than or equal to the cut-in "
    8396              :                                                    "temperature of the desuperheater. Desuperheater will be disabled warning continues...",
    8397            0 :                                                DesupHtr.SetPointErrIndex1,
    8398              :                                                MinTemp,
    8399              :                                                MinTemp);
    8400              :             }
    8401              :         }
    8402              : 
    8403              :         //   Simulate tank if desuperheater unavailable for water heating
    8404            0 :         this->CalcWaterThermalTank(state);
    8405            0 :         return;
    8406              :     }
    8407              : 
    8408           11 :     Real64 Effic = DesupHtr.HeatReclaimRecoveryEff;
    8409              : 
    8410           11 :     state.dataLoopNodes->Node(WaterInletNode).Temp = this->SavedSourceOutletTemp;
    8411           11 :     DesupHtr.Mode = DesupHtr.SaveMode;
    8412              : 
    8413              :     Real64 HEffFTemp;
    8414           11 :     if (DesupHtr.HEffFTemp > 0) {
    8415            0 :         HEffFTemp = max(0.0, Curve::CurveValue(state, DesupHtr.HEffFTemp, this->SavedTankTemp, state.dataEnvrn->OutDryBulbTemp));
    8416              :     } else {
    8417           11 :         HEffFTemp = 1.0;
    8418              :     }
    8419              : 
    8420              :     // set limits on heat recovery efficiency
    8421           11 :     if (DesupHtr.ReclaimHeatingSource == ReclaimHeatObjectType::CondenserRefrigeration) {
    8422            0 :         if ((HEffFTemp * Effic) > 0.9) HEffFTemp = 0.9 / Effic;
    8423              :     } else { // max is 0.3 for all other sources
    8424           11 :         if ((HEffFTemp * Effic) > 0.3) HEffFTemp = 0.3 / Effic;
    8425              :     } // setting limits on heat recovery efficiency
    8426              : 
    8427              :     // Access the appropriate structure to find the average heating capacity of the desuperheater heating coil
    8428           11 :     Real64 AverageWasteHeat = 0.0;
    8429           11 :     if (DesupHtr.ValidSourceType) {
    8430           11 :         int SourceID = DesupHtr.ReclaimHeatingSourceIndexNum;
    8431           11 :         if (DesupHtr.ReclaimHeatingSource == ReclaimHeatObjectType::CompressorRackRefrigeratedCase) {
    8432              :             // Refrigeration systems are solved outside the time step iteration, so the
    8433              :             //  appropriate decrement for other waste heat applications is handled differently
    8434            0 :             AverageWasteHeat = state.dataHeatBal->HeatReclaimRefrigeratedRack(SourceID).AvailCapacity -
    8435            0 :                                state.dataHeatBal->HeatReclaimRefrigeratedRack(SourceID).HVACDesuperheaterReclaimedHeatTotal;
    8436            0 :             DesupHtr.DXSysPLR = 1.0;
    8437           11 :         } else if (DesupHtr.ReclaimHeatingSource == ReclaimHeatObjectType::CondenserRefrigeration) {
    8438            0 :             AverageWasteHeat = state.dataHeatBal->HeatReclaimRefrigCondenser(SourceID).AvailCapacity -
    8439            0 :                                state.dataHeatBal->HeatReclaimRefrigCondenser(SourceID).HVACDesuperheaterReclaimedHeatTotal;
    8440            0 :             DesupHtr.DXSysPLR = 1.0;
    8441           11 :         } else if (DesupHtr.ReclaimHeatingSource == ReclaimHeatObjectType::DXCooling ||
    8442            6 :                    DesupHtr.ReclaimHeatingSource == ReclaimHeatObjectType::DXMultiSpeed ||
    8443            4 :                    DesupHtr.ReclaimHeatingSource == ReclaimHeatObjectType::DXMultiMode) {
    8444            7 :             AverageWasteHeat = state.dataHeatBal->HeatReclaimDXCoil(SourceID).AvailCapacity -
    8445            7 :                                state.dataHeatBal->HeatReclaimDXCoil(SourceID).HVACDesuperheaterReclaimedHeatTotal;
    8446            7 :             DesupHtr.DXSysPLR = state.dataDXCoils->DXCoil(SourceID).PartLoadRatio;
    8447            4 :         } else if (DesupHtr.ReclaimHeatingSource == ReclaimHeatObjectType::DXVariableCooling ||
    8448            4 :                    DesupHtr.ReclaimHeatingSource == ReclaimHeatObjectType::AirWaterHeatPumpVSEQ) {
    8449            2 :             AverageWasteHeat = state.dataHeatBal->HeatReclaimVS_Coil(SourceID).AvailCapacity -
    8450            2 :                                state.dataHeatBal->HeatReclaimVS_Coil(SourceID).HVACDesuperheaterReclaimedHeatTotal;
    8451            2 :             DesupHtr.DXSysPLR = state.dataVariableSpeedCoils->VarSpeedCoil(SourceID).PartLoadRatio;
    8452            2 :         } else if (DesupHtr.ReclaimHeatingSource == ReclaimHeatObjectType::AirWaterHeatPumpEQ) {
    8453            2 :             AverageWasteHeat = state.dataHeatBal->HeatReclaimSimple_WAHPCoil(SourceID).AvailCapacity -
    8454            2 :                                state.dataHeatBal->HeatReclaimSimple_WAHPCoil(SourceID).HVACDesuperheaterReclaimedHeatTotal;
    8455            2 :             DesupHtr.DXSysPLR = state.dataWaterToAirHeatPumpSimple->SimpleWatertoAirHP(SourceID).PartLoadRatio;
    8456            0 :         } else if (DesupHtr.ReclaimHeatingSource == ReclaimHeatObjectType::CoilCoolingDX) {
    8457            0 :             AverageWasteHeat =
    8458            0 :                 state.dataCoilCoolingDX->coilCoolingDXs[DesupHtr.ReclaimHeatingSourceIndexNum].reclaimHeat.AvailCapacity -
    8459            0 :                 state.dataCoilCoolingDX->coilCoolingDXs[DesupHtr.ReclaimHeatingSourceIndexNum].reclaimHeat.HVACDesuperheaterReclaimedHeatTotal;
    8460            0 :             DesupHtr.DXSysPLR = state.dataCoilCoolingDX->coilCoolingDXs[DesupHtr.ReclaimHeatingSourceIndexNum].partLoadRatioReport;
    8461              :         }
    8462              :     } else {
    8463            0 :         AverageWasteHeat = 0.0;
    8464              :     }
    8465              : 
    8466              :     // simulate only water heater tank if reclaim heating source is off
    8467           11 :     if (DesupHtr.DXSysPLR == 0.0) {
    8468            1 :         this->CalcWaterThermalTank(state);
    8469            1 :         return;
    8470              :     }
    8471              : 
    8472              :     // If the set point is higher than the maximum water temp, reset both the set point and the dead band temperature difference
    8473           10 :     if (desupHtrSetPointTemp > DesupHtr.MaxInletWaterTemp) {
    8474            0 :         Real64 CutInTemp = desupHtrSetPointTemp - DeadBandTempDiff;
    8475            0 :         desupHtrSetPointTemp = DesupHtr.MaxInletWaterTemp;
    8476            0 :         DeadBandTempDiff = max(0.0, (desupHtrSetPointTemp - CutInTemp));
    8477              :     }
    8478              : 
    8479              :     Real64 Acc; // Accuracy of result from RegulaFalsi
    8480           10 :     if (DesupHtr.TankTypeNum == DataPlant::PlantEquipmentType::WtrHeaterStratified) {
    8481            1 :         Acc = 0.001;
    8482              :     } else {
    8483            9 :         Acc = 0.00001;
    8484              :     }
    8485              : 
    8486              :     // set the water-side mass flow rate
    8487           10 :     Real64 CpWater = Psychrometrics::CPHW(state.dataLoopNodes->Node(WaterInletNode).Temp);
    8488           10 :     Real64 MdotWater = DesupHtr.OperatingWaterFlowRate * Psychrometrics::RhoH2O(state.dataLoopNodes->Node(WaterInletNode).Temp);
    8489           10 :     Real64 QHeatRate = 0.0;
    8490           10 :     if (state.dataLoopNodes->Node(WaterInletNode).Temp <= DesupHtr.MaxInletWaterTemp + Acc) {
    8491            8 :         QHeatRate = ((AverageWasteHeat * Effic * HEffFTemp) / DesupHtr.DXSysPLR) + (DesupHtr.PumpElecPower * DesupHtr.PumpFracToWater);
    8492              :     }
    8493              : 
    8494              :     // change to tanktypenum using parameters?
    8495           10 :     Real64 partLoadRatio = 0.0;
    8496              :     Real64 NewTankTemp;
    8497              :     {
    8498           10 :         DataPlant::PlantEquipmentType const TankType = DesupHtr.TankTypeNum;
    8499              : 
    8500           10 :         if (TankType == DataPlant::PlantEquipmentType::WtrHeaterMixed || TankType == DataPlant::PlantEquipmentType::WtrHeaterStratified) {
    8501              : 
    8502           10 :             DesupHtr.SaveWHMode = this->Mode;
    8503           10 :             Real64 PreTankAvgTemp = this->TankTempAvg;
    8504           10 :             Real64 NewTankAvgTemp = 0.0; // Initialization
    8505           10 :             int max_count = 200;
    8506           10 :             int count = 0;
    8507           10 :             bool firstThrough = true;
    8508           10 :             switch (DesupHtr.Mode) {
    8509            8 :             case TankOperatingMode::Heating:
    8510              :                 // Calculate until consistency of desuperheater and tank source side energy transfer achieved
    8511           79 :                 while ((std::abs(PreTankAvgTemp - NewTankAvgTemp) > HVAC::SmallTempDiff || firstThrough) && count < max_count) {
    8512           71 :                     count++;
    8513           71 :                     firstThrough = false;
    8514           71 :                     PreTankAvgTemp = this->TankTempAvg;
    8515           71 :                     partLoadRatio = DesupHtr.DXSysPLR;
    8516           71 :                     if (MdotWater > 0.0) {
    8517           71 :                         state.dataLoopNodes->Node(WaterOutletNode).Temp = this->SourceOutletTemp + QHeatRate / (MdotWater * CpWater);
    8518              :                     } else {
    8519            0 :                         state.dataLoopNodes->Node(WaterOutletNode).Temp = this->SourceOutletTemp;
    8520              :                     }
    8521              : 
    8522              :                     //         set the full load outlet temperature on the water heater source inlet node (init has already been called)
    8523           71 :                     this->SourceInletTemp = state.dataLoopNodes->Node(WaterOutletNode).Temp;
    8524              : 
    8525              :                     //         set the source mass flow rate for the tank
    8526           71 :                     this->SourceMassFlowRate = MdotWater * partLoadRatio;
    8527              : 
    8528           71 :                     this->MaxCapacity = DesupHtr.BackupElementCapacity;
    8529           71 :                     this->MinCapacity = DesupHtr.BackupElementCapacity;
    8530           71 :                     DesupHtr.DesuperheaterPLR = partLoadRatio;
    8531           71 :                     DesupHtr.HeaterRate = QHeatRate * partLoadRatio;
    8532           71 :                     this->CalcWaterThermalTank(state);
    8533           71 :                     Real64 NewTankTemp = this->TankTemp;
    8534              : 
    8535           71 :                     if (NewTankTemp > desupHtrSetPointTemp) {
    8536              :                         //           Only revert to floating mode if the tank temperature is higher than the cut out temperature
    8537           12 :                         if (NewTankTemp > DesupHtr.SetPointTemp) {
    8538           12 :                             DesupHtr.Mode = TankOperatingMode::Floating;
    8539              :                         }
    8540              :                         int SolFla;
    8541           12 :                         std::string IterNum;
    8542          169 :                         auto f = [&state, this, desupHtrSetPointTemp, &DesupHtr, MdotWater](Real64 const HPPartLoadRatio) {
    8543          169 :                             this->Mode = DesupHtr.SaveWHMode;
    8544          169 :                             this->SourceMassFlowRate = MdotWater * HPPartLoadRatio;
    8545          169 :                             this->CalcWaterThermalTank(state);
    8546          169 :                             Real64 NewTankTemp = this->TankTemp;
    8547          169 :                             Real64 PLRResidualWaterThermalTank = desupHtrSetPointTemp - NewTankTemp;
    8548          169 :                             return PLRResidualWaterThermalTank;
    8549           12 :                         };
    8550           12 :                         General::SolveRoot(state, Acc, MaxIte, SolFla, partLoadRatio, f, 0.0, DesupHtr.DXSysPLR);
    8551           12 :                         if (SolFla == -1) {
    8552            0 :                             IterNum = fmt::to_string(MaxIte);
    8553            0 :                             if (!state.dataGlobal->WarmupFlag) {
    8554            0 :                                 ++DesupHtr.IterLimitExceededNum1;
    8555            0 :                                 if (DesupHtr.IterLimitExceededNum1 == 1) {
    8556            0 :                                     ShowWarningError(state, format("{} \"{}\"", DesupHtr.Type, DesupHtr.Name));
    8557            0 :                                     ShowContinueError(state,
    8558            0 :                                                       format("Iteration limit exceeded calculating desuperheater unit part-load ratio, "
    8559              :                                                              "maximum iterations = {}. Part-load ratio returned = {:.3R}",
    8560              :                                                              IterNum,
    8561              :                                                              partLoadRatio));
    8562            0 :                                     ShowContinueErrorTimeStamp(state, "This error occurred in heating mode.");
    8563              :                                 } else {
    8564            0 :                                     ShowRecurringWarningErrorAtEnd(state,
    8565            0 :                                                                    DesupHtr.Type + " \"" + DesupHtr.Name +
    8566              :                                                                        "\":  Iteration limit exceeded in heating mode warning continues. "
    8567              :                                                                        "Part-load ratio statistics follow.",
    8568            0 :                                                                    DesupHtr.IterLimitErrIndex1,
    8569              :                                                                    partLoadRatio,
    8570              :                                                                    partLoadRatio);
    8571              :                                 }
    8572              :                             }
    8573           12 :                         } else if (SolFla == -2) {
    8574            0 :                             partLoadRatio =
    8575            0 :                                 max(0.0, min(DesupHtr.DXSysPLR, (desupHtrSetPointTemp - this->SavedTankTemp) / (NewTankTemp - this->SavedTankTemp)));
    8576            0 :                             this->SourceMassFlowRate = MdotWater * partLoadRatio;
    8577            0 :                             this->CalcWaterThermalTank(state);
    8578            0 :                             if (!state.dataGlobal->WarmupFlag) {
    8579            0 :                                 ++DesupHtr.RegulaFalsiFailedNum1;
    8580            0 :                                 if (DesupHtr.RegulaFalsiFailedNum1 == 1) {
    8581            0 :                                     ShowWarningError(state, format("{} \"{}\"", DesupHtr.Type, DesupHtr.Name));
    8582            0 :                                     ShowContinueError(state,
    8583            0 :                                                       format("Desuperheater unit part-load ratio calculation failed: PLR limits of 0 to 1 "
    8584              :                                                              "exceeded. Part-load ratio used = {:.3R}",
    8585              :                                                              partLoadRatio));
    8586            0 :                                     ShowContinueError(state, "Please send this information to the EnergyPlus support group.");
    8587            0 :                                     ShowContinueErrorTimeStamp(state, "This error occurred in heating mode.");
    8588              :                                 } else {
    8589            0 :                                     ShowRecurringWarningErrorAtEnd(state,
    8590            0 :                                                                    DesupHtr.Type + " \"" + DesupHtr.Name +
    8591              :                                                                        "\":  Part-load ratio calculation failed in heating mode warning "
    8592              :                                                                        "continues. Part-load ratio statistics follow.",
    8593            0 :                                                                    DesupHtr.RegulaFalsiFailedIndex1,
    8594              :                                                                    partLoadRatio,
    8595              :                                                                    partLoadRatio);
    8596              :                                 }
    8597              :                             }
    8598              :                         }
    8599           12 :                     } else {
    8600           59 :                         partLoadRatio = DesupHtr.DXSysPLR;
    8601              :                     }
    8602           71 :                     NewTankAvgTemp = this->TankTempAvg;
    8603              :                 }
    8604            8 :                 break;
    8605            2 :             case TankOperatingMode::Floating:
    8606            2 :                 if (MdotWater > 0.0) {
    8607            2 :                     state.dataLoopNodes->Node(WaterOutletNode).Temp =
    8608            2 :                         state.dataLoopNodes->Node(WaterInletNode).Temp + QHeatRate / (MdotWater * CpWater);
    8609              :                 } else {
    8610            0 :                     state.dataLoopNodes->Node(WaterOutletNode).Temp = state.dataLoopNodes->Node(WaterInletNode).Temp;
    8611              :                 }
    8612              :                 //         check tank temperature by setting source inlet mass flow rate to zero
    8613            2 :                 partLoadRatio = 0.0;
    8614              : 
    8615              :                 //         set the full load outlet temperature on the water heater source inlet node (init has already been called)
    8616            2 :                 this->SourceInletTemp = state.dataLoopNodes->Node(WaterOutletNode).Temp;
    8617              : 
    8618              :                 //         check tank temperature by setting source inlet mass flow rate to zero
    8619            2 :                 this->SourceMassFlowRate = 0.0;
    8620              : 
    8621              :                 //         disable the tank heater to find PLR of the HPWH
    8622            2 :                 this->MaxCapacity = 0.0;
    8623            2 :                 this->MinCapacity = 0.0;
    8624            2 :                 DesupHtr.DesuperheaterPLR = partLoadRatio;
    8625            2 :                 DesupHtr.HeaterRate = QHeatRate * partLoadRatio;
    8626            2 :                 this->CalcWaterThermalTank(state);
    8627            2 :                 NewTankTemp = this->TankTemp;
    8628              : 
    8629            2 :                 if (NewTankTemp <= (desupHtrSetPointTemp - DeadBandTempDiff)) {
    8630            0 :                     this->Mode = DesupHtr.SaveWHMode;
    8631            0 :                     if ((this->SavedTankTemp - NewTankTemp) != 0.0) {
    8632            0 :                         partLoadRatio =
    8633            0 :                             min(DesupHtr.DXSysPLR,
    8634            0 :                                 max(0.0, ((desupHtrSetPointTemp - DeadBandTempDiff) - NewTankTemp) / (this->SavedTankTemp - NewTankTemp)));
    8635              :                     } else {
    8636            0 :                         partLoadRatio = DesupHtr.DXSysPLR;
    8637              :                     }
    8638            0 :                     while ((std::abs(PreTankAvgTemp - NewTankAvgTemp) > HVAC::SmallTempDiff || firstThrough) && count < max_count) {
    8639            0 :                         count++;
    8640            0 :                         firstThrough = false;
    8641            0 :                         PreTankAvgTemp = this->TankTempAvg;
    8642            0 :                         DesupHtr.Mode = TankOperatingMode::Heating;
    8643            0 :                         if (MdotWater > 0.0) {
    8644            0 :                             state.dataLoopNodes->Node(WaterOutletNode).Temp = this->SourceOutletTemp + QHeatRate / (MdotWater * CpWater);
    8645              :                         } else {
    8646            0 :                             state.dataLoopNodes->Node(WaterOutletNode).Temp = this->SourceOutletTemp;
    8647              :                         }
    8648              : 
    8649              :                         //           set the full load outlet temperature on the water heater source inlet node
    8650            0 :                         this->SourceInletTemp = state.dataLoopNodes->Node(WaterOutletNode).Temp;
    8651              : 
    8652              :                         //           set the source mass flow rate for the tank and enable backup heating element
    8653            0 :                         this->SourceMassFlowRate = MdotWater * partLoadRatio;
    8654            0 :                         this->MaxCapacity = DesupHtr.BackupElementCapacity;
    8655            0 :                         this->MinCapacity = DesupHtr.BackupElementCapacity;
    8656            0 :                         DesupHtr.DesuperheaterPLR = partLoadRatio;
    8657            0 :                         DesupHtr.HeaterRate = QHeatRate * partLoadRatio;
    8658            0 :                         this->CalcWaterThermalTank(state);
    8659            0 :                         NewTankTemp = this->TankTemp;
    8660              : 
    8661            0 :                         if (NewTankTemp > desupHtrSetPointTemp) {
    8662              :                             //           Only revert to floating mode if the tank temperature is higher than the cut-out temperature
    8663            0 :                             if (NewTankTemp > DesupHtr.SetPointTemp) {
    8664            0 :                                 DesupHtr.Mode = TankOperatingMode::Floating;
    8665              :                             }
    8666              :                             int SolFla;
    8667            0 :                             std::string IterNum;
    8668            0 :                             auto f = [&state, this, desupHtrSetPointTemp, &DesupHtr, MdotWater](Real64 const HPPartLoadRatio) {
    8669            0 :                                 this->Mode = DesupHtr.SaveWHMode;
    8670            0 :                                 this->SourceMassFlowRate = MdotWater * HPPartLoadRatio;
    8671            0 :                                 this->CalcWaterThermalTank(state);
    8672            0 :                                 Real64 NewTankTemp = this->TankTemp;
    8673            0 :                                 Real64 PLRResidualWaterThermalTank = desupHtrSetPointTemp - NewTankTemp;
    8674            0 :                                 return PLRResidualWaterThermalTank;
    8675            0 :                             };
    8676            0 :                             General::SolveRoot(state, Acc, MaxIte, SolFla, partLoadRatio, f, 0.0, DesupHtr.DXSysPLR);
    8677            0 :                             if (SolFla == -1) {
    8678            0 :                                 IterNum = fmt::to_string(MaxIte);
    8679            0 :                                 if (!state.dataGlobal->WarmupFlag) {
    8680            0 :                                     ++DesupHtr.IterLimitExceededNum2;
    8681            0 :                                     if (DesupHtr.IterLimitExceededNum2 == 1) {
    8682            0 :                                         ShowWarningError(state, format("{} \"{}\"", DesupHtr.Type, DesupHtr.Name));
    8683            0 :                                         ShowContinueError(state,
    8684            0 :                                                           format("Iteration limit exceeded calculating desuperheater unit part-load ratio, "
    8685              :                                                                  "maximum iterations = {}. Part-load ratio returned = {:.3R}",
    8686              :                                                                  IterNum,
    8687              :                                                                  partLoadRatio));
    8688            0 :                                         ShowContinueErrorTimeStamp(state, "This error occurred in float mode.");
    8689              :                                     } else {
    8690            0 :                                         ShowRecurringWarningErrorAtEnd(state,
    8691            0 :                                                                        DesupHtr.Type + " \"" + DesupHtr.Name +
    8692              :                                                                            "\":  Iteration limit exceeded in float mode warning continues. "
    8693              :                                                                            "Part-load ratio statistics follow.",
    8694            0 :                                                                        DesupHtr.IterLimitErrIndex2,
    8695              :                                                                        partLoadRatio,
    8696              :                                                                        partLoadRatio);
    8697              :                                     }
    8698              :                                 }
    8699            0 :                             } else if (SolFla == -2) {
    8700            0 :                                 partLoadRatio = max(
    8701            0 :                                     0.0, min(DesupHtr.DXSysPLR, (desupHtrSetPointTemp - this->SavedTankTemp) / (NewTankTemp - this->SavedTankTemp)));
    8702            0 :                                 if (!state.dataGlobal->WarmupFlag) {
    8703            0 :                                     ++DesupHtr.RegulaFalsiFailedNum2;
    8704            0 :                                     if (DesupHtr.RegulaFalsiFailedNum2 == 1) {
    8705            0 :                                         ShowWarningError(state, format("{} \"{}\"", DesupHtr.Type, DesupHtr.Name));
    8706            0 :                                         ShowContinueError(state,
    8707            0 :                                                           format("Desuperheater unit part-load ratio calculation failed: PLR limits of 0 to "
    8708              :                                                                  "1 exceeded. Part-load ratio used = {:.3R}",
    8709              :                                                                  partLoadRatio));
    8710            0 :                                         ShowContinueError(state, "Please send this information to the EnergyPlus support group.");
    8711            0 :                                         ShowContinueErrorTimeStamp(state, "This error occurred in float mode.");
    8712              :                                     } else {
    8713            0 :                                         ShowRecurringWarningErrorAtEnd(
    8714              :                                             state,
    8715            0 :                                             DesupHtr.Type + " \"" + DesupHtr.Name +
    8716              :                                                 "\": Part-load ratio calculation failed in float mode warning "
    8717              :                                                 "continues. Part-load ratio statistics follow.",
    8718            0 :                                             state.dataWaterThermalTanks->WaterHeaterDesuperheater(DesuperheaterNum).RegulaFalsiFailedIndex2,
    8719              :                                             partLoadRatio,
    8720              :                                             partLoadRatio);
    8721              :                                     }
    8722              :                                 }
    8723              :                             }
    8724            0 :                         }
    8725            0 :                         NewTankAvgTemp = this->TankTempAvg;
    8726              :                     }
    8727              :                 } else {
    8728            2 :                     this->MaxCapacity = DesupHtr.BackupElementCapacity;
    8729            2 :                     this->MinCapacity = DesupHtr.BackupElementCapacity;
    8730              :                 }
    8731            2 :                 break;
    8732            0 :             default:
    8733            0 :                 break;
    8734              :             }
    8735              : 
    8736              :             //   should never get here, case is checked in GetWaterThermalTankInput
    8737           10 :         } else {
    8738            0 :             ShowFatalError(state,
    8739            0 :                            format("Coil:WaterHeating:Desuperheater = {}:  invalid water heater tank type and name entered = {}, {}",
    8740            0 :                                   state.dataWaterThermalTanks->WaterHeaterDesuperheater(DesuperheaterNum).Name,
    8741            0 :                                   state.dataWaterThermalTanks->WaterHeaterDesuperheater(DesuperheaterNum).TankType,
    8742            0 :                                   state.dataWaterThermalTanks->WaterHeaterDesuperheater(DesuperheaterNum).TankName));
    8743              :         }
    8744              :     }
    8745              : 
    8746           10 :     if (QHeatRate == 0) partLoadRatio = 0.0;
    8747              : 
    8748           10 :     state.dataLoopNodes->Node(WaterOutletNode).MassFlowRate = MdotWater * partLoadRatio;
    8749           10 :     DesupHtr.HEffFTempOutput = HEffFTemp;
    8750           10 :     DesupHtr.HeaterRate = QHeatRate * partLoadRatio;
    8751           10 :     this->SourceMassFlowRate = MdotWater * partLoadRatio;
    8752              : 
    8753           10 :     if (partLoadRatio == 0) {
    8754            3 :         this->SourceInletTemp = this->SourceOutletTemp;
    8755            3 :         state.dataLoopNodes->Node(WaterOutletNode).Temp = this->SourceOutletTemp;
    8756            3 :         DesupHtr.HEffFTempOutput = 0.0;
    8757            3 :         DesupHtr.HeaterRate = 0.0;
    8758              :     }
    8759              : 
    8760           10 :     DesupHtr.HeaterEnergy = DesupHtr.HeaterRate * state.dataHVACGlobal->TimeStepSysSec;
    8761           10 :     DesupHtr.DesuperheaterPLR = partLoadRatio;
    8762           10 :     DesupHtr.OnCycParaFuelRate = DesupHtr.OnCycParaLoad * partLoadRatio;
    8763           10 :     DesupHtr.OnCycParaFuelEnergy = DesupHtr.OnCycParaFuelRate * state.dataHVACGlobal->TimeStepSysSec;
    8764           10 :     DesupHtr.OffCycParaFuelRate = DesupHtr.OffCycParaLoad * (1 - partLoadRatio);
    8765           10 :     DesupHtr.OffCycParaFuelEnergy = DesupHtr.OffCycParaFuelRate * state.dataHVACGlobal->TimeStepSysSec;
    8766           10 :     DesupHtr.PumpPower = DesupHtr.PumpElecPower * (partLoadRatio);
    8767           10 :     DesupHtr.PumpEnergy = DesupHtr.PumpPower * state.dataHVACGlobal->TimeStepSysSec;
    8768              : 
    8769              :     // Update used waste heat (just in case multiple users of waste heat use same source)
    8770           10 :     if (DesupHtr.ValidSourceType) {
    8771           10 :         int SourceID = DesupHtr.ReclaimHeatingSourceIndexNum;
    8772           10 :         if (DesupHtr.ReclaimHeatingSource == ReclaimHeatObjectType::CompressorRackRefrigeratedCase) {
    8773            0 :             state.dataHeatBal->HeatReclaimRefrigeratedRack(SourceID).WaterHeatingDesuperheaterReclaimedHeat(DesuperheaterNum) = DesupHtr.HeaterRate;
    8774            0 :             state.dataHeatBal->HeatReclaimRefrigeratedRack(SourceID).WaterHeatingDesuperheaterReclaimedHeatTotal = 0.0;
    8775            0 :             for (auto const &num : state.dataHeatBal->HeatReclaimRefrigeratedRack(SourceID).WaterHeatingDesuperheaterReclaimedHeat)
    8776            0 :                 state.dataHeatBal->HeatReclaimRefrigeratedRack(SourceID).WaterHeatingDesuperheaterReclaimedHeatTotal += num;
    8777           10 :         } else if (DesupHtr.ReclaimHeatingSource == ReclaimHeatObjectType::CondenserRefrigeration) {
    8778            0 :             state.dataHeatBal->HeatReclaimRefrigCondenser(SourceID).WaterHeatingDesuperheaterReclaimedHeat(DesuperheaterNum) = DesupHtr.HeaterRate;
    8779            0 :             state.dataHeatBal->HeatReclaimRefrigCondenser(SourceID).WaterHeatingDesuperheaterReclaimedHeatTotal = 0.0;
    8780            0 :             for (auto const &num : state.dataHeatBal->HeatReclaimRefrigCondenser(SourceID).WaterHeatingDesuperheaterReclaimedHeat)
    8781            0 :                 state.dataHeatBal->HeatReclaimRefrigCondenser(SourceID).WaterHeatingDesuperheaterReclaimedHeatTotal += num;
    8782           10 :         } else if (DesupHtr.ReclaimHeatingSource == ReclaimHeatObjectType::DXCooling ||
    8783            5 :                    DesupHtr.ReclaimHeatingSource == ReclaimHeatObjectType::DXMultiSpeed ||
    8784            3 :                    DesupHtr.ReclaimHeatingSource == ReclaimHeatObjectType::DXMultiMode) {
    8785            7 :             state.dataHeatBal->HeatReclaimDXCoil(SourceID).WaterHeatingDesuperheaterReclaimedHeat(DesuperheaterNum) = DesupHtr.HeaterRate;
    8786            7 :             state.dataHeatBal->HeatReclaimDXCoil(SourceID).WaterHeatingDesuperheaterReclaimedHeatTotal = 0.0;
    8787           16 :             for (auto const &num : state.dataHeatBal->HeatReclaimDXCoil(SourceID).WaterHeatingDesuperheaterReclaimedHeat)
    8788            9 :                 state.dataHeatBal->HeatReclaimDXCoil(SourceID).WaterHeatingDesuperheaterReclaimedHeatTotal += num;
    8789           10 :         } else if (DesupHtr.ReclaimHeatingSource == ReclaimHeatObjectType::DXVariableCooling ||
    8790            3 :                    DesupHtr.ReclaimHeatingSource == ReclaimHeatObjectType::AirWaterHeatPumpVSEQ) {
    8791            2 :             state.dataHeatBal->HeatReclaimVS_Coil(SourceID).WaterHeatingDesuperheaterReclaimedHeat(DesuperheaterNum) = DesupHtr.HeaterRate;
    8792            2 :             state.dataHeatBal->HeatReclaimVS_Coil(SourceID).WaterHeatingDesuperheaterReclaimedHeatTotal = 0.0;
    8793            4 :             for (auto const &num : state.dataHeatBal->HeatReclaimVS_Coil(SourceID).WaterHeatingDesuperheaterReclaimedHeat)
    8794            2 :                 state.dataHeatBal->HeatReclaimVS_Coil(SourceID).WaterHeatingDesuperheaterReclaimedHeatTotal += num;
    8795            3 :         } else if (DesupHtr.ReclaimHeatingSource == ReclaimHeatObjectType::AirWaterHeatPumpEQ) {
    8796            1 :             state.dataHeatBal->HeatReclaimSimple_WAHPCoil(SourceID).WaterHeatingDesuperheaterReclaimedHeat(DesuperheaterNum) = DesupHtr.HeaterRate;
    8797            1 :             state.dataHeatBal->HeatReclaimSimple_WAHPCoil(SourceID).WaterHeatingDesuperheaterReclaimedHeatTotal = 0.0;
    8798            2 :             for (auto const &num : state.dataHeatBal->HeatReclaimSimple_WAHPCoil(SourceID).WaterHeatingDesuperheaterReclaimedHeat)
    8799            1 :                 state.dataHeatBal->HeatReclaimSimple_WAHPCoil(SourceID).WaterHeatingDesuperheaterReclaimedHeatTotal += num;
    8800            0 :         } else if (DesupHtr.ReclaimHeatingSource == ReclaimHeatObjectType::CoilCoolingDX) {
    8801            0 :             state.dataCoilCoolingDX->coilCoolingDXs[DesupHtr.ReclaimHeatingSourceIndexNum].reclaimHeat.WaterHeatingDesuperheaterReclaimedHeat(
    8802            0 :                 DesuperheaterNum) = DesupHtr.HeaterRate;
    8803            0 :             state.dataCoilCoolingDX->coilCoolingDXs[DesupHtr.ReclaimHeatingSourceIndexNum].reclaimHeat.WaterHeatingDesuperheaterReclaimedHeatTotal =
    8804              :                 0.0;
    8805            0 :             for (auto const &num :
    8806            0 :                  state.dataCoilCoolingDX->coilCoolingDXs[DesupHtr.ReclaimHeatingSourceIndexNum].reclaimHeat.WaterHeatingDesuperheaterReclaimedHeat)
    8807            0 :                 state.dataCoilCoolingDX->coilCoolingDXs[DesupHtr.ReclaimHeatingSourceIndexNum]
    8808            0 :                     .reclaimHeat.WaterHeatingDesuperheaterReclaimedHeatTotal += num;
    8809              :         }
    8810              :     }
    8811              : }
    8812              : 
    8813            8 : void WaterThermalTankData::CalcHeatPumpWaterHeater(EnergyPlusData &state, bool const FirstHVACIteration)
    8814              : {
    8815              : 
    8816              :     // SUBROUTINE INFORMATION:
    8817              :     //       AUTHOR         Richard Raustad
    8818              :     //       DATE WRITTEN   March 2005
    8819              :     //       MODIFIED       B. Griffith, Jan 2012 for stratified tank
    8820              :     //                        B. Shen 12/2014, add air-source variable-speed heat pump water heating
    8821              :     //       RE-ENGINEERED  na
    8822              : 
    8823              :     // PURPOSE OF THIS SUBROUTINE:
    8824              :     // Simulates a heat pump water heater
    8825              : 
    8826              :     // METHODOLOGY EMPLOYED:
    8827              :     // Simulate the water heater tank, DX coil, and fan to meet the water heating requirements.
    8828              : 
    8829            8 :     int constexpr MaxIte(500);   // maximum number of iterations
    8830            8 :     Real64 constexpr Acc(0.001); // Accuracy of result from RegulaFalsi
    8831              : 
    8832              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    8833              :     Real64 MdotWater;                                                                         // mass flow rate of condenser water, kg/s
    8834            8 :     IntegratedHeatPump::IHPOperationMode IHPMode(IntegratedHeatPump::IHPOperationMode::Idle); // IHP working mode
    8835              : 
    8836              :     // References to objects used in this function
    8837            8 :     HeatPumpWaterHeaterData &HeatPump = state.dataWaterThermalTanks->HPWaterHeater(this->HeatPumpNum);
    8838              : 
    8839              :     // initialize local variables
    8840            8 :     int AvailSchedule = HeatPump.availSched->getCurrentVal();
    8841            8 :     int HPAirInletNode = HeatPump.HeatPumpAirInletNode;
    8842            8 :     int HPAirOutletNode = HeatPump.HeatPumpAirOutletNode;
    8843            8 :     int OutdoorAirNode = HeatPump.OutsideAirNode;
    8844            8 :     int ExhaustAirNode = HeatPump.ExhaustAirNode;
    8845            8 :     int HPWaterInletNode = HeatPump.CondWaterInletNode;
    8846            8 :     int HPWaterOutletNode = HeatPump.CondWaterOutletNode;
    8847            8 :     int InletAirMixerNode = HeatPump.InletAirMixerNode;
    8848            8 :     int OutletAirSplitterNode = HeatPump.OutletAirSplitterNode;
    8849            8 :     int DXCoilAirInletNode = HeatPump.DXCoilAirInletNode;
    8850            8 :     state.dataWaterThermalTanks->hpPartLoadRatio = 0.0;
    8851            8 :     HVAC::CompressorOp compressorOp = HVAC::CompressorOp::Off; // DX compressor operation; 1=on, 0=off
    8852            8 :     HeatPump.OnCycParaFuelRate = 0.0;
    8853            8 :     HeatPump.OnCycParaFuelEnergy = 0.0;
    8854            8 :     HeatPump.OffCycParaFuelRate = 0.0;
    8855            8 :     HeatPump.OffCycParaFuelEnergy = 0.0;
    8856            8 :     state.dataLoopNodes->Node(HPWaterOutletNode) = state.dataLoopNodes->Node(HPWaterInletNode);
    8857            8 :     int MaxSpeedNum = HeatPump.NumofSpeed; // speed number of variable speed HPWH coil
    8858              : 
    8859              :     // assign set point temperature (cut-out) and dead band temp diff (cut-in = cut-out minus dead band temp diff)
    8860            8 :     Real64 HPSetPointTemp = HeatPump.SetPointTemp;
    8861            8 :     Real64 DeadBandTempDiff = HeatPump.DeadBandTempDiff;
    8862            8 :     Real64 RhoWater = Psychrometrics::RhoH2O(HPSetPointTemp); // initialize
    8863              : 
    8864              :     // store first iteration tank temperature and HP mode of operation
    8865              :     // this code can be called more than once with FirstHVACIteration = .TRUE., use FirstTimeThroughFlag to control save
    8866            8 :     if (FirstHVACIteration && !state.dataHVACGlobal->ShortenTimeStepSys && HeatPump.FirstTimeThroughFlag) {
    8867            2 :         this->SavedTankTemp = this->TankTemp;
    8868            2 :         HeatPump.SaveMode = HeatPump.Mode;
    8869            2 :         HeatPump.SaveWHMode = this->Mode;
    8870            2 :         HeatPump.FirstTimeThroughFlag = false;
    8871              :     }
    8872              : 
    8873            8 :     if (!FirstHVACIteration) HeatPump.FirstTimeThroughFlag = true;
    8874              : 
    8875              :     // check if HPWH is off for some reason and simulate HPWH air- and water-side mass flow rates of 0
    8876              :     // simulate only water heater tank if HP compressor is scheduled off
    8877              :     //   simulate only water heater tank if HP compressor cut-out temperature is lower than the tank's cut-in temperature
    8878              :     //    simulate only water heater tank if HP inlet air temperature is below minimum temperature for HP compressor operation
    8879              :     //    if the tank maximum temperature limit is less than the HPWH set point temp, disable HPWH
    8880            8 :     if (AvailSchedule == 0.0 || (HPSetPointTemp - DeadBandTempDiff) <= this->SetPointTemp ||
    8881            6 :         state.dataHVACGlobal->HPWHInletDBTemp < HeatPump.MinAirTempForHPOperation ||
    8882            6 :         state.dataHVACGlobal->HPWHInletDBTemp > HeatPump.MaxAirTempForHPOperation || HPSetPointTemp >= this->TankTempLimit ||
    8883            6 :         (!HeatPump.AllowHeatingElementAndHeatPumpToRunAtSameTime && this->WaterThermalTankType == DataPlant::PlantEquipmentType::WtrHeaterMixed &&
    8884           16 :          this->SavedMode == TankOperatingMode::Heating) ||
    8885            6 :         (!HeatPump.AllowHeatingElementAndHeatPumpToRunAtSameTime &&
    8886            1 :          this->WaterThermalTankType == DataPlant::PlantEquipmentType::WtrHeaterStratified && (this->SavedHeaterOn1 || this->SavedHeaterOn2))) {
    8887              :         //   revert to float mode any time HPWH compressor is OFF
    8888            2 :         HeatPump.Mode = TankOperatingMode::Floating;
    8889            2 :         if (InletAirMixerNode > 0) {
    8890            0 :             state.dataLoopNodes->Node(InletAirMixerNode) = state.dataLoopNodes->Node(HPAirInletNode);
    8891              :         }
    8892              :         //   pass node info and simulate crankcase heater
    8893            2 :         if (MaxSpeedNum > 0) {
    8894            0 :             int VSCoilNum = HeatPump.DXCoilNum;
    8895              : 
    8896            0 :             if (HeatPump.bIsIHP) {
    8897            0 :                 VSCoilNum = state.dataIntegratedHP->IntegratedHeatPumps(VSCoilNum).SCWHCoilIndex;
    8898              :             }
    8899              :             // set the SCWH mode
    8900            0 :             Real64 SpeedRatio = 1.0; // speed ratio for interpolating between two speed levels
    8901            0 :             int SpeedNum = 1;
    8902            0 :             if (HeatPump.fanPlace == HVAC::FanPlace::BlowThru) {
    8903            0 :                 state.dataFans->fans(HeatPump.FanNum)->simulate(state, FirstHVACIteration, _, _);
    8904              : 
    8905            0 :                 this->SetVSHPWHFlowRates(state, HeatPump, SpeedNum, SpeedRatio, RhoWater, MdotWater, FirstHVACIteration);
    8906            0 :                 if (HeatPump.bIsIHP)
    8907            0 :                     VariableSpeedCoils::SimVariableSpeedCoils(state,
    8908              :                                                               "",
    8909              :                                                               VSCoilNum,
    8910              :                                                               HVAC::FanOp::Cycling,
    8911              :                                                               HVAC::CompressorOp::On,
    8912            0 :                                                               state.dataWaterThermalTanks->hpPartLoadRatio,
    8913              :                                                               SpeedNum,
    8914              :                                                               SpeedRatio,
    8915              :                                                               0.0,
    8916              :                                                               0.0,
    8917              :                                                               1.0);
    8918              :                 else
    8919            0 :                     VariableSpeedCoils::SimVariableSpeedCoils(state,
    8920              :                                                               HeatPump.DXCoilName,
    8921              :                                                               VSCoilNum,
    8922              :                                                               HVAC::FanOp::Cycling,
    8923              :                                                               HVAC::CompressorOp::On,
    8924            0 :                                                               state.dataWaterThermalTanks->hpPartLoadRatio,
    8925              :                                                               SpeedNum,
    8926              :                                                               SpeedRatio,
    8927              :                                                               0.0,
    8928              :                                                               0.0,
    8929              :                                                               1.0);
    8930              :             } else {
    8931            0 :                 this->SetVSHPWHFlowRates(state, HeatPump, SpeedNum, SpeedRatio, RhoWater, MdotWater, FirstHVACIteration);
    8932            0 :                 if (HeatPump.bIsIHP)
    8933            0 :                     VariableSpeedCoils::SimVariableSpeedCoils(state,
    8934              :                                                               "",
    8935              :                                                               VSCoilNum,
    8936              :                                                               HVAC::FanOp::Cycling,
    8937              :                                                               HVAC::CompressorOp::On,
    8938            0 :                                                               state.dataWaterThermalTanks->hpPartLoadRatio,
    8939              :                                                               SpeedNum,
    8940              :                                                               SpeedRatio,
    8941              :                                                               0.0,
    8942              :                                                               0.0,
    8943              :                                                               1.0);
    8944              :                 else
    8945            0 :                     VariableSpeedCoils::SimVariableSpeedCoils(state,
    8946              :                                                               HeatPump.DXCoilName,
    8947              :                                                               VSCoilNum,
    8948              :                                                               HVAC::FanOp::Cycling,
    8949              :                                                               HVAC::CompressorOp::On,
    8950            0 :                                                               state.dataWaterThermalTanks->hpPartLoadRatio,
    8951              :                                                               SpeedNum,
    8952              :                                                               SpeedRatio,
    8953              :                                                               0.0,
    8954              :                                                               0.0,
    8955              :                                                               1.0);
    8956            0 :                 state.dataFans->fans(HeatPump.FanNum)->simulate(state, FirstHVACIteration, _, _);
    8957              :             }
    8958              : 
    8959              :             // set the DWH mode
    8960            0 :             if (HeatPump.bIsIHP) {
    8961            0 :                 VSCoilNum = state.dataIntegratedHP->IntegratedHeatPumps(HeatPump.DXCoilNum).DWHCoilIndex;
    8962              : 
    8963            0 :                 if (VSCoilNum > 0) // if DWH coil exists
    8964              :                 {
    8965            0 :                     if (HeatPump.fanPlace == HVAC::FanPlace::BlowThru) {
    8966            0 :                         state.dataFans->fans(HeatPump.FanNum)->simulate(state, FirstHVACIteration, _, _);
    8967              : 
    8968            0 :                         this->SetVSHPWHFlowRates(state, HeatPump, SpeedNum, SpeedRatio, RhoWater, MdotWater, FirstHVACIteration);
    8969            0 :                         VariableSpeedCoils::SimVariableSpeedCoils(state,
    8970              :                                                                   "",
    8971              :                                                                   VSCoilNum,
    8972              :                                                                   HVAC::FanOp::Cycling,
    8973              :                                                                   HVAC::CompressorOp::On,
    8974            0 :                                                                   state.dataWaterThermalTanks->hpPartLoadRatio,
    8975              :                                                                   SpeedNum,
    8976              :                                                                   SpeedRatio,
    8977              :                                                                   0.0,
    8978              :                                                                   0.0,
    8979              :                                                                   1.0);
    8980              :                     } else {
    8981            0 :                         this->SetVSHPWHFlowRates(state, HeatPump, SpeedNum, SpeedRatio, RhoWater, MdotWater, FirstHVACIteration);
    8982            0 :                         VariableSpeedCoils::SimVariableSpeedCoils(state,
    8983              :                                                                   "",
    8984              :                                                                   VSCoilNum,
    8985              :                                                                   HVAC::FanOp::Cycling,
    8986              :                                                                   HVAC::CompressorOp::On,
    8987            0 :                                                                   state.dataWaterThermalTanks->hpPartLoadRatio,
    8988              :                                                                   SpeedNum,
    8989              :                                                                   SpeedRatio,
    8990              :                                                                   0.0,
    8991              :                                                                   0.0,
    8992              :                                                                   1.0);
    8993            0 :                         state.dataFans->fans(HeatPump.FanNum)->simulate(state, FirstHVACIteration, _, _);
    8994              :                     }
    8995              :                 }
    8996              :             }
    8997              : 
    8998              :         } else {
    8999            2 :             if (HeatPump.fanPlace == HVAC::FanPlace::BlowThru) {
    9000            0 :                 state.dataFans->fans(HeatPump.FanNum)->simulate(state, FirstHVACIteration, _, _);
    9001              : 
    9002            0 :                 DXCoils::SimDXCoil(state,
    9003              :                                    HeatPump.DXCoilName,
    9004              :                                    compressorOp,
    9005              :                                    FirstHVACIteration,
    9006            0 :                                    HeatPump.DXCoilNum,
    9007              :                                    HVAC::FanOp::Cycling,
    9008            0 :                                    state.dataWaterThermalTanks->hpPartLoadRatio);
    9009              :             } else {
    9010            4 :                 DXCoils::SimDXCoil(state,
    9011              :                                    HeatPump.DXCoilName,
    9012              :                                    compressorOp,
    9013              :                                    FirstHVACIteration,
    9014            2 :                                    HeatPump.DXCoilNum,
    9015              :                                    HVAC::FanOp::Cycling,
    9016            2 :                                    state.dataWaterThermalTanks->hpPartLoadRatio);
    9017            2 :                 state.dataFans->fans(HeatPump.FanNum)->simulate(state, FirstHVACIteration, _, _);
    9018              :             }
    9019              :         }
    9020              : 
    9021            2 :         if (OutletAirSplitterNode > 0) {
    9022            0 :             state.dataLoopNodes->Node(HPAirOutletNode) = state.dataLoopNodes->Node(OutletAirSplitterNode);
    9023              :         }
    9024              : 
    9025              :         //   Simulate tank if HP compressor unavailable for water heating
    9026            2 :         this->CalcWaterThermalTank(state);
    9027              : 
    9028              :         //   If HPWH compressor is available and unit is off for another reason, off-cycle parasitics are calculated
    9029            2 :         if (AvailSchedule != 0) {
    9030            2 :             HeatPump.OffCycParaFuelRate = HeatPump.OffCycParaLoad * (1.0 - state.dataWaterThermalTanks->hpPartLoadRatio);
    9031            2 :             HeatPump.OffCycParaFuelEnergy = HeatPump.OffCycParaFuelRate * state.dataHVACGlobal->TimeStepSysSec;
    9032              :         }
    9033              : 
    9034              :         //   Warn if HPWH compressor cut-in temperature is less than the water heater tank's set point temp
    9035            2 :         if (!state.dataGlobal->WarmupFlag && !state.dataGlobal->DoingSizing && !state.dataGlobal->KickOffSimulation) {
    9036            2 :             if ((HPSetPointTemp - DeadBandTempDiff) <= this->SetPointTemp) {
    9037            2 :                 Real64 HPMinTemp = HPSetPointTemp - DeadBandTempDiff;
    9038            2 :                 const std::string HPMinTempChar = fmt::to_string(HPMinTemp);
    9039            2 :                 ++HeatPump.HPSetPointError;
    9040              :                 //  add logic for warmup, DataGlobals::KickOffSimulation and doing sizing here
    9041            2 :                 if (HeatPump.HPSetPointError == 1) {
    9042            4 :                     ShowWarningError(state,
    9043            4 :                                      format("{} \"{}:  Water heater tank set point temperature is greater than or equal to the cut-in temperature of "
    9044              :                                             "the heat pump water heater. Heat Pump will be disabled and simulation continues.",
    9045            2 :                                             HeatPump.Type,
    9046            2 :                                             HeatPump.Name));
    9047            2 :                     ShowContinueErrorTimeStamp(state, format(" ...Heat Pump cut-in temperature={}", HPMinTempChar));
    9048              :                 } else {
    9049            0 :                     ShowRecurringWarningErrorAtEnd(state,
    9050            0 :                                                    HeatPump.Type + " \"" + HeatPump.Name +
    9051              :                                                        ":  Water heater tank set point temperature is greater than or equal to the cut-in "
    9052              :                                                        "temperature of the heat pump water heater. Heat Pump will be disabled error continues...",
    9053            0 :                                                    HeatPump.HPSetPointErrIndex1,
    9054              :                                                    HPMinTemp,
    9055              :                                                    HPMinTemp);
    9056              :                 }
    9057            2 :             }
    9058              :         }
    9059            2 :         return;
    9060              :     }
    9061            6 :     Real64 savedTankTemp = this->SavedTankTemp;
    9062            6 :     HeatPump.Mode = HeatPump.SaveMode;
    9063              : 
    9064            6 :     RhoWater = Psychrometrics::RhoH2O(savedTankTemp); // update water density using tank temp
    9065              : 
    9066              :     // set the heat pump air- and water-side mass flow rate
    9067            6 :     MdotWater = HeatPump.OperatingWaterFlowRate * Psychrometrics::RhoH2O(savedTankTemp);
    9068              : 
    9069              :     // Select mode of operation (float mode or heat mode) from last iteration.
    9070              :     // Determine if heating will occur this iteration and get an estimate of the PLR
    9071            6 :     if (HeatPump.Mode == TankOperatingMode::Heating) {
    9072              :         // HPWH was heating last iteration and will continue to heat until the set point is reached
    9073            3 :         state.dataWaterThermalTanks->hpPartLoadRatio = 1.0;
    9074            3 :         if (savedTankTemp > HPSetPointTemp) { // tank set point temp may have been reduced since last iteration and float mode may be needed
    9075            0 :             HeatPump.Mode = TankOperatingMode::Floating;
    9076            0 :             state.dataWaterThermalTanks->hpPartLoadRatio = 0.0;
    9077              :             // check to see if HP needs to operate
    9078              :             // set the condenser inlet node temperature and full mass flow rate prior to calling the HPWH DX coil
    9079            0 :             if (HeatPump.HPWHTankType == DataPlant::PlantEquipmentType::WtrHeaterMixed) {
    9080            0 :                 state.dataLoopNodes->Node(HPWaterInletNode).Temp = savedTankTemp;
    9081            0 :                 state.dataLoopNodes->Node(HPWaterOutletNode).Temp = savedTankTemp;
    9082            0 :             } else if (HeatPump.HPWHTankType == DataPlant::PlantEquipmentType::WtrHeaterStratified) {
    9083            0 :                 state.dataLoopNodes->Node(HPWaterInletNode).Temp = this->SourceOutletTemp;
    9084            0 :                 state.dataLoopNodes->Node(HPWaterOutletNode).Temp = this->SourceInletTemp;
    9085              :             }
    9086            0 :             state.dataLoopNodes->Node(HPWaterInletNode).MassFlowRate = 0.0;
    9087            0 :             state.dataLoopNodes->Node(HPWaterOutletNode).MassFlowRate = 0.0;
    9088              : 
    9089              :             // Check tank temperature by setting source inlet mass flow rate to zero.
    9090            0 :             state.dataWaterThermalTanks->hpPartLoadRatio = 0.0;
    9091              : 
    9092              :             // Set the full load outlet temperature on the water heater source inlet node (init has already been called).
    9093            0 :             this->SourceInletTemp = state.dataLoopNodes->Node(HPWaterOutletNode).Temp;
    9094              : 
    9095              :             // Disable the tank's internal heating element to find PLR of the HPWH using floating temperatures.
    9096            0 :             this->MaxCapacity = 0.0;
    9097            0 :             this->MinCapacity = 0.0;
    9098            0 :             this->SourceMassFlowRate = 0.0; // disables heat pump for mixed tanks
    9099            0 :             Real64 SourceEffectivenessBackup = this->SourceEffectiveness;
    9100            0 :             this->SourceEffectiveness = 0.0; // disables heat pump for stratified tanks
    9101            0 :             this->CalcWaterThermalTank(state);
    9102            0 :             this->SourceEffectiveness = SourceEffectivenessBackup;
    9103            0 :             Real64 NewTankTemp = this->GetHPWHSensedTankTemp(state);
    9104              : 
    9105              :             // Reset the tank's internal heating element capacity.
    9106            0 :             this->MaxCapacity = HeatPump.BackupElementCapacity;
    9107            0 :             this->MinCapacity = HeatPump.BackupElementCapacity;
    9108              : 
    9109              :             // Check to see if the tank drifts below set point if no heating happens.
    9110            0 :             if (NewTankTemp <= (HPSetPointTemp - DeadBandTempDiff)) {
    9111              : 
    9112              :                 // HPWH is now in heating mode
    9113            0 :                 HeatPump.Mode = TankOperatingMode::Heating;
    9114              : 
    9115              :                 // Reset the water heater's mode (call above may have changed modes)
    9116            0 :                 this->Mode = HeatPump.SaveWHMode;
    9117              : 
    9118            0 :                 state.dataWaterThermalTanks->hpPartLoadRatio = 1.0;
    9119              :             }
    9120              :         } else { // or use side nodes may meet set point without need for heat pump compressor operation
    9121              :                  // check to see if HP needs to operate
    9122            3 :             if (HeatPump.HPWHTankType == DataPlant::PlantEquipmentType::WtrHeaterMixed) {
    9123            3 :                 state.dataLoopNodes->Node(HPWaterInletNode).Temp = savedTankTemp;
    9124            3 :                 state.dataLoopNodes->Node(HPWaterOutletNode).Temp = savedTankTemp;
    9125            0 :             } else if (HeatPump.HPWHTankType == DataPlant::PlantEquipmentType::WtrHeaterStratified) {
    9126            0 :                 state.dataLoopNodes->Node(HPWaterInletNode).Temp = this->SourceOutletTemp;
    9127            0 :                 state.dataLoopNodes->Node(HPWaterOutletNode).Temp = this->SourceInletTemp;
    9128              :             }
    9129              :             // Check tank temperature by setting source inlet mass flow rate to zero.
    9130            3 :             state.dataLoopNodes->Node(HPWaterInletNode).MassFlowRate = 0.0;
    9131            3 :             state.dataLoopNodes->Node(HPWaterOutletNode).MassFlowRate = 0.0;
    9132              : 
    9133            3 :             state.dataWaterThermalTanks->hpPartLoadRatio = 0.0;
    9134              : 
    9135              :             // Set the full load outlet temperature on the water heater source inlet node (init has already been called).
    9136            3 :             this->SourceInletTemp = state.dataLoopNodes->Node(HPWaterOutletNode).Temp;
    9137              : 
    9138              :             // Disable the tank's internal heating element to find PLR of the HPWH using floating temperatures.
    9139            3 :             this->MaxCapacity = 0.0;
    9140            3 :             this->MinCapacity = 0.0;
    9141            3 :             this->SourceMassFlowRate = 0.0; // disables heat pump for mixed tanks
    9142            3 :             Real64 SourceEffectivenessBackup = this->SourceEffectiveness;
    9143            3 :             this->SourceEffectiveness = 0.0; // disables heat pump for stratified tanks
    9144            3 :             this->CalcWaterThermalTank(state);
    9145            3 :             this->SourceEffectiveness = SourceEffectivenessBackup;
    9146            3 :             Real64 NewTankTemp = this->GetHPWHSensedTankTemp(state);
    9147              : 
    9148              :             // Reset the tank's internal heating element capacity.
    9149            3 :             this->MaxCapacity = HeatPump.BackupElementCapacity;
    9150            3 :             this->MinCapacity = HeatPump.BackupElementCapacity;
    9151              : 
    9152              :             // Check to see if the tank meets set point if no heating happens.
    9153            3 :             if (NewTankTemp > HPSetPointTemp) {
    9154              : 
    9155              :                 // HPWH is now in floating mode
    9156            1 :                 HeatPump.Mode = TankOperatingMode::Floating;
    9157              : 
    9158              :             } else {
    9159              : 
    9160              :                 // HPWH remains in heating mode
    9161            2 :                 state.dataWaterThermalTanks->hpPartLoadRatio = 1.0;
    9162              :             }
    9163              : 
    9164              :             // Reset the water heater's mode (call above may have changed modes)
    9165            3 :             this->Mode = HeatPump.SaveWHMode;
    9166              :         }
    9167              :     } else {
    9168            3 :         assert(HeatPump.Mode == TankOperatingMode::Floating);
    9169              :         // HPWH was floating last iteration and will continue to float until the cut-in temperature is reached
    9170              : 
    9171              :         // set the condenser inlet node temperature and full mass flow rate prior to calling the HPWH DX coil
    9172            3 :         if (HeatPump.HPWHTankType == DataPlant::PlantEquipmentType::WtrHeaterMixed) {
    9173            2 :             state.dataLoopNodes->Node(HPWaterInletNode).Temp = savedTankTemp;
    9174            2 :             state.dataLoopNodes->Node(HPWaterOutletNode).Temp = savedTankTemp;
    9175            1 :         } else if (HeatPump.HPWHTankType == DataPlant::PlantEquipmentType::WtrHeaterStratified) {
    9176            1 :             state.dataLoopNodes->Node(HPWaterInletNode).Temp = this->SourceOutletTemp;
    9177            1 :             state.dataLoopNodes->Node(HPWaterOutletNode).Temp = this->SourceInletTemp;
    9178              :         }
    9179            3 :         state.dataLoopNodes->Node(HPWaterInletNode).MassFlowRate = 0.0;
    9180            3 :         state.dataLoopNodes->Node(HPWaterOutletNode).MassFlowRate = 0.0;
    9181              : 
    9182              :         // Check tank temperature by setting source inlet mass flow rate to zero.
    9183            3 :         state.dataWaterThermalTanks->hpPartLoadRatio = 0.0;
    9184              : 
    9185              :         // Set the full load outlet temperature on the water heater source inlet node (init has already been called).
    9186            3 :         this->SourceInletTemp = state.dataLoopNodes->Node(HPWaterOutletNode).Temp;
    9187              : 
    9188              :         // Disable the tank's internal heating element to find PLR of the HPWH using floating temperatures.
    9189            3 :         this->MaxCapacity = 0.0;
    9190            3 :         this->MinCapacity = 0.0;
    9191            3 :         this->SourceMassFlowRate = 0.0; // disables heat pump for mixed tanks
    9192            3 :         Real64 SourceEffectivenessBackup = this->SourceEffectiveness;
    9193            3 :         this->SourceEffectiveness = 0.0; // disables heat pump for stratified tanks
    9194            3 :         this->CalcWaterThermalTank(state);
    9195            3 :         this->SourceEffectiveness = SourceEffectivenessBackup;
    9196            3 :         Real64 NewTankTemp = this->GetHPWHSensedTankTemp(state);
    9197              : 
    9198              :         // Reset the tank's internal heating element capacity.
    9199            3 :         this->MaxCapacity = HeatPump.BackupElementCapacity;
    9200            3 :         this->MinCapacity = HeatPump.BackupElementCapacity;
    9201              : 
    9202              :         // Check to see if the tank drifts below set point if no heating happens.
    9203            3 :         if (NewTankTemp <= (HPSetPointTemp - DeadBandTempDiff)) {
    9204              : 
    9205              :             // HPWH is now in heating mode
    9206            1 :             HeatPump.Mode = TankOperatingMode::Heating;
    9207              : 
    9208              :             // Reset the water heater's mode (call above may have changed modes)
    9209            1 :             this->Mode = HeatPump.SaveWHMode;
    9210              : 
    9211            1 :             state.dataWaterThermalTanks->hpPartLoadRatio = 1.0;
    9212              :         }
    9213              :     }
    9214              : 
    9215            6 :     if (HeatPump.bIsIHP) // mark the water heating call, if existing
    9216              :     {
    9217            0 :         if (state.dataIntegratedHP->IntegratedHeatPumps(HeatPump.DXCoilNum).CheckWHCall) {
    9218            0 :             if (HeatPump.Mode == TankOperatingMode::Heating)
    9219            0 :                 state.dataIntegratedHP->IntegratedHeatPumps(HeatPump.DXCoilNum).IsWHCallAvail = true;
    9220              :             else
    9221            0 :                 state.dataIntegratedHP->IntegratedHeatPumps(HeatPump.DXCoilNum).IsWHCallAvail = false;
    9222              :         }
    9223              :     }
    9224              : 
    9225              :     // If the HPWH was in heating mode during the last DataGlobals::TimeStep or if it was determined that
    9226              :     // heating would be needed during this DataGlobals::TimeStep to maintain setpoint, do the heating calculation.
    9227            6 :     int SpeedNum = 0;
    9228            6 :     Real64 SpeedRatio = 0.0;
    9229            6 :     if (HeatPump.Mode == TankOperatingMode::Heating) {
    9230              : 
    9231              :         // set up air flow on DX coil inlet node
    9232            3 :         state.dataLoopNodes->Node(DXCoilAirInletNode).MassFlowRate =
    9233            3 :             state.dataWaterThermalTanks->mdotAir * state.dataWaterThermalTanks->hpPartLoadRatio;
    9234              : 
    9235              :         // set the condenser inlet node mass flow rate prior to calling the DXCoils::CalcHPWHDXCoil
    9236            3 :         state.dataLoopNodes->Node(HPWaterInletNode).MassFlowRate = MdotWater * state.dataWaterThermalTanks->hpPartLoadRatio;
    9237            3 :         this->SourceMassFlowRate = MdotWater * state.dataWaterThermalTanks->hpPartLoadRatio;
    9238              : 
    9239              :         // Do the coil and tank calculations at full PLR to see if it overshoots setpoint.
    9240            3 :         bool bIterSpeed = false;
    9241            3 :         if (MaxSpeedNum > 0) { // lowest speed of VS HPWH coil
    9242            0 :             SpeedRatio = 1.0;
    9243            0 :             state.dataWaterThermalTanks->hpPartLoadRatio = 1.0;
    9244            0 :             bIterSpeed = true; // prepare for iterating between speed levels
    9245            0 :             SpeedNum = 1;
    9246            0 :             this->SetVSHPWHFlowRates(state, HeatPump, SpeedNum, SpeedRatio, RhoWater, MdotWater, FirstHVACIteration);
    9247              : 
    9248            0 :             if (HeatPump.bIsIHP) {
    9249            0 :                 bIterSpeed = false; // don't iterate speed unless match conditions below
    9250            0 :                 IHPMode = IntegratedHeatPump::GetCurWorkMode(state, HeatPump.DXCoilNum);
    9251              : 
    9252            0 :                 if (state.dataIntegratedHP->IntegratedHeatPumps(HeatPump.DXCoilNum).CheckWHCall) {
    9253              :                     int VSCoilNum;
    9254            0 :                     if (IntegratedHeatPump::IHPOperationMode::DedicatedWaterHtg == IHPMode) {
    9255            0 :                         VSCoilNum = state.dataIntegratedHP->IntegratedHeatPumps(HeatPump.DXCoilNum).DWHCoilIndex;
    9256            0 :                         state.dataIntegratedHP->IntegratedHeatPumps(HeatPump.DXCoilNum).CurMode =
    9257              :                             IntegratedHeatPump::IHPOperationMode::DedicatedWaterHtg;
    9258              :                     } else {
    9259            0 :                         VSCoilNum = state.dataIntegratedHP->IntegratedHeatPumps(HeatPump.DXCoilNum).SCWHCoilIndex;
    9260            0 :                         state.dataIntegratedHP->IntegratedHeatPumps(HeatPump.DXCoilNum).CurMode = IntegratedHeatPump::IHPOperationMode::SCWHMatchWH;
    9261              :                     }
    9262              : 
    9263            0 :                     this->SetVSHPWHFlowRates(state, HeatPump, SpeedNum, SpeedRatio, RhoWater, MdotWater, FirstHVACIteration);
    9264              : 
    9265            0 :                     VariableSpeedCoils::SimVariableSpeedCoils(state,
    9266              :                                                               "",
    9267              :                                                               VSCoilNum,
    9268              :                                                               HVAC::FanOp::Cycling,
    9269              :                                                               HVAC::CompressorOp::On,
    9270            0 :                                                               state.dataWaterThermalTanks->hpPartLoadRatio,
    9271              :                                                               SpeedNum,
    9272              :                                                               SpeedRatio,
    9273              :                                                               0.0,
    9274              :                                                               0.0,
    9275              :                                                               1.0);
    9276              : 
    9277            0 :                     state.dataIntegratedHP->IntegratedHeatPumps(HeatPump.DXCoilNum).CurMode = IHPMode;
    9278            0 :                     this->SetVSHPWHFlowRates(state, HeatPump, SpeedNum, SpeedRatio, RhoWater, MdotWater, FirstHVACIteration);
    9279              :                 } else {
    9280            0 :                     SpeedNum = IntegratedHeatPump::GetLowSpeedNumIHP(state, HeatPump.DXCoilNum);
    9281              : 
    9282            0 :                     this->SetVSHPWHFlowRates(state, HeatPump, SpeedNum, SpeedRatio, RhoWater, MdotWater, FirstHVACIteration);
    9283            0 :                     IntegratedHeatPump::SimIHP(state,
    9284              :                                                HeatPump.DXCoilName,
    9285            0 :                                                HeatPump.DXCoilNum,
    9286              :                                                HVAC::FanOp::Cycling,
    9287              :                                                HVAC::CompressorOp::On,
    9288            0 :                                                state.dataWaterThermalTanks->hpPartLoadRatio,
    9289              :                                                SpeedNum,
    9290              :                                                SpeedRatio,
    9291              :                                                0.0,
    9292              :                                                0.0,
    9293              :                                                true,
    9294              :                                                false,
    9295            0 :                                                1.0);
    9296              : 
    9297            0 :                     if ((IntegratedHeatPump::IHPOperationMode::SCWHMatchWH == IHPMode) ||
    9298              :                         (IntegratedHeatPump::IHPOperationMode::DedicatedWaterHtg == IHPMode)) {
    9299            0 :                         bIterSpeed = true;
    9300              :                     } else {
    9301            0 :                         this->SourceMassFlowRate = state.dataIntegratedHP->IntegratedHeatPumps(HeatPump.DXCoilNum).TankSourceWaterMassFlowRate;
    9302            0 :                         MdotWater = this->SourceMassFlowRate;
    9303              :                     }
    9304              : 
    9305            0 :                     if (IntegratedHeatPump::IHPOperationMode::SHDWHElecHeatOff == IHPMode) // turn off heater element
    9306              :                     {
    9307            0 :                         this->MaxCapacity = 0.0;
    9308            0 :                         this->MinCapacity = 0.0;
    9309              :                     }
    9310              :                 }
    9311              :             } else {
    9312            0 :                 VariableSpeedCoils::SimVariableSpeedCoils(state,
    9313              :                                                           HeatPump.DXCoilName,
    9314            0 :                                                           HeatPump.DXCoilNum,
    9315              :                                                           HVAC::FanOp::Cycling,
    9316              :                                                           HVAC::CompressorOp::On,
    9317            0 :                                                           state.dataWaterThermalTanks->hpPartLoadRatio,
    9318              :                                                           SpeedNum,
    9319              :                                                           SpeedRatio,
    9320              :                                                           0.0,
    9321              :                                                           0.0,
    9322              :                                                           1.0);
    9323              :             }
    9324              : 
    9325            0 :             this->CalcWaterThermalTank(state);
    9326              :         } else {
    9327            3 :             this->ConvergeSingleSpeedHPWHCoilAndTank(state, state.dataWaterThermalTanks->hpPartLoadRatio);
    9328              :         }
    9329              : 
    9330            3 :         Real64 NewTankTemp = this->GetHPWHSensedTankTemp(state);
    9331            3 :         Real64 LowSpeedTankTemp = NewTankTemp;
    9332            3 :         Real64 HPWHCondInletNodeLast = state.dataLoopNodes->Node(HPWaterInletNode).Temp;
    9333              : 
    9334            3 :         if (NewTankTemp > HPSetPointTemp) {
    9335            2 :             HeatPump.Mode = TankOperatingMode::Floating;
    9336            2 :             TankOperatingMode tmpMode = HeatPump.SaveWHMode;
    9337            6 :             auto f = [&state, this, HPSetPointTemp, tmpMode, MdotWater](Real64 const HPPartLoadRatio) {
    9338            6 :                 return this->PLRResidualHPWH(state, HPPartLoadRatio, HPSetPointTemp, tmpMode, MdotWater);
    9339            2 :             };
    9340            2 :             Real64 zeroResidual = 1.0;
    9341            2 :             if (MaxSpeedNum > 0) {
    9342              :                 // square the solving, and avoid warning
    9343              :                 // due to very small capacity at lowest speed of VSHPWH coil
    9344            0 :                 if (bIterSpeed)
    9345            0 :                     zeroResidual = this->PLRResidualHPWH(state, 0.0, HPSetPointTemp, tmpMode, MdotWater);
    9346              :                 else
    9347            0 :                     zeroResidual = -1.0;
    9348              :             }
    9349              : 
    9350            2 :             if (zeroResidual > 0.0) { // then iteration
    9351              :                 int SolFla;
    9352            2 :                 General::SolveRoot(state, Acc, MaxIte, SolFla, state.dataWaterThermalTanks->hpPartLoadRatio, f, 0.0, 1.0);
    9353            2 :                 if (SolFla == -1) {
    9354            0 :                     std::string IterNum;
    9355            0 :                     IterNum = fmt::to_string(MaxIte);
    9356            0 :                     if (!state.dataGlobal->WarmupFlag) {
    9357            0 :                         ++HeatPump.IterLimitExceededNum2;
    9358            0 :                         if (HeatPump.IterLimitExceededNum2 == 1) {
    9359            0 :                             ShowWarningError(state, format("{} \"{}\"", HeatPump.Type, HeatPump.Name));
    9360            0 :                             ShowContinueError(state,
    9361            0 :                                               format("Iteration limit exceeded calculating heat pump water heater compressor part-load ratio, "
    9362              :                                                      "maximum iterations = {}. Part-load ratio returned = {:.3R}",
    9363              :                                                      IterNum,
    9364            0 :                                                      state.dataWaterThermalTanks->hpPartLoadRatio));
    9365            0 :                             ShowContinueErrorTimeStamp(state, "This error occurred in float mode.");
    9366              :                         } else {
    9367            0 :                             ShowRecurringWarningErrorAtEnd(
    9368              :                                 state,
    9369            0 :                                 HeatPump.Type + " \"" + HeatPump.Name +
    9370              :                                     "\":  Iteration limit exceeded in float mode warning continues. Part-load ratio statistics follow.",
    9371            0 :                                 HeatPump.IterLimitErrIndex2,
    9372            0 :                                 state.dataWaterThermalTanks->hpPartLoadRatio,
    9373            0 :                                 state.dataWaterThermalTanks->hpPartLoadRatio);
    9374              :                         }
    9375              :                     }
    9376            2 :                 } else if (SolFla == -2) {
    9377            0 :                     state.dataWaterThermalTanks->hpPartLoadRatio =
    9378            0 :                         max(0.0, min(1.0, (HPSetPointTemp - savedTankTemp) / (NewTankTemp - savedTankTemp)));
    9379            0 :                     if (!state.dataGlobal->WarmupFlag) {
    9380            0 :                         ++HeatPump.RegulaFalsiFailedNum2;
    9381            0 :                         if (HeatPump.RegulaFalsiFailedNum2 == 1) {
    9382            0 :                             ShowWarningError(state, format("{} \"{}\"", HeatPump.Type, HeatPump.Name));
    9383            0 :                             ShowContinueError(state,
    9384            0 :                                               format("Heat pump water heater compressor part-load ratio calculation failed: PLR limits of 0 to 1 "
    9385              :                                                      "exceeded. Part-load ratio used = {:.3R}",
    9386            0 :                                                      state.dataWaterThermalTanks->hpPartLoadRatio));
    9387            0 :                             ShowContinueError(state, "Please send this information to the EnergyPlus support group.");
    9388            0 :                             ShowContinueErrorTimeStamp(state, "This error occurred in float mode.");
    9389              :                         } else {
    9390            0 :                             ShowRecurringWarningErrorAtEnd(
    9391              :                                 state,
    9392            0 :                                 HeatPump.Type + " \"" + HeatPump.Name +
    9393              :                                     "\": Part-load ratio calculation failed in float mode warning continues. Part-load ratio statistics follow.",
    9394            0 :                                 HeatPump.RegulaFalsiFailedIndex2,
    9395            0 :                                 state.dataWaterThermalTanks->hpPartLoadRatio,
    9396            0 :                                 state.dataWaterThermalTanks->hpPartLoadRatio);
    9397              :                         }
    9398              :                     }
    9399              :                 }
    9400              :             } else {
    9401            0 :                 state.dataWaterThermalTanks->hpPartLoadRatio = 0.0;
    9402              :             }
    9403              : 
    9404              :             // Re-calculate the HPWH Coil to get the correct heat transfer rate.
    9405            2 :             state.dataLoopNodes->Node(HPWaterInletNode).Temp = this->SourceOutletTemp;
    9406            2 :             if (MaxSpeedNum > 0) {
    9407            0 :                 SpeedRatio = 1.0;
    9408            0 :                 SpeedNum = 1;
    9409              : 
    9410            0 :                 this->SetVSHPWHFlowRates(state, HeatPump, SpeedNum, SpeedRatio, RhoWater, MdotWater, FirstHVACIteration);
    9411              : 
    9412            0 :                 if (HeatPump.bIsIHP) {
    9413            0 :                     if (bIterSpeed) {
    9414            0 :                         IntegratedHeatPump::SimIHP(state,
    9415              :                                                    HeatPump.DXCoilName,
    9416            0 :                                                    HeatPump.DXCoilNum,
    9417              :                                                    HVAC::FanOp::Cycling,
    9418              :                                                    HVAC::CompressorOp::On,
    9419            0 :                                                    state.dataWaterThermalTanks->hpPartLoadRatio,
    9420              :                                                    SpeedNum,
    9421              :                                                    SpeedRatio,
    9422              :                                                    0.0,
    9423              :                                                    0.0,
    9424              :                                                    true,
    9425              :                                                    false,
    9426            0 :                                                    1.0);
    9427              :                     }
    9428              :                 } else {
    9429            0 :                     VariableSpeedCoils::SimVariableSpeedCoils(state,
    9430              :                                                               HeatPump.DXCoilName,
    9431            0 :                                                               HeatPump.DXCoilNum,
    9432              :                                                               HVAC::FanOp::Cycling,
    9433              :                                                               HVAC::CompressorOp::On,
    9434            0 :                                                               state.dataWaterThermalTanks->hpPartLoadRatio,
    9435              :                                                               SpeedNum,
    9436              :                                                               SpeedRatio,
    9437              :                                                               0.0,
    9438              :                                                               0.0,
    9439              :                                                               1.0);
    9440              :                 }
    9441              : 
    9442              :             } else {
    9443            2 :                 DXCoils::CalcHPWHDXCoil(state, HeatPump.DXCoilNum, state.dataWaterThermalTanks->hpPartLoadRatio);
    9444              :             }
    9445            1 :         } else if (bIterSpeed) {
    9446            0 :             for (int loopIter = 1; loopIter <= 4; ++loopIter) {
    9447            0 :                 HeatPump.Mode = TankOperatingMode::Heating; // modHeatMode is important for system convergence
    9448            0 :                 state.dataWaterThermalTanks->hpPartLoadRatio = 1.0;
    9449            0 :                 SpeedRatio = 1.0;
    9450            0 :                 int LowSpeedNum = 2;
    9451            0 :                 if (HeatPump.bIsIHP) {
    9452            0 :                     LowSpeedNum = IntegratedHeatPump::GetLowSpeedNumIHP(state, HeatPump.DXCoilNum);
    9453            0 :                     MaxSpeedNum = IntegratedHeatPump::GetMaxSpeedNumIHP(state, HeatPump.DXCoilNum);
    9454              :                 }
    9455              : 
    9456            0 :                 for (int i = LowSpeedNum; i <= MaxSpeedNum; ++i) {
    9457            0 :                     SpeedNum = i;
    9458            0 :                     this->SetVSHPWHFlowRates(state, HeatPump, SpeedNum, SpeedRatio, RhoWater, MdotWater, FirstHVACIteration);
    9459            0 :                     if (HeatPump.bIsIHP) {
    9460            0 :                         IntegratedHeatPump::SimIHP(state,
    9461              :                                                    HeatPump.DXCoilName,
    9462            0 :                                                    HeatPump.DXCoilNum,
    9463              :                                                    HVAC::FanOp::Cycling,
    9464              :                                                    HVAC::CompressorOp::On,
    9465            0 :                                                    state.dataWaterThermalTanks->hpPartLoadRatio,
    9466              :                                                    SpeedNum,
    9467              :                                                    SpeedRatio,
    9468              :                                                    0.0,
    9469              :                                                    0.0,
    9470              :                                                    true,
    9471              :                                                    false,
    9472            0 :                                                    1.0);
    9473              :                     } else {
    9474            0 :                         VariableSpeedCoils::SimVariableSpeedCoils(state,
    9475              :                                                                   HeatPump.DXCoilName,
    9476            0 :                                                                   HeatPump.DXCoilNum,
    9477              :                                                                   HVAC::FanOp::Cycling,
    9478              :                                                                   HVAC::CompressorOp::On,
    9479            0 :                                                                   state.dataWaterThermalTanks->hpPartLoadRatio,
    9480              :                                                                   SpeedNum,
    9481              :                                                                   SpeedRatio,
    9482              :                                                                   0.0,
    9483              :                                                                   0.0,
    9484              :                                                                   1.0);
    9485              :                     }
    9486              : 
    9487              :                     // HPWH condenser water temperature difference
    9488            0 :                     Real64 CondenserDeltaT = state.dataLoopNodes->Node(HPWaterOutletNode).Temp - state.dataLoopNodes->Node(HPWaterInletNode).Temp;
    9489              : 
    9490              :                     //           move the full load outlet temperature rate to the water heater structure variables
    9491              :                     //           (water heaters source inlet node temperature/mdot are set in Init, set it here after DXCoils::CalcHPWHDXCoil has
    9492              :                     //           been called)
    9493            0 :                     this->SourceInletTemp = state.dataLoopNodes->Node(HPWaterInletNode).Temp + CondenserDeltaT;
    9494              :                     //           this CALL does not update node temps, must use WaterThermalTank variables
    9495              :                     // select tank type
    9496            0 :                     if (HeatPump.HPWHTankType == DataPlant::PlantEquipmentType::WtrHeaterMixed) {
    9497            0 :                         this->CalcWaterThermalTankMixed(state);
    9498            0 :                         NewTankTemp = this->TankTemp;
    9499            0 :                     } else if (HeatPump.HPWHTankType == DataPlant::PlantEquipmentType::WtrHeaterStratified) {
    9500            0 :                         this->CalcWaterThermalTankStratified(state);
    9501            0 :                         NewTankTemp = this->FindStratifiedTankSensedTemp(state);
    9502              :                     }
    9503              : 
    9504            0 :                     if (NewTankTemp > HPSetPointTemp) {
    9505            0 :                         SpeedNum = i;
    9506            0 :                         break;
    9507              :                     } else {
    9508            0 :                         LowSpeedTankTemp = NewTankTemp;
    9509              :                     }
    9510              :                 }
    9511              : 
    9512            0 :                 if (NewTankTemp > HPSetPointTemp) {
    9513              :                     int SolFla;
    9514            0 :                     std::string IterNum;
    9515            0 :                     auto f = [&state, this, SpeedNum, HPWaterInletNode, HPWaterOutletNode, RhoWater, HPSetPointTemp, &HeatPump, FirstHVACIteration](
    9516              :                                  Real64 const SpeedRatio) {
    9517            0 :                         return this->PLRResidualIterSpeed(state,
    9518              :                                                           SpeedRatio,
    9519            0 :                                                           this->HeatPumpNum,
    9520              :                                                           SpeedNum,
    9521              :                                                           HPWaterInletNode,
    9522              :                                                           HPWaterOutletNode,
    9523              :                                                           RhoWater,
    9524              :                                                           HPSetPointTemp,
    9525            0 :                                                           HeatPump.SaveWHMode,
    9526            0 :                                                           FirstHVACIteration);
    9527            0 :                     };
    9528            0 :                     General::SolveRoot(state, Acc, MaxIte, SolFla, SpeedRatio, f, 1.0e-10, 1.0);
    9529              : 
    9530            0 :                     if (SolFla == -1) {
    9531            0 :                         IterNum = fmt::to_string(MaxIte);
    9532            0 :                         if (!state.dataGlobal->WarmupFlag) {
    9533            0 :                             ++HeatPump.IterLimitExceededNum1;
    9534            0 :                             if (HeatPump.IterLimitExceededNum1 == 1) {
    9535            0 :                                 ShowWarningError(state, format("{} \"{}\"", HeatPump.Type, HeatPump.Name));
    9536            0 :                                 ShowContinueError(state,
    9537            0 :                                                   format("Iteration limit exceeded calculating heat pump water heater speed speed ratio ratio, "
    9538              :                                                          "maximum iterations = {}. speed ratio returned = {:.3R}",
    9539              :                                                          IterNum,
    9540              :                                                          SpeedRatio));
    9541            0 :                                 ShowContinueErrorTimeStamp(state, "This error occurred in heating mode.");
    9542              :                             } else {
    9543            0 :                                 ShowRecurringWarningErrorAtEnd(
    9544              :                                     state,
    9545            0 :                                     HeatPump.Type + " \"" + HeatPump.Name +
    9546              :                                         "\":  Iteration limit exceeded in heating mode warning continues. speed ratio statistics follow.",
    9547            0 :                                     HeatPump.IterLimitErrIndex1,
    9548              :                                     SpeedRatio,
    9549              :                                     SpeedRatio);
    9550              :                             }
    9551              :                         }
    9552            0 :                     } else if (SolFla == -2) {
    9553            0 :                         SpeedRatio = max(0.0, min(1.0, (HPSetPointTemp - LowSpeedTankTemp) / (NewTankTemp - LowSpeedTankTemp)));
    9554            0 :                         if (!state.dataGlobal->WarmupFlag) {
    9555            0 :                             ++HeatPump.RegulaFalsiFailedNum1;
    9556            0 :                             if (HeatPump.RegulaFalsiFailedNum1 == 1) {
    9557            0 :                                 ShowWarningError(state, format("{} \"{}\"", HeatPump.Type, HeatPump.Name));
    9558            0 :                                 ShowContinueError(state,
    9559            0 :                                                   format("Heat pump water heater speed ratio calculation failed: speed ratio limits of 0 to 1 "
    9560              :                                                          "exceeded. speed ratio used = {:.3R}",
    9561              :                                                          SpeedRatio));
    9562            0 :                                 ShowContinueError(state, "Please send this information to the EnergyPlus support group.");
    9563            0 :                                 ShowContinueErrorTimeStamp(state, "This error occurred in heating mode.");
    9564              :                             } else {
    9565            0 :                                 ShowRecurringWarningErrorAtEnd(
    9566              :                                     state,
    9567            0 :                                     HeatPump.Type + " \"" + HeatPump.Name +
    9568              :                                         "\":  Speed ratio calculation failed in heating mode warning continues. Speed ratio statistics follow.",
    9569            0 :                                     HeatPump.RegulaFalsiFailedIndex1,
    9570              :                                     SpeedRatio,
    9571              :                                     SpeedRatio);
    9572              :                             }
    9573              :                         }
    9574              :                     }
    9575            0 :                 } else {
    9576            0 :                     SpeedNum = MaxSpeedNum;
    9577            0 :                     SpeedRatio = 1.0;
    9578              :                 }
    9579              : 
    9580            0 :                 state.dataWaterThermalTanks->hpPartLoadRatio = 1.0;
    9581            0 :                 this->SetVSHPWHFlowRates(state, HeatPump, SpeedNum, SpeedRatio, RhoWater, MdotWater, FirstHVACIteration);
    9582              : 
    9583            0 :                 if (HeatPump.bIsIHP) {
    9584            0 :                     IntegratedHeatPump::SimIHP(state,
    9585              :                                                HeatPump.DXCoilName,
    9586            0 :                                                HeatPump.DXCoilNum,
    9587              :                                                HVAC::FanOp::Cycling,
    9588              :                                                HVAC::CompressorOp::On,
    9589            0 :                                                state.dataWaterThermalTanks->hpPartLoadRatio,
    9590              :                                                SpeedNum,
    9591              :                                                SpeedRatio,
    9592              :                                                0.0,
    9593              :                                                0.0,
    9594              :                                                true,
    9595              :                                                false,
    9596            0 :                                                1.0);
    9597              :                 } else {
    9598            0 :                     VariableSpeedCoils::SimVariableSpeedCoils(state,
    9599              :                                                               HeatPump.DXCoilName,
    9600            0 :                                                               HeatPump.DXCoilNum,
    9601              :                                                               HVAC::FanOp::Cycling,
    9602              :                                                               HVAC::CompressorOp::On,
    9603            0 :                                                               state.dataWaterThermalTanks->hpPartLoadRatio,
    9604              :                                                               SpeedNum,
    9605              :                                                               SpeedRatio,
    9606              :                                                               0.0,
    9607              :                                                               0.0,
    9608              :                                                               1.0);
    9609              :                 }
    9610              : 
    9611              :                 // HPWH condenser water temperature difference
    9612            0 :                 Real64 CondenserDeltaT = state.dataLoopNodes->Node(HPWaterOutletNode).Temp - state.dataLoopNodes->Node(HPWaterInletNode).Temp;
    9613              : 
    9614              :                 //           move the full load outlet temperature rate to the water heater structure variables
    9615              :                 //           (water heaters source inlet node temperature/mdot are set in Init, set it here after DXCoils::CalcHPWHDXCoil has been
    9616              :                 //           called)
    9617            0 :                 this->SourceInletTemp = state.dataLoopNodes->Node(HPWaterInletNode).Temp + CondenserDeltaT;
    9618              :                 //           this CALL does not update node temps, must use WaterThermalTank variables
    9619              :                 // select tank type
    9620            0 :                 if (HeatPump.HPWHTankType == DataPlant::PlantEquipmentType::WtrHeaterMixed) {
    9621            0 :                     this->CalcWaterThermalTankMixed(state);
    9622            0 :                     NewTankTemp = this->TankTemp;
    9623            0 :                 } else if (HeatPump.HPWHTankType == DataPlant::PlantEquipmentType::WtrHeaterStratified) {
    9624            0 :                     this->CalcWaterThermalTankStratified(state);
    9625            0 :                     NewTankTemp = this->FindStratifiedTankSensedTemp(state);
    9626              :                 }
    9627              :                 // update inlet temp
    9628            0 :                 state.dataLoopNodes->Node(HPWaterInletNode).Temp = this->SourceOutletTemp;
    9629            0 :                 if (std::abs(state.dataLoopNodes->Node(HPWaterInletNode).Temp - HPWHCondInletNodeLast) < HVAC::SmallTempDiff) break;
    9630            0 :                 HPWHCondInletNodeLast = state.dataLoopNodes->Node(HPWaterInletNode).Temp;
    9631              :             }
    9632              : 
    9633              :         } else {
    9634              :             // Set the PLR to 1 if we're not going to reach setpoint during this DataGlobals::TimeStep.
    9635            1 :             state.dataWaterThermalTanks->hpPartLoadRatio = 1.0;
    9636              :         }
    9637              :     }
    9638              : 
    9639            6 :     if (HeatPump.bIsIHP) {
    9640            0 :         if (state.dataIntegratedHP->IntegratedHeatPumps(HeatPump.DXCoilNum).CheckWHCall) {
    9641            0 :             IntegratedHeatPump::ClearCoils(state, HeatPump.DXCoilNum); // clear node info when checking the heating load
    9642              :         }
    9643              :     }
    9644              : 
    9645              :     // set air-side mass flow rate for final calculation
    9646            6 :     if (InletAirMixerNode > 0) {
    9647            0 :         state.dataLoopNodes->Node(InletAirMixerNode).MassFlowRate =
    9648            0 :             state.dataWaterThermalTanks->mdotAir * state.dataWaterThermalTanks->hpPartLoadRatio;
    9649            0 :         state.dataLoopNodes->Node(HPAirInletNode).MassFlowRate = state.dataWaterThermalTanks->mdotAir * state.dataWaterThermalTanks->hpPartLoadRatio *
    9650            0 :                                                                  (1.0 - state.dataWaterThermalTanks->mixerInletAirSchedule);
    9651            0 :         state.dataLoopNodes->Node(OutdoorAirNode).MassFlowRate =
    9652            0 :             state.dataWaterThermalTanks->mdotAir * state.dataWaterThermalTanks->hpPartLoadRatio * state.dataWaterThermalTanks->mixerInletAirSchedule;
    9653              :         //   IF HPWH is off, pass zone node conditions through HPWH air-side
    9654            0 :         if (state.dataWaterThermalTanks->hpPartLoadRatio == 0)
    9655            0 :             state.dataLoopNodes->Node(InletAirMixerNode) = state.dataLoopNodes->Node(HPAirInletNode);
    9656              :     } else {
    9657            6 :         if (OutdoorAirNode == 0) {
    9658            1 :             state.dataLoopNodes->Node(HPAirInletNode).MassFlowRate =
    9659            1 :                 state.dataWaterThermalTanks->mdotAir * state.dataWaterThermalTanks->hpPartLoadRatio;
    9660              :         } else {
    9661            5 :             state.dataLoopNodes->Node(OutdoorAirNode).MassFlowRate =
    9662            5 :                 state.dataWaterThermalTanks->mdotAir * state.dataWaterThermalTanks->hpPartLoadRatio;
    9663              :         }
    9664              :     }
    9665            6 :     if (state.dataWaterThermalTanks->hpPartLoadRatio == 0) this->SourceInletTemp = this->SourceOutletTemp;
    9666              : 
    9667              :     // set water-side mass flow rate for final calculation
    9668            6 :     state.dataLoopNodes->Node(HPWaterInletNode).MassFlowRate = MdotWater * state.dataWaterThermalTanks->hpPartLoadRatio;
    9669              : 
    9670            6 :     if (MaxSpeedNum > 0) {
    9671              : 
    9672              :         // it is important to use mdotAir to reset the notes, otherwise, could fail to converge
    9673            0 :         if (InletAirMixerNode > 0) {
    9674            0 :             state.dataLoopNodes->Node(InletAirMixerNode).MassFlowRateMax = state.dataWaterThermalTanks->mdotAir;
    9675            0 :             state.dataLoopNodes->Node(InletAirMixerNode).MassFlowRateMaxAvail = state.dataWaterThermalTanks->mdotAir;
    9676              :         } else {
    9677            0 :             if (OutdoorAirNode == 0) {
    9678            0 :                 state.dataLoopNodes->Node(HPAirInletNode).MassFlowRateMax = state.dataWaterThermalTanks->mdotAir;
    9679            0 :                 state.dataLoopNodes->Node(HPAirInletNode).MassFlowRateMaxAvail = state.dataWaterThermalTanks->mdotAir;
    9680              :             } else {
    9681            0 :                 state.dataLoopNodes->Node(OutdoorAirNode).MassFlowRateMax = state.dataWaterThermalTanks->mdotAir;
    9682            0 :                 state.dataLoopNodes->Node(OutdoorAirNode).MassFlowRateMaxAvail = state.dataWaterThermalTanks->mdotAir;
    9683              :             }
    9684              :         }
    9685              : 
    9686              :         //   set the max mass flow rate for outdoor fans
    9687            0 :         state.dataLoopNodes->Node(HeatPump.FanOutletNode).MassFlowRateMax = state.dataWaterThermalTanks->mdotAir;
    9688              : 
    9689            0 :         if (HeatPump.bIsIHP) {
    9690              :             // pass node information using resulting PLR
    9691            0 :             if (HeatPump.fanPlace == HVAC::FanPlace::BlowThru) {
    9692              :                 //   simulate fan and DX coil twice to pass PLF (OnOffFanPartLoadFraction) to fan
    9693            0 :                 state.dataFans->fans(HeatPump.FanNum)->simulate(state, FirstHVACIteration, _, _);
    9694              : 
    9695            0 :                 IntegratedHeatPump::SimIHP(state,
    9696              :                                            HeatPump.DXCoilName,
    9697            0 :                                            HeatPump.DXCoilNum,
    9698              :                                            HVAC::FanOp::Cycling,
    9699              :                                            compressorOp,
    9700            0 :                                            state.dataWaterThermalTanks->hpPartLoadRatio,
    9701              :                                            SpeedNum,
    9702              :                                            SpeedRatio,
    9703              :                                            0.0,
    9704              :                                            0.0,
    9705              :                                            true,
    9706              :                                            false,
    9707            0 :                                            1.0);
    9708            0 :                 state.dataFans->fans(HeatPump.FanNum)->simulate(state, FirstHVACIteration, _, _);
    9709              : 
    9710            0 :                 IntegratedHeatPump::SimIHP(state,
    9711              :                                            HeatPump.DXCoilName,
    9712            0 :                                            HeatPump.DXCoilNum,
    9713              :                                            HVAC::FanOp::Cycling,
    9714              :                                            compressorOp,
    9715            0 :                                            state.dataWaterThermalTanks->hpPartLoadRatio,
    9716              :                                            SpeedNum,
    9717              :                                            SpeedRatio,
    9718              :                                            0.0,
    9719              :                                            0.0,
    9720              :                                            true,
    9721              :                                            false,
    9722            0 :                                            1.0);
    9723              :             } else {
    9724              :                 //   simulate DX coil and fan twice to pass fan power (FanElecPower) to DX coil
    9725            0 :                 IntegratedHeatPump::SimIHP(state,
    9726              :                                            HeatPump.DXCoilName,
    9727            0 :                                            HeatPump.DXCoilNum,
    9728              :                                            HVAC::FanOp::Cycling,
    9729              :                                            compressorOp,
    9730            0 :                                            state.dataWaterThermalTanks->hpPartLoadRatio,
    9731              :                                            SpeedNum,
    9732              :                                            SpeedRatio,
    9733              :                                            0.0,
    9734              :                                            0.0,
    9735              :                                            true,
    9736              :                                            false,
    9737            0 :                                            1.0);
    9738            0 :                 state.dataFans->fans(HeatPump.FanNum)->simulate(state, FirstHVACIteration, _, _);
    9739              : 
    9740            0 :                 IntegratedHeatPump::SimIHP(state,
    9741              :                                            HeatPump.DXCoilName,
    9742            0 :                                            HeatPump.DXCoilNum,
    9743              :                                            HVAC::FanOp::Cycling,
    9744              :                                            compressorOp,
    9745            0 :                                            state.dataWaterThermalTanks->hpPartLoadRatio,
    9746              :                                            SpeedNum,
    9747              :                                            SpeedRatio,
    9748              :                                            0.0,
    9749              :                                            0.0,
    9750              :                                            true,
    9751              :                                            false,
    9752            0 :                                            1.0);
    9753            0 :                 state.dataFans->fans(HeatPump.FanNum)->simulate(state, FirstHVACIteration, _, _);
    9754              :             }
    9755              :         } else {
    9756              :             // pass node information using resulting PLR
    9757            0 :             if (HeatPump.fanPlace == HVAC::FanPlace::BlowThru) {
    9758              :                 //   simulate fan and DX coil twice to pass PLF (OnOffFanPartLoadFraction) to fan
    9759            0 :                 state.dataFans->fans(HeatPump.FanNum)->simulate(state, FirstHVACIteration, _, _);
    9760              : 
    9761            0 :                 VariableSpeedCoils::SimVariableSpeedCoils(state,
    9762              :                                                           HeatPump.DXCoilName,
    9763            0 :                                                           HeatPump.DXCoilNum,
    9764              :                                                           HVAC::FanOp::Cycling,
    9765              :                                                           compressorOp,
    9766            0 :                                                           state.dataWaterThermalTanks->hpPartLoadRatio,
    9767              :                                                           SpeedNum,
    9768              :                                                           SpeedRatio,
    9769              :                                                           0.0,
    9770              :                                                           0.0,
    9771              :                                                           1.0);
    9772              : 
    9773            0 :                 state.dataFans->fans(HeatPump.FanNum)->simulate(state, FirstHVACIteration, _, _);
    9774              : 
    9775            0 :                 VariableSpeedCoils::SimVariableSpeedCoils(state,
    9776              :                                                           HeatPump.DXCoilName,
    9777            0 :                                                           HeatPump.DXCoilNum,
    9778              :                                                           HVAC::FanOp::Cycling,
    9779              :                                                           compressorOp,
    9780            0 :                                                           state.dataWaterThermalTanks->hpPartLoadRatio,
    9781              :                                                           SpeedNum,
    9782              :                                                           SpeedRatio,
    9783              :                                                           0.0,
    9784              :                                                           0.0,
    9785              :                                                           1.0);
    9786              :             } else {
    9787              :                 //   simulate DX coil and fan twice to pass fan power (FanElecPower) to DX coil
    9788            0 :                 VariableSpeedCoils::SimVariableSpeedCoils(state,
    9789              :                                                           HeatPump.DXCoilName,
    9790            0 :                                                           HeatPump.DXCoilNum,
    9791              :                                                           HVAC::FanOp::Cycling,
    9792              :                                                           compressorOp,
    9793            0 :                                                           state.dataWaterThermalTanks->hpPartLoadRatio,
    9794              :                                                           SpeedNum,
    9795              :                                                           SpeedRatio,
    9796              :                                                           0.0,
    9797              :                                                           0.0,
    9798              :                                                           1.0);
    9799              : 
    9800            0 :                 state.dataFans->fans(HeatPump.FanNum)->simulate(state, FirstHVACIteration, _, _);
    9801              : 
    9802            0 :                 VariableSpeedCoils::SimVariableSpeedCoils(state,
    9803              :                                                           HeatPump.DXCoilName,
    9804            0 :                                                           HeatPump.DXCoilNum,
    9805              :                                                           HVAC::FanOp::Cycling,
    9806              :                                                           compressorOp,
    9807            0 :                                                           state.dataWaterThermalTanks->hpPartLoadRatio,
    9808              :                                                           SpeedNum,
    9809              :                                                           SpeedRatio,
    9810              :                                                           0.0,
    9811              :                                                           0.0,
    9812              :                                                           1.0);
    9813              : 
    9814            0 :                 state.dataFans->fans(HeatPump.FanNum)->simulate(state, FirstHVACIteration, _, _);
    9815              :             }
    9816              :         }
    9817              :     } else { // single speed
    9818              : 
    9819              :         // pass node information using resulting PLR
    9820            6 :         if (HeatPump.fanPlace == HVAC::FanPlace::BlowThru) {
    9821              :             //   simulate fan and DX coil twice to pass PLF (OnOffFanPartLoadFraction) to fan
    9822            0 :             state.dataFans->fans(HeatPump.FanNum)->simulate(state, FirstHVACIteration, _, _);
    9823              : 
    9824            0 :             DXCoils::SimDXCoil(state,
    9825              :                                HeatPump.DXCoilName,
    9826              :                                compressorOp,
    9827              :                                FirstHVACIteration,
    9828            0 :                                HeatPump.DXCoilNum,
    9829              :                                HVAC::FanOp::Cycling,
    9830            0 :                                state.dataWaterThermalTanks->hpPartLoadRatio);
    9831              : 
    9832            0 :             state.dataFans->fans(HeatPump.FanNum)->simulate(state, FirstHVACIteration, _, _);
    9833              : 
    9834            0 :             DXCoils::SimDXCoil(state,
    9835              :                                HeatPump.DXCoilName,
    9836              :                                compressorOp,
    9837              :                                FirstHVACIteration,
    9838            0 :                                HeatPump.DXCoilNum,
    9839              :                                HVAC::FanOp::Cycling,
    9840            0 :                                state.dataWaterThermalTanks->hpPartLoadRatio);
    9841              :         } else {
    9842              :             //   simulate DX coil and fan twice to pass fan power (FanElecPower) to DX coil
    9843           12 :             DXCoils::SimDXCoil(state,
    9844              :                                HeatPump.DXCoilName,
    9845              :                                compressorOp,
    9846              :                                FirstHVACIteration,
    9847            6 :                                HeatPump.DXCoilNum,
    9848              :                                HVAC::FanOp::Cycling,
    9849            6 :                                state.dataWaterThermalTanks->hpPartLoadRatio);
    9850              : 
    9851            6 :             state.dataFans->fans(HeatPump.FanNum)->simulate(state, FirstHVACIteration, _, _);
    9852              : 
    9853           12 :             DXCoils::SimDXCoil(state,
    9854              :                                HeatPump.DXCoilName,
    9855              :                                compressorOp,
    9856              :                                FirstHVACIteration,
    9857            6 :                                HeatPump.DXCoilNum,
    9858              :                                HVAC::FanOp::Cycling,
    9859            6 :                                state.dataWaterThermalTanks->hpPartLoadRatio);
    9860              : 
    9861            6 :             state.dataFans->fans(HeatPump.FanNum)->simulate(state, FirstHVACIteration, _, _);
    9862              :         }
    9863              :     }
    9864              : 
    9865              :     // Call the tank one more time with the final PLR
    9866            6 :     if (HeatPump.HPWHTankType == DataPlant::PlantEquipmentType::WtrHeaterMixed) {
    9867            5 :         this->CalcWaterThermalTankMixed(state);
    9868            1 :     } else if (HeatPump.HPWHTankType == DataPlant::PlantEquipmentType::WtrHeaterStratified) {
    9869            1 :         this->CalcWaterThermalTankStratified(state);
    9870              :     } else {
    9871            0 :         assert(0);
    9872              :     }
    9873              : 
    9874              :     // set HPWH outlet node equal to the outlet air splitter node conditions if outlet air splitter node exists
    9875            6 :     if (OutletAirSplitterNode > 0) {
    9876            0 :         state.dataLoopNodes->Node(HPAirOutletNode) = state.dataLoopNodes->Node(OutletAirSplitterNode);
    9877            0 :         state.dataLoopNodes->Node(ExhaustAirNode) = state.dataLoopNodes->Node(OutletAirSplitterNode);
    9878              :     }
    9879              : 
    9880              :     // Check schedule to divert air-side cooling to outdoors.
    9881            6 :     if (HeatPump.outletAirSplitterSched != nullptr) {
    9882            0 :         Real64 OutletAirSplitterSch = HeatPump.outletAirSplitterSched->getCurrentVal();
    9883            0 :         state.dataLoopNodes->Node(HPAirOutletNode).MassFlowRate =
    9884            0 :             state.dataWaterThermalTanks->mdotAir * state.dataWaterThermalTanks->hpPartLoadRatio * (1.0 - OutletAirSplitterSch);
    9885            0 :         state.dataLoopNodes->Node(ExhaustAirNode).MassFlowRate =
    9886            0 :             state.dataWaterThermalTanks->mdotAir * state.dataWaterThermalTanks->hpPartLoadRatio * OutletAirSplitterSch;
    9887              :     }
    9888              : 
    9889            6 :     HeatPump.HeatingPLR = state.dataWaterThermalTanks->hpPartLoadRatio;
    9890            6 :     HeatPump.OnCycParaFuelRate = HeatPump.OnCycParaLoad * state.dataWaterThermalTanks->hpPartLoadRatio;
    9891            6 :     HeatPump.OnCycParaFuelEnergy = HeatPump.OnCycParaFuelRate * state.dataHVACGlobal->TimeStepSysSec;
    9892            6 :     HeatPump.OffCycParaFuelRate = HeatPump.OffCycParaLoad * (1.0 - state.dataWaterThermalTanks->hpPartLoadRatio);
    9893            6 :     HeatPump.OffCycParaFuelEnergy = HeatPump.OffCycParaFuelRate * state.dataHVACGlobal->TimeStepSysSec;
    9894            6 :     if (HeatPump.HPWHTankType == DataPlant::PlantEquipmentType::WtrHeaterMixed) {
    9895            5 :         HeatPump.ControlTempAvg = this->TankTempAvg;
    9896            5 :         HeatPump.ControlTempFinal = this->TankTemp;
    9897            1 :     } else if (HeatPump.HPWHTankType == DataPlant::PlantEquipmentType::WtrHeaterStratified) {
    9898            1 :         HeatPump.ControlTempAvg = this->FindStratifiedTankSensedTemp(state, true);
    9899            1 :         HeatPump.ControlTempFinal = this->FindStratifiedTankSensedTemp(state);
    9900              :     } else {
    9901            0 :         assert(0);
    9902              :     }
    9903              : 
    9904            6 :     switch (HeatPump.InletAirConfiguration) {
    9905              : 
    9906              :     //   no sensible capacity to zone for outdoor and scheduled HPWH
    9907            6 :     case WTTAmbientTemp::OutsideAir:
    9908              :     case WTTAmbientTemp::Schedule: {
    9909            6 :         HeatPump.HPWaterHeaterSensibleCapacity = 0.0;
    9910            6 :         HeatPump.HPWaterHeaterLatentCapacity = 0.0;
    9911              : 
    9912              :         //   calculate sensible capacity to zone for inlet air configuration equals Zone Only or Zone And Outdoor Air configurations
    9913            6 :         break;
    9914              :     }
    9915            0 :     default:
    9916              : 
    9917            0 :         Real64 CpAir = Psychrometrics::PsyCpAirFnW(state.dataLoopNodes->Node(HPAirInletNode).HumRat);
    9918              : 
    9919              :         //     add parasitics to zone heat balance if parasitic heat load is to zone otherwise neglect parasitics
    9920            0 :         if (HeatPump.ParasiticTempIndicator == WTTAmbientTemp::TempZone) {
    9921            0 :             HeatPump.HPWaterHeaterSensibleCapacity =
    9922            0 :                 (state.dataLoopNodes->Node(HPAirOutletNode).MassFlowRate * CpAir *
    9923            0 :                  (state.dataLoopNodes->Node(HPAirOutletNode).Temp - state.dataLoopNodes->Node(HPAirInletNode).Temp)) +
    9924            0 :                 HeatPump.OnCycParaFuelRate + HeatPump.OffCycParaFuelRate;
    9925              :         } else {
    9926            0 :             HeatPump.HPWaterHeaterSensibleCapacity =
    9927            0 :                 state.dataLoopNodes->Node(HPAirOutletNode).MassFlowRate * CpAir *
    9928            0 :                 (state.dataLoopNodes->Node(HPAirOutletNode).Temp - state.dataLoopNodes->Node(HPAirInletNode).Temp);
    9929              :         }
    9930              : 
    9931            0 :         HeatPump.HPWaterHeaterLatentCapacity = state.dataLoopNodes->Node(HPAirOutletNode).MassFlowRate *
    9932            0 :                                                (state.dataLoopNodes->Node(HPAirOutletNode).HumRat - state.dataLoopNodes->Node(HPAirInletNode).HumRat);
    9933            0 :         break;
    9934              :     }
    9935              : }
    9936              : 
    9937          264 : void WaterThermalTankData::CalcWaterThermalTank(EnergyPlusData &state)
    9938              : {
    9939          264 :     switch (this->WaterThermalTankType) {
    9940          253 :     case DataPlant::PlantEquipmentType::WtrHeaterMixed:
    9941          253 :         this->CalcWaterThermalTankMixed(state);
    9942          253 :         break;
    9943           11 :     case DataPlant::PlantEquipmentType::WtrHeaterStratified:
    9944           11 :         this->CalcWaterThermalTankStratified(state);
    9945           11 :         break;
    9946            0 :     default:
    9947            0 :         assert(false);
    9948              :     }
    9949          264 : }
    9950              : 
    9951           15 : Real64 WaterThermalTankData::GetHPWHSensedTankTemp(EnergyPlusData &state)
    9952              : {
    9953           15 :     switch (this->WaterThermalTankType) {
    9954           10 :     case DataPlant::PlantEquipmentType::WtrHeaterMixed:
    9955           10 :         return this->TankTemp;
    9956              :         break;
    9957            5 :     case DataPlant::PlantEquipmentType::WtrHeaterStratified:
    9958            5 :         return this->FindStratifiedTankSensedTemp(state);
    9959              :         break;
    9960            0 :     default:
    9961            0 :         assert(false);
    9962              :         return 0.0; // silence compiler
    9963              :     }
    9964              : }
    9965              : 
    9966            3 : void WaterThermalTankData::ConvergeSingleSpeedHPWHCoilAndTank(EnergyPlusData &state, Real64 const partLoadRatio)
    9967              : {
    9968            3 :     HeatPumpWaterHeaterData &HPWH = state.dataWaterThermalTanks->HPWaterHeater(this->HeatPumpNum);
    9969            3 :     DXCoils::DXCoilData &Coil = state.dataDXCoils->DXCoil(HPWH.DXCoilNum);
    9970              : 
    9971            3 :     Real64 PrevTankTemp = this->SourceOutletTemp;
    9972           11 :     for (int i = 1; i <= 10; ++i) {
    9973              : 
    9974           11 :         DXCoils::CalcHPWHDXCoil(state, HPWH.DXCoilNum, partLoadRatio);
    9975           11 :         this->SourceInletTemp = state.dataLoopNodes->Node(HPWH.CondWaterOutletNode).Temp;
    9976              : 
    9977           11 :         this->CalcWaterThermalTank(state);
    9978           11 :         state.dataLoopNodes->Node(Coil.WaterInNode).Temp = this->SourceOutletTemp;
    9979              : 
    9980           11 :         if (std::abs(this->SourceOutletTemp - PrevTankTemp) < HVAC::SmallTempDiff) {
    9981            3 :             break;
    9982              :         }
    9983              : 
    9984            8 :         PrevTankTemp = this->SourceOutletTemp;
    9985              :     }
    9986            3 : }
    9987              : 
    9988            0 : void WaterThermalTankData::SetVSHPWHFlowRates(EnergyPlusData &state,
    9989              :                                               HeatPumpWaterHeaterData &HPWH, // heat pump coil
    9990              :                                               int const SpeedNum,            // upper speed number
    9991              :                                               Real64 const SpeedRatio,       // interpolation ration between upper and lower speed
    9992              :                                               Real64 const WaterDens,        // tank water density
    9993              :                                               Real64 &MdotWater,             // water flow rate
    9994              :                                               bool const FirstHVACIteration)
    9995              : {
    9996              :     // FUNCTION INFORMATION:
    9997              :     //       AUTHOR         B.Shen, ORNL, 12/2014
    9998              :     //       DATE WRITTEN   May 2005
    9999              :     //       MODIFIED
   10000              :     //       RE-ENGINEERED
   10001              : 
   10002              :     // PURPOSE OF THIS FUNCTION:
   10003              :     //  set water and air flow rates driven by the variable-speed HPWH coil
   10004              :     //  calculate resultant HPWH coil output
   10005              : 
   10006            0 :     int SpeedLow = SpeedNum - 1;
   10007            0 :     if (SpeedLow < 1) SpeedLow = 1;
   10008              : 
   10009            0 :     int HPWaterInletNode = HPWH.CondWaterInletNode;
   10010            0 :     int DXCoilAirInletNode = HPWH.DXCoilAirInletNode;
   10011            0 :     if (HPWH.bIsIHP) {
   10012            0 :         HPWH.OperatingWaterFlowRate = IntegratedHeatPump::GetWaterVolFlowRateIHP(state, HPWH.DXCoilNum, SpeedNum, SpeedRatio);
   10013            0 :         state.dataWaterThermalTanks->mdotAir = IntegratedHeatPump::GetAirMassFlowRateIHP(state, HPWH.DXCoilNum, SpeedNum, SpeedRatio, true);
   10014            0 :         HPWH.OperatingAirFlowRate = IntegratedHeatPump::GetAirVolFlowRateIHP(state, HPWH.DXCoilNum, SpeedNum, SpeedRatio, true);
   10015            0 :         state.dataLoopNodes->Node(DXCoilAirInletNode).MassFlowRate = state.dataWaterThermalTanks->mdotAir;
   10016            0 :         state.dataLoopNodes->Node(DXCoilAirInletNode).MassFlowRateMaxAvail = state.dataWaterThermalTanks->mdotAir;
   10017            0 :         state.dataLoopNodes->Node(DXCoilAirInletNode).MassFlowRateMax = state.dataWaterThermalTanks->mdotAir;
   10018              :     } else {
   10019            0 :         HPWH.OperatingWaterFlowRate = HPWH.HPWHWaterVolFlowRate(SpeedNum) * SpeedRatio + HPWH.HPWHWaterVolFlowRate(SpeedLow) * (1.0 - SpeedRatio);
   10020            0 :         HPWH.OperatingAirFlowRate = HPWH.HPWHAirVolFlowRate(SpeedNum) * SpeedRatio + HPWH.HPWHAirVolFlowRate(SpeedLow) * (1.0 - SpeedRatio);
   10021            0 :         state.dataWaterThermalTanks->mdotAir =
   10022            0 :             HPWH.HPWHAirMassFlowRate(SpeedNum) * SpeedRatio + HPWH.HPWHAirMassFlowRate(SpeedLow) * (1.0 - SpeedRatio);
   10023              :     }
   10024              : 
   10025            0 :     MdotWater = HPWH.OperatingWaterFlowRate * WaterDens;
   10026            0 :     this->SourceMassFlowRate = MdotWater;
   10027              : 
   10028            0 :     state.dataLoopNodes->Node(DXCoilAirInletNode).MassFlowRate = state.dataWaterThermalTanks->mdotAir;
   10029            0 :     state.dataLoopNodes->Node(HPWaterInletNode).MassFlowRate = MdotWater;
   10030            0 :     this->SourceMassFlowRate = MdotWater;
   10031              : 
   10032            0 :     if (HPWH.InletAirMixerNode > 0) {
   10033            0 :         state.dataLoopNodes->Node(HPWH.InletAirMixerNode).MassFlowRate = state.dataWaterThermalTanks->mdotAir;
   10034            0 :         state.dataLoopNodes->Node(HPWH.InletAirMixerNode).MassFlowRateMaxAvail = state.dataWaterThermalTanks->mdotAir;
   10035              :     } else {
   10036            0 :         if (HPWH.OutsideAirNode == 0) {
   10037            0 :             state.dataLoopNodes->Node(HPWH.HeatPumpAirInletNode).MassFlowRate = state.dataWaterThermalTanks->mdotAir;
   10038            0 :             state.dataLoopNodes->Node(HPWH.HeatPumpAirInletNode).MassFlowRateMaxAvail = state.dataWaterThermalTanks->mdotAir;
   10039              :         } else {
   10040            0 :             state.dataLoopNodes->Node(HPWH.OutsideAirNode).MassFlowRate = state.dataWaterThermalTanks->mdotAir;
   10041            0 :             state.dataLoopNodes->Node(HPWH.OutsideAirNode).MassFlowRateMaxAvail = state.dataWaterThermalTanks->mdotAir;
   10042              :         }
   10043              :     }
   10044              : 
   10045              :     // put fan component first, regardless placement, to calculate fan power
   10046            0 :     int FanInNode = state.dataFans->fans(HPWH.FanNum)->inletNodeNum;
   10047              : 
   10048            0 :     state.dataLoopNodes->Node(FanInNode).MassFlowRate = state.dataWaterThermalTanks->mdotAir;
   10049            0 :     state.dataLoopNodes->Node(FanInNode).MassFlowRateMaxAvail = state.dataWaterThermalTanks->mdotAir;
   10050            0 :     state.dataLoopNodes->Node(FanInNode).MassFlowRateMax = state.dataWaterThermalTanks->mdotAir;
   10051            0 :     if (HPWH.fanType != HVAC::FanType::SystemModel) {
   10052            0 :         state.dataFans->fans(HPWH.FanNum)->massFlowRateMaxAvail = state.dataWaterThermalTanks->mdotAir;
   10053              :     } // system fan will use the inlet node max avail.
   10054              : 
   10055            0 :     state.dataFans->fans(HPWH.FanNum)->simulate(state, FirstHVACIteration, _, _);
   10056            0 : }
   10057              : 
   10058            0 : Real64 WaterThermalTankData::PLRResidualIterSpeed(EnergyPlusData &state,
   10059              :                                                   Real64 const SpeedRatio, // speed ratio between two speed levels
   10060              :                                                   int const HPNum,
   10061              :                                                   int const SpeedNum,
   10062              :                                                   int const HPWaterInletNode,
   10063              :                                                   int const HPWaterOutletNode,
   10064              :                                                   Real64 const RhoWater,
   10065              :                                                   Real64 const desTankTemp,
   10066              :                                                   TankOperatingMode const mode,
   10067              :                                                   bool const FirstHVACIteration)
   10068              : {
   10069              :     // FUNCTION INFORMATION:
   10070              :     //       AUTHOR         B.Shen, ORNL, 12/2014
   10071              :     //       MODIFIED
   10072              :     //       RE-ENGINEERED
   10073              : 
   10074              :     // PURPOSE OF THIS FUNCTION:
   10075              :     //  Calculates residual function (desired tank temp - actual tank temp), when iterating speed ration between two speed levels
   10076              :     //  HP water heater output depends on the speed ratio which is being varied to zero the residual.
   10077              : 
   10078              :     // METHODOLOGY EMPLOYED:
   10079              :     //  Calls residuals to get tank temperature at the given speed ratio between a lower and an upper speed levels
   10080              :     //  and calculates the residual as defined respectively for DataPlant::PlantEquipmentType::WtrHeaterMixed or
   10081              :     //  DataPlant::PlantEquipmentType::WtrHeaterStratified
   10082              : 
   10083            0 :     this->Mode = mode;
   10084            0 :     state.dataWaterThermalTanks->hpPartLoadRatio = 1.0;
   10085            0 :     Real64 MdotWater = 0.0;
   10086              : 
   10087            0 :     auto &HPWH = state.dataWaterThermalTanks->HPWaterHeater(HPNum);
   10088              : 
   10089            0 :     this->SetVSHPWHFlowRates(state, HPWH, SpeedNum, SpeedRatio, RhoWater, MdotWater, FirstHVACIteration);
   10090              : 
   10091            0 :     if (state.dataWaterThermalTanks->HPWaterHeater(HPNum).bIsIHP) {
   10092            0 :         IntegratedHeatPump::SimIHP(state,
   10093            0 :                                    state.dataWaterThermalTanks->HPWaterHeater(HPNum).DXCoilName,
   10094            0 :                                    state.dataWaterThermalTanks->HPWaterHeater(HPNum).DXCoilNum,
   10095              :                                    HVAC::FanOp::Cycling,
   10096              :                                    HVAC::CompressorOp::On,
   10097            0 :                                    state.dataWaterThermalTanks->hpPartLoadRatio,
   10098              :                                    SpeedNum,
   10099              :                                    SpeedRatio,
   10100              :                                    0.0,
   10101              :                                    0.0,
   10102              :                                    true,
   10103              :                                    false,
   10104            0 :                                    1.0);
   10105              :     } else {
   10106            0 :         VariableSpeedCoils::SimVariableSpeedCoils(state,
   10107            0 :                                                   state.dataWaterThermalTanks->HPWaterHeater(HPNum).DXCoilName,
   10108            0 :                                                   state.dataWaterThermalTanks->HPWaterHeater(HPNum).DXCoilNum,
   10109              :                                                   HVAC::FanOp::Cycling,
   10110              :                                                   HVAC::CompressorOp::On,
   10111            0 :                                                   state.dataWaterThermalTanks->hpPartLoadRatio,
   10112              :                                                   SpeedNum,
   10113              :                                                   SpeedRatio,
   10114              :                                                   0.0,
   10115              :                                                   0.0,
   10116              :                                                   1.0);
   10117              :     }
   10118              : 
   10119              :     Real64 CondenserDeltaT;
   10120            0 :     CondenserDeltaT = state.dataLoopNodes->Node(HPWaterOutletNode).Temp - state.dataLoopNodes->Node(HPWaterInletNode).Temp;
   10121              : 
   10122              :     //           move the full load outlet temperature rate to the water heater structure variables
   10123              :     //           (water heaters source inlet node temperature/mdot are set in Init, set it here after DXCoils::CalcHPWHDXCoil has been called)
   10124            0 :     this->SourceInletTemp = state.dataLoopNodes->Node(HPWaterInletNode).Temp + CondenserDeltaT;
   10125              : 
   10126              :     //           this CALL does not update node temps, must use WaterThermalTank variables
   10127              :     // select tank type
   10128            0 :     Real64 NewTankTemp = 0.0;
   10129            0 :     if (state.dataWaterThermalTanks->HPWaterHeater(HPNum).HPWHTankType == DataPlant::PlantEquipmentType::WtrHeaterMixed) {
   10130            0 :         this->CalcWaterThermalTankMixed(state);
   10131            0 :         NewTankTemp = this->TankTemp;
   10132            0 :     } else if (state.dataWaterThermalTanks->HPWaterHeater(HPNum).HPWHTankType == DataPlant::PlantEquipmentType::WtrHeaterStratified) {
   10133            0 :         this->CalcWaterThermalTankStratified(state);
   10134            0 :         NewTankTemp = this->FindStratifiedTankSensedTemp(state);
   10135              :     }
   10136              : 
   10137            0 :     return desTankTemp - NewTankTemp;
   10138              : }
   10139              : 
   10140            6 : Real64 WaterThermalTankData::PLRResidualHPWH(
   10141              :     EnergyPlusData &state, Real64 const HPPartLoadRatio, Real64 const desTankTemp, TankOperatingMode const mode, Real64 const mDotWater)
   10142              : {
   10143              :     // FUNCTION INFORMATION:
   10144              :     //       AUTHOR         B.Griffith,  Richard Raustad
   10145              :     //       DATE WRITTEN   Jan 2012
   10146              :     //       MODIFIED
   10147              :     //       RE-ENGINEERED  Noel Merket, Oct 2015
   10148              : 
   10149              :     // PURPOSE OF THIS FUNCTION:
   10150              :     //  Calculates residual function (desired tank temp - actual tank temp)
   10151              :     //  HP water heater output depends on the part load ratio which is being varied to zero the residual.
   10152              : 
   10153              :     // METHODOLOGY EMPLOYED:
   10154              :     //  Calls with CalcWaterThermalTankMixed or CalcWaterThermalTankStratified to get tank temperature at the given part load ratio (source water
   10155              :     //  mass flow rate) and calculates the residual as defined above
   10156              : 
   10157            6 :     HeatPumpWaterHeaterData &HeatPump = state.dataWaterThermalTanks->HPWaterHeater(this->HeatPumpNum);
   10158            6 :     bool const isVariableSpeed = (HeatPump.NumofSpeed > 0);
   10159            6 :     this->Mode = mode;
   10160              :     // Apply the PLR
   10161            6 :     if (this->WaterThermalTankType == DataPlant::PlantEquipmentType::WtrHeaterMixed) {
   10162              :         // For a mixed tank, the PLR is applied to the source mass flow rate.
   10163            3 :         this->SourceMassFlowRate = mDotWater * HPPartLoadRatio;
   10164            3 :         this->CalcWaterThermalTankMixed(state);
   10165              :     } else {
   10166            3 :         assert(this->WaterThermalTankType == DataPlant::PlantEquipmentType::WtrHeaterStratified);
   10167              :         // For a stratified tank, the PLR is applied to the Coil.TotalHeatingEnergyRate
   10168              :         // whether that's a VarSpeedCoil or DXCoils::DXCoil.
   10169              :         // Here we create a pointer to the TotalHeatingEnergyRate for the appropriate coil type.
   10170              :         Real64 *CoilTotalHeatingEnergyRatePtr;
   10171            3 :         if (isVariableSpeed) {
   10172            0 :             if (HeatPump.bIsIHP)
   10173            0 :                 CoilTotalHeatingEnergyRatePtr = &state.dataIntegratedHP->IntegratedHeatPumps(HeatPump.DXCoilNum).TotalWaterHeatingRate;
   10174              :             else
   10175            0 :                 CoilTotalHeatingEnergyRatePtr = &state.dataVariableSpeedCoils->VarSpeedCoil(HeatPump.DXCoilNum).TotalHeatingEnergyRate;
   10176              :         } else {
   10177            3 :             CoilTotalHeatingEnergyRatePtr = &state.dataDXCoils->DXCoil(HeatPump.DXCoilNum).TotalHeatingEnergyRate;
   10178              :         }
   10179              :         // Copy the value of the total heating energy rate
   10180            3 :         Real64 const CoilTotalHeatingEnergyRateBackup = *CoilTotalHeatingEnergyRatePtr;
   10181              :         // Apply the PLR
   10182            3 :         *CoilTotalHeatingEnergyRatePtr *= HPPartLoadRatio;
   10183              :         // Tank Calculation
   10184            3 :         this->CalcWaterThermalTankStratified(state);
   10185              :         // Restore the original value
   10186            3 :         *CoilTotalHeatingEnergyRatePtr = CoilTotalHeatingEnergyRateBackup;
   10187              :     }
   10188            6 :     Real64 NewTankTemp = this->GetHPWHSensedTankTemp(state);
   10189            6 :     return desTankTemp - NewTankTemp;
   10190              : }
   10191              : 
   10192            5 : bool WaterThermalTankData::SourceHeatNeed([[maybe_unused]] EnergyPlusData &state,
   10193              :                                           Real64 const OutletTemp,
   10194              :                                           Real64 const DeadBandTemp,
   10195              :                                           Real64 const SetPointTemp_loc)
   10196              : {
   10197              :     // FUNCTION INFORMATION:
   10198              :     //       AUTHOR         Yueyue Zhou
   10199              :     //       DATE WRITTEN   May 2019
   10200              :     //       MODIFIED       na
   10201              :     //       RE-ENGINEERED  na
   10202              : 
   10203              :     // PURPOSE OF THIS FUNCTION:
   10204              :     // Determine by tank type, tank temperature and control mode if source side flow is needed
   10205              : 
   10206              :     // return value initialization
   10207            5 :     bool NeedsHeatOrCool = false;
   10208              : 
   10209            5 :     if (!this->IsChilledWaterTank) {
   10210            5 :         if (this->SourceSideControlMode == SourceSideControl::IndirectHeatPrimarySetpoint) {
   10211            1 :             if (OutletTemp < DeadBandTemp) {
   10212            1 :                 NeedsHeatOrCool = true;
   10213            0 :             } else if ((OutletTemp >= DeadBandTemp) && (OutletTemp < SetPointTemp_loc)) {
   10214              :                 // inside the deadband, use saved mode from water heater calcs
   10215            0 :                 if (this->SavedMode == TankOperatingMode::Heating) {
   10216            0 :                     NeedsHeatOrCool = true;
   10217            0 :                 } else if (this->SavedMode == TankOperatingMode::Floating) {
   10218            0 :                     NeedsHeatOrCool = false;
   10219              :                 }
   10220              : 
   10221            0 :             } else if (OutletTemp >= SetPointTemp_loc) {
   10222            0 :                 NeedsHeatOrCool = false;
   10223              :             }
   10224            4 :         } else if (this->SourceSideControlMode == SourceSideControl::IndirectHeatAltSetpoint) {
   10225              :             // get alternate setpoint
   10226            4 :             Real64 const AltSetpointTemp = this->sourceSideAltSetpointSched->getCurrentVal();
   10227            4 :             Real64 const AltDeadBandTemp = AltSetpointTemp - this->DeadBandDeltaTemp;
   10228            4 :             if (OutletTemp < AltDeadBandTemp) {
   10229            3 :                 NeedsHeatOrCool = true;
   10230            1 :             } else if ((OutletTemp >= AltDeadBandTemp) && (OutletTemp < AltSetpointTemp)) {
   10231              :                 // inside the deadband, use saved mode from water heater calcs
   10232            0 :                 if (this->SavedMode == TankOperatingMode::Heating) {
   10233            0 :                     NeedsHeatOrCool = true;
   10234            0 :                 } else if (this->SavedMode == TankOperatingMode::Floating) {
   10235            0 :                     NeedsHeatOrCool = false;
   10236              :                 }
   10237              : 
   10238            1 :             } else if (OutletTemp >= AltSetpointTemp) {
   10239            1 :                 NeedsHeatOrCool = false;
   10240              :             }
   10241            0 :         } else if (this->SourceSideControlMode == SourceSideControl::StorageTank) {
   10242            0 :             if (OutletTemp < this->TankTempLimit) {
   10243            0 :                 NeedsHeatOrCool = true;
   10244              :             } else {
   10245            0 :                 NeedsHeatOrCool = false;
   10246              :             }
   10247              :         }
   10248              :     } else { // is a chilled water tank so flip logic
   10249            0 :         if (OutletTemp > DeadBandTemp) {
   10250            0 :             NeedsHeatOrCool = true;
   10251            0 :         } else if ((OutletTemp <= DeadBandTemp) && (OutletTemp > SetPointTemp_loc)) {
   10252              :             // inside the deadband, use saved mode from water thermal tank calcs (modes only for mixed)
   10253            0 :             if (this->WaterThermalTankType == DataPlant::PlantEquipmentType::ChilledWaterTankMixed) {
   10254            0 :                 if (this->SavedMode == TankOperatingMode::Cooling) {
   10255            0 :                     NeedsHeatOrCool = true;
   10256            0 :                 } else if (this->SavedMode == TankOperatingMode::Floating) {
   10257            0 :                     NeedsHeatOrCool = false;
   10258              :                 }
   10259            0 :             } else if (this->WaterThermalTankType == DataPlant::PlantEquipmentType::ChilledWaterTankStratified) {
   10260            0 :                 NeedsHeatOrCool = true;
   10261              :             }
   10262              : 
   10263            0 :         } else if (OutletTemp <= SetPointTemp_loc) {
   10264            0 :             NeedsHeatOrCool = false;
   10265              :         }
   10266              :     }
   10267            5 :     return NeedsHeatOrCool;
   10268              : }
   10269              : 
   10270           17 : Real64 WaterThermalTankData::PlantMassFlowRatesFunc(EnergyPlusData &state,
   10271              :                                                     int const InNodeNum,
   10272              :                                                     bool const FirstHVACIteration,
   10273              :                                                     WaterHeaterSide const WaterThermalTankSide,
   10274              :                                                     const DataPlant::LoopSideLocation PlantLoopSide,
   10275              :                                                     [[maybe_unused]] bool const PlumbedInSeries,
   10276              :                                                     DataBranchAirLoopPlant::ControlType const BranchControlType,
   10277              :                                                     Real64 const OutletTemp,
   10278              :                                                     Real64 const DeadBandTemp,
   10279              :                                                     Real64 const SetPointTemp_loc)
   10280              : {
   10281              : 
   10282              :     // FUNCTION INFORMATION:
   10283              :     //       AUTHOR         Brent Griffith
   10284              :     //       DATE WRITTEN   October 2007
   10285              :     //       MODIFIED       na
   10286              :     //       RE-ENGINEERED  na
   10287              : 
   10288              :     // PURPOSE OF THIS FUNCTION:
   10289              :     // collect routines for setting flow rates for Water heaters
   10290              :     // with plant connections.
   10291              : 
   10292              :     // determine current mode.  there are three possible
   10293              :     //  1.  passing thru what was given to inlet node
   10294              :     //  2.  potentially making a flow request
   10295              :     //  3.  throttling flow in response to Plant's restrictions (MassFlowRateMaxAvail)
   10296              :     // init default mode changed to Unassigned
   10297           17 :     FlowMode CurrentMode = FlowMode::Invalid; // default
   10298              : 
   10299           17 :     if (PlantLoopSide == DataPlant::LoopSideLocation::Invalid) {
   10300           14 :         CurrentMode = FlowMode::PassingFlowThru;
   10301            3 :     } else if (PlantLoopSide == DataPlant::LoopSideLocation::Supply) {
   10302              :         // If FlowLock is False (0), the tank sets the plant loop mdot
   10303              :         // If FlowLock is True (1),  the new resolved plant loop mdot is used
   10304            1 :         if (this->UseCurrentFlowLock == DataPlant::FlowLock::Unlocked) {
   10305            1 :             CurrentMode = FlowMode::PassingFlowThru;
   10306            1 :             if ((this->UseSideLoadRequested > 0.0) && (WaterThermalTankSide == WaterHeaterSide::Use)) {
   10307            0 :                 CurrentMode = FlowMode::MaybeRequestingFlow;
   10308              :             }
   10309              :         } else {
   10310            0 :             CurrentMode = FlowMode::PassingFlowThru;
   10311              :         }
   10312            1 :         if (WaterThermalTankSide == WaterHeaterSide::Source) {
   10313            1 :             CurrentMode = FlowMode::MaybeRequestingFlow;
   10314              :         }
   10315            2 :     } else if (PlantLoopSide == DataPlant::LoopSideLocation::Demand) {
   10316              : 
   10317              :         //  2.  Might be Requesting Flow.
   10318            2 :         if (FirstHVACIteration) {
   10319            1 :             if (BranchControlType == DataBranchAirLoopPlant::ControlType::Bypass) {
   10320            0 :                 CurrentMode = FlowMode::PassingFlowThru;
   10321              :             } else {
   10322            1 :                 CurrentMode = FlowMode::MaybeRequestingFlow;
   10323              :             }
   10324              :         } else {
   10325            1 :             if (BranchControlType == DataBranchAirLoopPlant::ControlType::Bypass) {
   10326            0 :                 CurrentMode = FlowMode::PassingFlowThru;
   10327              :             } else {
   10328            1 :                 CurrentMode = FlowMode::ThrottlingFlow;
   10329              :             }
   10330              :         }
   10331              :     }
   10332              : 
   10333              :     // evaluate Availability schedule,
   10334           17 :     bool ScheduledAvail = true;
   10335           17 :     if (WaterThermalTankSide == WaterHeaterSide::Use) {
   10336            6 :         if (this->useSideAvailSched->getCurrentVal() == 0.0) {
   10337            0 :             ScheduledAvail = false;
   10338              :         }
   10339           11 :     } else if (WaterThermalTankSide == WaterHeaterSide::Source) {
   10340           11 :         if (this->sourceSideAvailSched->getCurrentVal() == 0.0) {
   10341            0 :             ScheduledAvail = false;
   10342              :         }
   10343              :     }
   10344              : 
   10345              :     // now act based on current mode
   10346           17 :     Real64 FlowResult = 0.0;
   10347           17 :     switch (CurrentMode) {
   10348              : 
   10349           14 :     case FlowMode::PassingFlowThru: {
   10350           14 :         if (!ScheduledAvail) {
   10351            0 :             FlowResult = 0.0;
   10352              :         } else {
   10353           14 :             FlowResult = state.dataLoopNodes->Node(InNodeNum).MassFlowRate;
   10354              :         }
   10355              : 
   10356           14 :         break;
   10357              :     }
   10358            1 :     case FlowMode::ThrottlingFlow: {
   10359              :         // first determine what mass flow would be if it is to requested
   10360            1 :         Real64 MassFlowRequest = 0.0;
   10361            1 :         if (!ScheduledAvail) {
   10362            0 :             MassFlowRequest = 0.0;
   10363              :         } else {
   10364            1 :             if (WaterThermalTankSide == WaterHeaterSide::Use) {
   10365            0 :                 MassFlowRequest = this->PlantUseMassFlowRateMax;
   10366            1 :             } else if (WaterThermalTankSide == WaterHeaterSide::Source) {
   10367            1 :                 MassFlowRequest = this->PlantSourceMassFlowRateMax;
   10368              :             } else {
   10369            0 :                 assert(false);
   10370              :             }
   10371              :         }
   10372              : 
   10373              :         // next determine if tank temperature is such that source side flow might be requested
   10374            1 :         bool NeedsHeatOrCool = this->SourceHeatNeed(state, OutletTemp, DeadBandTemp, SetPointTemp_loc);
   10375              : 
   10376            1 :         if (MassFlowRequest > 0.0) {
   10377            1 :             if (WaterThermalTankSide == WaterHeaterSide::Use) {
   10378            0 :                 FlowResult = MassFlowRequest;
   10379            1 :             } else if (WaterThermalTankSide == WaterHeaterSide::Source) {
   10380            1 :                 if (NeedsHeatOrCool) {
   10381            1 :                     FlowResult = MassFlowRequest;
   10382              :                 } else {
   10383            0 :                     FlowResult = 0.0;
   10384              :                 }
   10385              :             } else {
   10386            0 :                 assert(false);
   10387              :             }
   10388              :         } else {
   10389            0 :             FlowResult = 0.0;
   10390              :         }
   10391              : 
   10392              :         // now throttle against MassFlowRateMaxAvail, MassFlowRateMinAvail, MassFlowRateMax, and MassFlowRateMin
   10393              :         // see notes about reverse dd compliance (specifically 5ZoneWaterSystems file)
   10394            1 :         FlowResult = max(state.dataLoopNodes->Node(InNodeNum).MassFlowRateMinAvail, FlowResult); // okay for compliance (reverse dd)
   10395            1 :         FlowResult = max(state.dataLoopNodes->Node(InNodeNum).MassFlowRateMin, FlowResult);      // okay for compliance (reverse dd)
   10396            1 :         FlowResult = min(state.dataLoopNodes->Node(InNodeNum).MassFlowRateMaxAvail, FlowResult);
   10397              :         //=> following might take out of reverse dd compliance
   10398            1 :         FlowResult = min(state.dataLoopNodes->Node(InNodeNum).MassFlowRateMax, FlowResult);
   10399              : 
   10400            1 :         break;
   10401              :     }
   10402            2 :     case FlowMode::MaybeRequestingFlow: {
   10403              : 
   10404              :         // first determine what mass flow would be if it is to requested
   10405            2 :         Real64 MassFlowRequest = 0.0;
   10406            2 :         if (!ScheduledAvail) {
   10407            0 :             MassFlowRequest = 0.0;
   10408              :         } else {
   10409            2 :             if (WaterThermalTankSide == WaterHeaterSide::Use) {
   10410            0 :                 if ((this->IsChilledWaterTank) && (this->UseSideLoadRequested > 0.0)) {
   10411            0 :                     MassFlowRequest = this->PlantUseMassFlowRateMax;
   10412            0 :                 } else if ((this->IsChilledWaterTank) && (this->UseSideLoadRequested == 0.0)) {
   10413            0 :                     MassFlowRequest = 0.0;
   10414              :                 } else {
   10415            0 :                     MassFlowRequest = this->PlantUseMassFlowRateMax;
   10416              :                 }
   10417              : 
   10418            2 :             } else if (WaterThermalTankSide == WaterHeaterSide::Source) {
   10419            2 :                 MassFlowRequest = this->PlantSourceMassFlowRateMax;
   10420              :             }
   10421              :         }
   10422              : 
   10423            2 :         if (WaterThermalTankSide == WaterHeaterSide::Source) { // temperature dependent controls for indirect heating/cooling
   10424            2 :             bool NeedsHeatOrCool = this->SourceHeatNeed(state, OutletTemp, DeadBandTemp, SetPointTemp_loc);
   10425            2 :             if (MassFlowRequest > 0.0) {
   10426            2 :                 if (NeedsHeatOrCool) {
   10427            2 :                     FlowResult = MassFlowRequest;
   10428              :                 } else {
   10429            0 :                     FlowResult = 0.0;
   10430              :                 }
   10431              :             } else {
   10432            0 :                 FlowResult = 0.0;
   10433              :             }
   10434              :         } else { // end source side, begin use side
   10435            0 :             if (MassFlowRequest > 0.0) {
   10436            0 :                 FlowResult = MassFlowRequest;
   10437              :             } else {
   10438            0 :                 FlowResult = 0.0;
   10439              :             }
   10440              :         }
   10441            2 :         break;
   10442              :     }
   10443            0 :     default:
   10444            0 :         break;
   10445              :     }
   10446              : 
   10447           17 :     if (FlowResult < HVAC::VerySmallMassFlow) FlowResult = 0.0; // Catch underflow problems
   10448              : 
   10449           17 :     return FlowResult;
   10450              : }
   10451              : 
   10452            1 : void WaterThermalTankData::MinePlantStructForInfo(EnergyPlusData &state)
   10453              : {
   10454              : 
   10455              :     // SUBROUTINE INFORMATION:
   10456              :     //       AUTHOR         Brent Griffith
   10457              :     //       DATE WRITTEN   October 2007
   10458              :     //       MODIFIED       na
   10459              :     //       RE-ENGINEERED  na
   10460              : 
   10461              :     // PURPOSE OF THIS SUBROUTINE:
   10462              :     // get information from plant loop data structure
   10463              :     // check what we can learn from plant structure against user inputs
   10464              : 
   10465            1 :     bool ErrorsFound = false;
   10466              : 
   10467            1 :     if (allocated(state.dataPlnt->PlantLoop) && this->UseSidePlantLoc.loopNum > 0) {
   10468              : 
   10469              :         // check plant structure for useful data.
   10470              : 
   10471            0 :         int PlantLoopNum = this->UseSidePlantLoc.loopNum;
   10472            0 :         DataPlant::LoopSideLocation LoopSideNum = this->UseSidePlantLoc.loopSideNum;
   10473              : 
   10474            0 :         if ((this->UseDesignVolFlowRateWasAutoSized) && (this->UseSidePlantSizNum == 0)) {
   10475            0 :             ShowSevereError(state,
   10476            0 :                             format("Water heater = {} for autosizing Use side flow rate, did not find Sizing:Plant object {}",
   10477            0 :                                    this->Name,
   10478            0 :                                    state.dataPlnt->PlantLoop(PlantLoopNum).Name));
   10479            0 :             ErrorsFound = true;
   10480              :         }
   10481              :         // Is this wh Use side plumbed in series (default) or are there other branches in parallel?
   10482            0 :         if (state.dataPlnt->PlantLoop(PlantLoopNum).LoopSide(LoopSideNum).Splitter.Exists) {
   10483            0 :             if (any_eq(state.dataPlnt->PlantLoop(PlantLoopNum).LoopSide(LoopSideNum).Splitter.NodeNumOut,
   10484            0 :                        this->UseInletNode)) { // this wh is on the splitter
   10485            0 :                 if (state.dataPlnt->PlantLoop(PlantLoopNum).LoopSide(LoopSideNum).Splitter.TotalOutletNodes > 1) {
   10486            0 :                     this->UseSideSeries = false;
   10487              :                 }
   10488              :             }
   10489              :         }
   10490              :     }
   10491              : 
   10492            1 :     if (allocated(state.dataPlnt->PlantLoop) && this->SrcSidePlantLoc.loopNum > 0) {
   10493              :         // was user's input correct for plant loop name?
   10494            1 :         if ((this->SourceDesignVolFlowRateWasAutoSized) && (this->SourceSidePlantSizNum == 0) && (this->DesuperheaterNum == 0) &&
   10495            0 :             (this->HeatPumpNum == 0)) {
   10496            0 :             ShowSevereError(state,
   10497            0 :                             format("Water heater = {}for autosizing Source side flow rate, did not find Sizing:Plant object {}",
   10498            0 :                                    this->Name,
   10499            0 :                                    state.dataPlnt->PlantLoop(this->SrcSidePlantLoc.loopNum).Name));
   10500            0 :             ErrorsFound = true;
   10501              :         }
   10502              :         // Is this wh Source side plumbed in series (default) or are there other branches in parallel?
   10503            1 :         if (state.dataPlnt->PlantLoop(this->SrcSidePlantLoc.loopNum).LoopSide(this->SrcSidePlantLoc.loopSideNum).Splitter.Exists) {
   10504            0 :             if (any_eq(state.dataPlnt->PlantLoop(this->SrcSidePlantLoc.loopNum).LoopSide(this->SrcSidePlantLoc.loopSideNum).Splitter.NodeNumOut,
   10505            0 :                        this->SourceInletNode)) { // this wh is on the splitter
   10506            0 :                 if (state.dataPlnt->PlantLoop(this->SrcSidePlantLoc.loopNum).LoopSide(this->SrcSidePlantLoc.loopSideNum).Splitter.TotalOutletNodes >
   10507              :                     1) {
   10508            0 :                     this->SourceSideSeries = false;
   10509              :                 }
   10510              :             }
   10511              :         }
   10512              :     }
   10513              : 
   10514            1 :     if (ErrorsFound) {
   10515            0 :         ShowFatalError(state, "Preceding water heater input errors cause program termination");
   10516              :     }
   10517            1 : }
   10518              : 
   10519            1 : void WaterThermalTankData::SizeSupplySidePlantConnections(EnergyPlusData &state, const int loopNum)
   10520              : {
   10521              : 
   10522              :     // SUBROUTINE INFORMATION:
   10523              :     //       AUTHOR         Brent Griffith
   10524              :     //       DATE WRITTEN   October 2007
   10525              :     //       MODIFIED       na
   10526              :     //       RE-ENGINEERED  na
   10527              : 
   10528              :     // PURPOSE OF THIS SUBROUTINE:
   10529              :     // This subroutine is for sizing water heater plant connection flow rates
   10530              :     // on the supply that have not been specified in the input.
   10531              : 
   10532              :     // METHODOLOGY EMPLOYED:
   10533              :     // This routine is called later in the simulation than the sizing routine for the demand side
   10534              :     //  because the simulation needs to be further along before the needed data are available.
   10535              :     // For water heaters sides on Supply LoopSide, obtains hot water flow rate from the plant sizing array
   10536              :     //  (adapted approach from boiler sizing routines)
   10537              : 
   10538              :     static constexpr std::string_view RoutineName("SizeSupplySidePlantConnections");
   10539              : 
   10540            1 :     auto &PlantSizData = state.dataSize->PlantSizData;
   10541              : 
   10542            1 :     Real64 tmpUseDesignVolFlowRate = this->UseDesignVolFlowRate;
   10543            1 :     Real64 tmpSourceDesignVolFlowRate = this->SourceDesignVolFlowRate;
   10544              : 
   10545            1 :     if ((this->UseInletNode > 0) && (loopNum == this->UseSidePlantLoc.loopNum)) {
   10546            0 :         if (this->UseDesignVolFlowRateWasAutoSized) {
   10547            0 :             int PltSizNum = this->UseSidePlantSizNum;
   10548            0 :             if (PltSizNum > 0) { // we have a Plant Sizing Object
   10549            0 :                 if (this->UseSidePlantLoc.loopSideNum == DataPlant::LoopSideLocation::Supply) {
   10550            0 :                     if (PlantSizData(PltSizNum).DesVolFlowRate >= HVAC::SmallWaterVolFlow) {
   10551            0 :                         if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
   10552            0 :                             this->UseDesignVolFlowRate = PlantSizData(PltSizNum).DesVolFlowRate;
   10553              :                         } else {
   10554            0 :                             tmpUseDesignVolFlowRate = PlantSizData(PltSizNum).DesVolFlowRate;
   10555              :                         }
   10556              :                     } else {
   10557            0 :                         if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
   10558            0 :                             this->UseDesignVolFlowRate = 0.0;
   10559              :                         } else {
   10560            0 :                             tmpUseDesignVolFlowRate = 0.0;
   10561              :                         }
   10562              :                     }
   10563            0 :                     if (state.dataPlnt->PlantFinalSizesOkayToReport) {
   10564            0 :                         BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Use Side Design Flow Rate [m3/s]", this->UseDesignVolFlowRate);
   10565              :                     }
   10566            0 :                     if (state.dataPlnt->PlantFirstSizesOkayToReport) {
   10567            0 :                         BaseSizer::reportSizerOutput(
   10568              :                             state, this->Type, this->Name, "Initial Use Side Design Flow Rate [m3/s]", this->UseDesignVolFlowRate);
   10569              :                     }
   10570            0 :                     if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
   10571            0 :                         PlantUtilities::RegisterPlantCompDesignFlow(state, this->UseInletNode, this->UseDesignVolFlowRate);
   10572              :                     } else {
   10573            0 :                         PlantUtilities::RegisterPlantCompDesignFlow(state, this->UseInletNode, tmpUseDesignVolFlowRate);
   10574              :                     }
   10575              : 
   10576              :                     Real64 rho =
   10577            0 :                         state.dataPlnt->PlantLoop(this->UseSidePlantLoc.loopNum).glycol->getDensity(state, Constant::InitConvTemp, RoutineName);
   10578            0 :                     if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
   10579            0 :                         this->PlantUseMassFlowRateMax = this->UseDesignVolFlowRate * rho;
   10580              :                     } else {
   10581            0 :                         this->PlantUseMassFlowRateMax = tmpUseDesignVolFlowRate * rho;
   10582              :                     }
   10583              :                 }
   10584              :             } else {
   10585              :                 // do nothing
   10586              :             } // plant sizing object
   10587              :         } else {
   10588            0 :             PlantUtilities::RegisterPlantCompDesignFlow(state, this->UseInletNode, this->UseDesignVolFlowRate);
   10589              :             Real64 rho;
   10590            0 :             if (this->UseSidePlantLoc.loopNum > 0) {
   10591            0 :                 rho = state.dataPlnt->PlantLoop(this->UseSidePlantLoc.loopNum).glycol->getDensity(state, Constant::InitConvTemp, RoutineName);
   10592              :             } else {
   10593            0 :                 rho = this->water->getDensity(state, Constant::InitConvTemp, RoutineName);
   10594              :             }
   10595              : 
   10596            0 :             this->PlantUseMassFlowRateMax = this->UseDesignVolFlowRate * rho;
   10597              : 
   10598              :         } // autosizing needed.
   10599              :     }     // connected to plant
   10600              : 
   10601            1 :     if ((this->SourceInletNode > 0) && (loopNum == this->SrcSidePlantLoc.loopNum)) {
   10602            1 :         if (this->SourceDesignVolFlowRateWasAutoSized) {
   10603            0 :             int PltSizNum = this->SourceSidePlantSizNum;
   10604            0 :             if (PltSizNum > 0) {
   10605            0 :                 if (this->SrcSidePlantLoc.loopSideNum == DataPlant::LoopSideLocation::Supply) {
   10606            0 :                     if (PlantSizData(PltSizNum).DesVolFlowRate >= HVAC::SmallWaterVolFlow) {
   10607            0 :                         if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
   10608            0 :                             this->SourceDesignVolFlowRate = PlantSizData(PltSizNum).DesVolFlowRate;
   10609              :                         } else {
   10610            0 :                             tmpSourceDesignVolFlowRate = PlantSizData(PltSizNum).DesVolFlowRate;
   10611              :                         }
   10612              :                     } else {
   10613            0 :                         if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
   10614            0 :                             this->SourceDesignVolFlowRate = 0.0;
   10615              :                         } else {
   10616            0 :                             tmpSourceDesignVolFlowRate = 0.0;
   10617              :                         }
   10618              :                     }
   10619            0 :                     if (state.dataPlnt->PlantFinalSizesOkayToReport) {
   10620            0 :                         BaseSizer::reportSizerOutput(
   10621              :                             state, this->Type, this->Name, "Source Side Design Flow Rate [m3/s]", this->SourceDesignVolFlowRate);
   10622              :                     }
   10623            0 :                     if (state.dataPlnt->PlantFirstSizesOkayToReport) {
   10624            0 :                         BaseSizer::reportSizerOutput(
   10625              :                             state, this->Type, this->Name, "Initial Source Side Design Flow Rate [m3/s]", this->SourceDesignVolFlowRate);
   10626              :                     }
   10627            0 :                     if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
   10628            0 :                         PlantUtilities::RegisterPlantCompDesignFlow(state, this->SourceInletNode, this->SourceDesignVolFlowRate);
   10629              :                     } else {
   10630            0 :                         PlantUtilities::RegisterPlantCompDesignFlow(state, this->SourceInletNode, tmpSourceDesignVolFlowRate);
   10631              :                     }
   10632              :                     Real64 rho =
   10633            0 :                         state.dataPlnt->PlantLoop(this->SrcSidePlantLoc.loopNum).glycol->getDensity(state, Constant::InitConvTemp, RoutineName);
   10634            0 :                     if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
   10635            0 :                         this->PlantSourceMassFlowRateMax = this->SourceDesignVolFlowRate * rho;
   10636              :                     } else {
   10637            0 :                         this->PlantSourceMassFlowRateMax = tmpSourceDesignVolFlowRate * rho;
   10638              :                     }
   10639              :                 } // plant loop allocation
   10640              :             } else {
   10641              :                 // do nothing
   10642              :             } // plant sizing object
   10643              :         } else {
   10644            1 :             if (this->SrcSidePlantLoc.loopSideNum == DataPlant::LoopSideLocation::Supply) {
   10645            1 :                 PlantUtilities::RegisterPlantCompDesignFlow(state, this->SourceInletNode, this->SourceDesignVolFlowRate);
   10646              :                 Real64 rho;
   10647            1 :                 if (this->SrcSidePlantLoc.loopNum > 0) {
   10648            1 :                     rho = state.dataPlnt->PlantLoop(this->SrcSidePlantLoc.loopNum).glycol->getDensity(state, Constant::InitConvTemp, RoutineName);
   10649              :                 } else {
   10650            0 :                     rho = this->water->getDensity(state, Constant::InitConvTemp, RoutineName);
   10651              :                 }
   10652            1 :                 this->PlantSourceMassFlowRateMax = this->SourceDesignVolFlowRate * rho;
   10653              :             }
   10654              :         } // autosizing needed.
   10655              :     }     // connected to plant
   10656            1 : }
   10657              : 
   10658            1 : void WaterThermalTankData::SizeTankForDemandSide(EnergyPlusData &state)
   10659              : {
   10660              : 
   10661              :     // SUBROUTINE INFORMATION:
   10662              :     //       AUTHOR         Brent Griffith
   10663              :     //       DATE WRITTEN   February 2008
   10664              :     //       MODIFIED       na
   10665              :     //       RE-ENGINEERED  na
   10666              : 
   10667              :     // PURPOSE OF THIS SUBROUTINE:
   10668              :     // This subroutine is for sizing water heater tank volume and heater
   10669              :     //  as best we can at this point in simulation. (prior to demand side
   10670              :     //  sizing that needs volume).
   10671              : 
   10672              :     // METHODOLOGY EMPLOYED:
   10673              :     //  depending on the sizing design mode...
   10674              : 
   10675              :     // REFERENCES:
   10676              :     // BA benchmark report for residential design mode
   10677              : 
   10678              :     // SUBROUTINE PARAMETER DEFINITIONS:
   10679              :     static constexpr std::string_view RoutineName("SizeTankForDemandSide");
   10680            1 :     Real64 constexpr GalTocubicMeters(0.0037854);
   10681            1 :     Real64 constexpr kBtuPerHrToWatts(293.1);
   10682              : 
   10683            1 :     Real64 Tstart = 14.44;
   10684            1 :     Real64 Tfinish = 57.22;
   10685              : 
   10686            1 :     Real64 tmpTankVolume = this->Volume;
   10687            1 :     Real64 tmpMaxCapacity = this->MaxCapacity;
   10688              : 
   10689            1 :     switch (this->Sizing.DesignMode) {
   10690              : 
   10691            0 :     case SizingMode::Invalid:
   10692              :     case SizingMode::PeakDraw: {
   10693              : 
   10694            0 :         break;
   10695              :     }
   10696            0 :     case SizingMode::ResidentialMin: {
   10697              : 
   10698              :         // assume can propagate rules for gas to other fuels.
   10699            0 :         bool FuelTypeIsLikeGas = false;
   10700            0 :         switch (this->FuelType) {
   10701            0 :         case Constant::eFuel::NaturalGas:
   10702              :         case Constant::eFuel::Diesel:
   10703              :         case Constant::eFuel::Gasoline:
   10704              :         case Constant::eFuel::Coal:
   10705              :         case Constant::eFuel::FuelOilNo1:
   10706              :         case Constant::eFuel::FuelOilNo2:
   10707              :         case Constant::eFuel::Propane:
   10708              :         case Constant::eFuel::OtherFuel1:
   10709              :         case Constant::eFuel::OtherFuel2:
   10710              :         case Constant::eFuel::DistrictHeatingWater:
   10711              :         case Constant::eFuel::DistrictHeatingSteam:
   10712            0 :             FuelTypeIsLikeGas = true;
   10713            0 :             break;
   10714            0 :         default: // FuelTypeIsLikeGas stays false
   10715            0 :             break;
   10716              :         }
   10717              : 
   10718            0 :         if (this->Sizing.NumberOfBedrooms == 1) {
   10719            0 :             if (this->FuelType == Constant::eFuel::Electricity) {
   10720            0 :                 if (this->VolumeWasAutoSized) tmpTankVolume = 20.0 * GalTocubicMeters;
   10721            0 :                 if (this->MaxCapacityWasAutoSized) tmpMaxCapacity = 2.5 * 1000.0; // 2.5 kW
   10722            0 :             } else if (FuelTypeIsLikeGas) {
   10723            0 :                 if (this->VolumeWasAutoSized) tmpTankVolume = 20.0 * GalTocubicMeters;
   10724            0 :                 if (this->MaxCapacityWasAutoSized) tmpMaxCapacity = 27.0 * kBtuPerHrToWatts; // 27kBtu/hr
   10725              :             }
   10726              : 
   10727            0 :         } else if (this->Sizing.NumberOfBedrooms == 2) {
   10728            0 :             if (this->Sizing.NumberOfBathrooms <= 1.5) {
   10729            0 :                 if (this->FuelType == Constant::eFuel::Electricity) {
   10730            0 :                     if (this->VolumeWasAutoSized) tmpTankVolume = 30.0 * GalTocubicMeters;
   10731            0 :                     if (this->MaxCapacityWasAutoSized) tmpMaxCapacity = 3.5 * 1000.0; // 3.5 kW
   10732            0 :                 } else if (FuelTypeIsLikeGas) {
   10733            0 :                     if (this->VolumeWasAutoSized) tmpTankVolume = 30.0 * GalTocubicMeters;
   10734            0 :                     if (this->MaxCapacityWasAutoSized) tmpMaxCapacity = 36.0 * kBtuPerHrToWatts; // 36 kBtu/hr
   10735              :                 }
   10736            0 :             } else if ((this->Sizing.NumberOfBathrooms > 1.5) && (this->Sizing.NumberOfBathrooms < 3.0)) {
   10737            0 :                 if (this->FuelType == Constant::eFuel::Electricity) {
   10738            0 :                     if (this->VolumeWasAutoSized) tmpTankVolume = 40.0 * GalTocubicMeters;
   10739            0 :                     if (this->MaxCapacityWasAutoSized) tmpMaxCapacity = 4.5 * 1000.0; // 4.5 kW
   10740            0 :                 } else if (FuelTypeIsLikeGas) {
   10741            0 :                     if (this->VolumeWasAutoSized) tmpTankVolume = 30.0 * GalTocubicMeters;
   10742            0 :                     if (this->MaxCapacityWasAutoSized) tmpMaxCapacity = 36.0 * kBtuPerHrToWatts; // 36 kBtu/hr
   10743              :                 }
   10744            0 :             } else if (this->Sizing.NumberOfBathrooms >= 3.0) {
   10745            0 :                 if (this->FuelType == Constant::eFuel::Electricity) {
   10746            0 :                     if (this->VolumeWasAutoSized) tmpTankVolume = 50.0 * GalTocubicMeters;
   10747            0 :                     if (this->MaxCapacityWasAutoSized) tmpMaxCapacity = 5.5 * 1000.0; // 5.5 kW
   10748            0 :                 } else if (FuelTypeIsLikeGas) {
   10749            0 :                     if (this->VolumeWasAutoSized) tmpTankVolume = 40.0 * GalTocubicMeters;
   10750            0 :                     if (this->MaxCapacityWasAutoSized) tmpMaxCapacity = 36.0 * kBtuPerHrToWatts; // 36 kBtu/hr
   10751              :                 }
   10752              :             }
   10753            0 :         } else if (this->Sizing.NumberOfBedrooms == 3) {
   10754            0 :             if (this->Sizing.NumberOfBathrooms <= 1.5) {
   10755            0 :                 if (this->FuelType == Constant::eFuel::Electricity) {
   10756            0 :                     if (this->VolumeWasAutoSized) tmpTankVolume = 40.0 * GalTocubicMeters;
   10757            0 :                     if (this->MaxCapacityWasAutoSized) tmpMaxCapacity = 4.5 * 1000.0; // 4.5 kW
   10758            0 :                 } else if (FuelTypeIsLikeGas) {
   10759            0 :                     if (this->VolumeWasAutoSized) tmpTankVolume = 30.0 * GalTocubicMeters;
   10760            0 :                     if (this->MaxCapacityWasAutoSized) tmpMaxCapacity = 36.0 * kBtuPerHrToWatts; // 36 kBtu/hr
   10761              :                 }
   10762            0 :             } else if ((this->Sizing.NumberOfBathrooms > 1.5) && (this->Sizing.NumberOfBathrooms < 3.0)) {
   10763            0 :                 if (this->FuelType == Constant::eFuel::Electricity) {
   10764            0 :                     if (this->VolumeWasAutoSized) tmpTankVolume = 50.0 * GalTocubicMeters;
   10765            0 :                     if (this->MaxCapacityWasAutoSized) tmpMaxCapacity = 5.5 * 1000.0; // 5.5 kW
   10766            0 :                 } else if (FuelTypeIsLikeGas) {
   10767            0 :                     if (this->VolumeWasAutoSized) tmpTankVolume = 40.0 * GalTocubicMeters;
   10768            0 :                     if (this->MaxCapacityWasAutoSized) tmpMaxCapacity = 36.0 * kBtuPerHrToWatts; // 36 kBtu/hr
   10769              :                 }
   10770            0 :             } else if (this->Sizing.NumberOfBathrooms >= 3.0) {
   10771            0 :                 if (this->FuelType == Constant::eFuel::Electricity) {
   10772            0 :                     if (this->VolumeWasAutoSized) tmpTankVolume = 50.0 * GalTocubicMeters;
   10773            0 :                     if (this->MaxCapacityWasAutoSized) tmpMaxCapacity = 5.5 * 1000.0; // 5.5 kW
   10774            0 :                 } else if (FuelTypeIsLikeGas) {
   10775            0 :                     if (this->VolumeWasAutoSized) tmpTankVolume = 40.0 * GalTocubicMeters;
   10776            0 :                     if (this->MaxCapacityWasAutoSized) tmpMaxCapacity = 38.0 * kBtuPerHrToWatts; // 38 kBtu/hr
   10777              :                 }
   10778              :             }
   10779            0 :         } else if (this->Sizing.NumberOfBedrooms == 4) {
   10780            0 :             if (this->Sizing.NumberOfBathrooms <= 1.5) {
   10781            0 :                 if (this->FuelType == Constant::eFuel::Electricity) {
   10782            0 :                     if (this->VolumeWasAutoSized) tmpTankVolume = 50.0 * GalTocubicMeters;
   10783            0 :                     if (this->MaxCapacityWasAutoSized) tmpMaxCapacity = 5.5 * 1000.0; // 5.5 kW
   10784            0 :                 } else if (FuelTypeIsLikeGas) {
   10785            0 :                     if (this->VolumeWasAutoSized) tmpTankVolume = 40.0 * GalTocubicMeters;
   10786            0 :                     if (this->MaxCapacityWasAutoSized) tmpMaxCapacity = 36.0 * kBtuPerHrToWatts; // 36 kBtu/hr
   10787              :                 }
   10788            0 :             } else if ((this->Sizing.NumberOfBathrooms > 1.5) && (this->Sizing.NumberOfBathrooms < 3.0)) {
   10789            0 :                 if (this->FuelType == Constant::eFuel::Electricity) {
   10790            0 :                     if (this->VolumeWasAutoSized) tmpTankVolume = 50.0 * GalTocubicMeters;
   10791            0 :                     if (this->MaxCapacityWasAutoSized) tmpMaxCapacity = 5.5 * 1000.0; // 5.5 kW
   10792            0 :                 } else if (FuelTypeIsLikeGas) {
   10793            0 :                     if (this->VolumeWasAutoSized) tmpTankVolume = 40.0 * GalTocubicMeters;
   10794            0 :                     if (this->MaxCapacityWasAutoSized) tmpMaxCapacity = 38.0 * kBtuPerHrToWatts; // 38 kBtu/hr
   10795              :                 }
   10796            0 :             } else if (this->Sizing.NumberOfBathrooms >= 3.0) {
   10797            0 :                 if (this->FuelType == Constant::eFuel::Electricity) {
   10798            0 :                     if (this->VolumeWasAutoSized) tmpTankVolume = 66.0 * GalTocubicMeters;
   10799            0 :                     if (this->MaxCapacityWasAutoSized) tmpMaxCapacity = 5.5 * 1000.0; // 5.5 kW
   10800            0 :                 } else if (FuelTypeIsLikeGas) {
   10801            0 :                     if (this->VolumeWasAutoSized) tmpTankVolume = 50.0 * GalTocubicMeters;
   10802            0 :                     if (this->MaxCapacityWasAutoSized) tmpMaxCapacity = 38.0 * kBtuPerHrToWatts; // 38 kBtu/hr
   10803              :                 }
   10804              :             }
   10805            0 :         } else if (this->Sizing.NumberOfBedrooms == 5) {
   10806            0 :             if (this->FuelType == Constant::eFuel::Electricity) {
   10807            0 :                 if (this->VolumeWasAutoSized) tmpTankVolume = 66.0 * GalTocubicMeters;
   10808            0 :                 if (this->MaxCapacityWasAutoSized) tmpMaxCapacity = 5.5 * 1000.0; // 5.5 kW
   10809            0 :             } else if (FuelTypeIsLikeGas) {
   10810            0 :                 if (this->VolumeWasAutoSized) tmpTankVolume = 50.0 * GalTocubicMeters;
   10811            0 :                 if (this->MaxCapacityWasAutoSized) tmpMaxCapacity = 47.0 * kBtuPerHrToWatts; // 47 kBtu/hr
   10812              :             }
   10813            0 :         } else if (this->Sizing.NumberOfBedrooms >= 6) {
   10814            0 :             if (this->FuelType == Constant::eFuel::Electricity) {
   10815            0 :                 if (this->VolumeWasAutoSized) tmpTankVolume = 66.0 * GalTocubicMeters;
   10816            0 :                 if (this->MaxCapacityWasAutoSized) tmpMaxCapacity = 5.5 * 1000.0; // 5.5 kW
   10817            0 :             } else if (FuelTypeIsLikeGas) {
   10818            0 :                 if (this->VolumeWasAutoSized) tmpTankVolume = 50.0 * GalTocubicMeters;
   10819            0 :                 if (this->MaxCapacityWasAutoSized) tmpMaxCapacity = 50.0 * kBtuPerHrToWatts; // 50 kBtu/hr
   10820              :             }
   10821              :         }
   10822              : 
   10823            0 :         if (this->VolumeWasAutoSized && state.dataPlnt->PlantFirstSizesOkayToFinalize) {
   10824            0 :             this->Volume = tmpTankVolume;
   10825            0 :             if (state.dataPlnt->PlantFinalSizesOkayToReport) {
   10826            0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Tank Volume [m3]", this->Volume);
   10827              :             }
   10828            0 :             if (state.dataPlnt->PlantFirstSizesOkayToReport) {
   10829            0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Initial Tank Volume [m3]", this->Volume);
   10830              :             }
   10831              :         }
   10832            0 :         if (this->MaxCapacityWasAutoSized && state.dataPlnt->PlantFirstSizesOkayToFinalize) {
   10833            0 :             this->MaxCapacity = tmpMaxCapacity;
   10834            0 :             if (state.dataPlnt->PlantFinalSizesOkayToReport) {
   10835            0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Maximum Heater Capacity [W]", this->MaxCapacity);
   10836              :             }
   10837            0 :             if (state.dataPlnt->PlantFirstSizesOkayToReport) {
   10838            0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Initial Maximum Heater Capacity [W]", this->MaxCapacity);
   10839              :             }
   10840              :         }
   10841            0 :         break;
   10842              :     }
   10843            0 :     case SizingMode::PerPerson: {
   10844              :         // how to get number of people?
   10845              : 
   10846              :         // MJW TODO: this won't compile now: Real64 SumPeopleAllZones = sum(state.dataHeatBal->Zone, &DataHeatBalance::ZoneData::TotOccupants);
   10847            0 :         Real64 SumPeopleAllZones = 0.0;
   10848            0 :         for (auto const &thisZone : state.dataHeatBal->Zone) {
   10849            0 :             SumPeopleAllZones += thisZone.TotOccupants;
   10850              :         }
   10851            0 :         if (this->VolumeWasAutoSized) tmpTankVolume = this->Sizing.TankCapacityPerPerson * SumPeopleAllZones;
   10852              : 
   10853            0 :         if (this->MaxCapacityWasAutoSized) {
   10854              :             Real64 rho;
   10855              :             Real64 Cp;
   10856            0 :             if (this->UseSidePlantLoc.loopNum > 0) {
   10857            0 :                 rho = state.dataPlnt->PlantLoop(this->UseSidePlantLoc.loopNum).glycol->getDensity(state, ((Tfinish + Tstart) / 2.0), RoutineName);
   10858            0 :                 Cp = state.dataPlnt->PlantLoop(this->UseSidePlantLoc.loopNum).glycol->getSpecificHeat(state, ((Tfinish + Tstart) / 2.0), RoutineName);
   10859              :             } else {
   10860            0 :                 rho = this->water->getDensity(state, ((Tfinish + Tstart) / 2.0), RoutineName);
   10861            0 :                 Cp = this->water->getSpecificHeat(state, ((Tfinish + Tstart) / 2.0), RoutineName);
   10862              :             }
   10863              : 
   10864            0 :             tmpMaxCapacity = SumPeopleAllZones * this->Sizing.RecoveryCapacityPerPerson * (Tfinish - Tstart) * (1.0 / Constant::rSecsInHour) * rho *
   10865              :                              Cp; // m3/hr/person | delta T  in K | 1 hr/ 3600 s | kg/m3 | J/Kg/k
   10866              :         }
   10867              : 
   10868            0 :         if (this->VolumeWasAutoSized && state.dataPlnt->PlantFirstSizesOkayToFinalize) {
   10869            0 :             this->Volume = tmpTankVolume;
   10870            0 :             if (state.dataPlnt->PlantFinalSizesOkayToReport) {
   10871            0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Tank Volume [m3]", this->Volume);
   10872              :             }
   10873            0 :             if (state.dataPlnt->PlantFirstSizesOkayToReport) {
   10874            0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Initial Tank Volume [m3]", this->Volume);
   10875              :             }
   10876              :         }
   10877            0 :         if (this->MaxCapacityWasAutoSized && state.dataPlnt->PlantFirstSizesOkayToFinalize) {
   10878            0 :             this->MaxCapacity = tmpMaxCapacity;
   10879            0 :             if (state.dataPlnt->PlantFinalSizesOkayToReport) {
   10880            0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Maximum Heater Capacity [W]", this->MaxCapacity);
   10881              :             }
   10882            0 :             if (state.dataPlnt->PlantFirstSizesOkayToReport) {
   10883            0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Initial Maximum Heater Capacity [W]", this->MaxCapacity);
   10884              :             }
   10885              :         }
   10886            0 :         break;
   10887              :     }
   10888            0 :     case SizingMode::PerFloorArea: {
   10889              : 
   10890              :         // MJW TODO: this won't compile now: Real64 SumFloorAreaAllZones = sum(state.dataHeatBal->Zone, &DataHeatBalance::ZoneData::FloorArea);
   10891            0 :         Real64 SumFloorAreaAllZones = 0.0;
   10892            0 :         for (auto const &thisZone : state.dataHeatBal->Zone) {
   10893            0 :             SumFloorAreaAllZones += thisZone.FloorArea;
   10894              :         }
   10895            0 :         if (this->VolumeWasAutoSized) tmpTankVolume = this->Sizing.TankCapacityPerArea * SumFloorAreaAllZones;
   10896            0 :         if (this->MaxCapacityWasAutoSized) {
   10897              :             Real64 rho;
   10898              :             Real64 Cp;
   10899            0 :             if (this->UseSidePlantLoc.loopNum > 0) {
   10900            0 :                 rho = state.dataPlnt->PlantLoop(this->UseSidePlantLoc.loopNum).glycol->getDensity(state, ((Tfinish + Tstart) / 2.0), RoutineName);
   10901            0 :                 Cp = state.dataPlnt->PlantLoop(this->UseSidePlantLoc.loopNum).glycol->getSpecificHeat(state, ((Tfinish + Tstart) / 2.0), RoutineName);
   10902              :             } else {
   10903            0 :                 rho = this->water->getDensity(state, ((Tfinish + Tstart) / 2.0), RoutineName);
   10904            0 :                 Cp = this->water->getSpecificHeat(state, ((Tfinish + Tstart) / 2.0), RoutineName);
   10905              :             }
   10906            0 :             tmpMaxCapacity = SumFloorAreaAllZones * this->Sizing.RecoveryCapacityPerArea * (Tfinish - Tstart) * (1.0 / Constant::rSecsInHour) * rho *
   10907              :                              Cp; // m2 | m3/hr/m2 | delta T  in K | 1 hr/ 3600 s | kg/m3 | J/Kg/k
   10908              :         }
   10909            0 :         if (this->VolumeWasAutoSized && state.dataPlnt->PlantFirstSizesOkayToFinalize) {
   10910            0 :             this->Volume = tmpTankVolume;
   10911            0 :             if (state.dataPlnt->PlantFinalSizesOkayToReport) {
   10912            0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Tank Volume [m3]", this->Volume);
   10913              :             }
   10914            0 :             if (state.dataPlnt->PlantFirstSizesOkayToReport) {
   10915            0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Initial Tank Volume [m3]", this->Volume);
   10916              :             }
   10917              :         }
   10918            0 :         if (this->MaxCapacityWasAutoSized && state.dataPlnt->PlantFirstSizesOkayToFinalize) {
   10919            0 :             this->MaxCapacity = tmpMaxCapacity;
   10920            0 :             if (state.dataPlnt->PlantFinalSizesOkayToReport) {
   10921            0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Maximum Heater Capacity [W]", this->MaxCapacity);
   10922              :             }
   10923            0 :             if (state.dataPlnt->PlantFirstSizesOkayToReport) {
   10924            0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Initial Maximum Heater Capacity [W]", this->MaxCapacity);
   10925              :             }
   10926              :         }
   10927            0 :         break;
   10928              :     }
   10929            0 :     case SizingMode::PerUnit: {
   10930              : 
   10931            0 :         if (this->VolumeWasAutoSized) tmpTankVolume = this->Sizing.TankCapacityPerUnit * this->Sizing.NumberOfUnits;
   10932              : 
   10933            0 :         if (this->MaxCapacityWasAutoSized) {
   10934              :             Real64 rho;
   10935              :             Real64 Cp;
   10936            0 :             if (this->UseSidePlantLoc.loopNum > 0) {
   10937            0 :                 rho = state.dataPlnt->PlantLoop(this->UseSidePlantLoc.loopNum).glycol->getDensity(state, ((Tfinish + Tstart) / 2.0), RoutineName);
   10938            0 :                 Cp = state.dataPlnt->PlantLoop(this->UseSidePlantLoc.loopNum).glycol->getSpecificHeat(state, ((Tfinish + Tstart) / 2.0), RoutineName);
   10939              :             } else {
   10940            0 :                 rho = this->water->getDensity(state, ((Tfinish + Tstart) / 2.0), RoutineName);
   10941            0 :                 Cp = this->water->getSpecificHeat(state, ((Tfinish + Tstart) / 2.0), RoutineName);
   10942              :             }
   10943            0 :             tmpMaxCapacity = this->Sizing.NumberOfUnits * this->Sizing.RecoveryCapacityPerUnit * (Tfinish - Tstart) * (1.0 / Constant::rSecsInHour) *
   10944              :                              rho * Cp; // m3/hr/ea | delta T  in K | 1 hr/ 3600 s | kg/m3 | J/Kg/k
   10945              :         }
   10946              : 
   10947            0 :         if (this->VolumeWasAutoSized && state.dataPlnt->PlantFirstSizesOkayToFinalize) {
   10948            0 :             this->Volume = tmpTankVolume;
   10949            0 :             if (state.dataPlnt->PlantFinalSizesOkayToReport) {
   10950            0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Tank Volume [m3]", this->Volume);
   10951              :             }
   10952            0 :             if (state.dataPlnt->PlantFirstSizesOkayToReport) {
   10953            0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Initial Tank Volume [m3]", this->Volume);
   10954              :             }
   10955              :         }
   10956            0 :         if (this->MaxCapacityWasAutoSized && state.dataPlnt->PlantFirstSizesOkayToFinalize) {
   10957            0 :             this->MaxCapacity = tmpMaxCapacity;
   10958            0 :             if (state.dataPlnt->PlantFinalSizesOkayToReport) {
   10959            0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Maximum Heater Capacity [W]", this->MaxCapacity);
   10960              :             }
   10961            0 :             if (state.dataPlnt->PlantFirstSizesOkayToReport) {
   10962            0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Initial Maximum Heater Capacity [W]", this->MaxCapacity);
   10963              :             }
   10964              :         }
   10965            0 :         break;
   10966              :     }
   10967            1 :     case SizingMode::PerSolarColArea: {
   10968            1 :         break;
   10969              :     }
   10970            0 :     default:
   10971            0 :         break;
   10972              :     }
   10973              : 
   10974            1 :     if (this->MaxCapacityWasAutoSized) this->setBackupElementCapacity(state);
   10975              : 
   10976              :     // if stratified, might set height.
   10977            1 :     if ((this->VolumeWasAutoSized) && (this->WaterThermalTankType == DataPlant::PlantEquipmentType::WtrHeaterStratified) &&
   10978            0 :         state.dataPlnt->PlantFirstSizesOkayToFinalize) { // might set height
   10979            0 :         if ((this->HeightWasAutoSized) && (!this->VolumeWasAutoSized)) {
   10980            0 :             this->Height = std::pow((4.0 * this->Volume * pow_2(this->Sizing.HeightAspectRatio)) / Constant::Pi, 0.3333333333333333);
   10981            0 :             if (state.dataPlnt->PlantFinalSizesOkayToReport) {
   10982            0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Tank Height [m]", this->Height);
   10983              :             }
   10984            0 :             if (state.dataPlnt->PlantFirstSizesOkayToReport) {
   10985            0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Initial Tank Height [m]", this->Height);
   10986              :             }
   10987              :             // check if Constant::AutoCalculate() Use outlet and source inlet are still set to autosize by earlier
   10988            0 :             if (this->UseOutletHeightWasAutoSized) {
   10989            0 :                 this->UseOutletHeight = this->Height;
   10990              :             }
   10991            0 :             if (this->SourceInletHeightWasAutoSized) {
   10992            0 :                 this->SourceInletHeight = this->Height;
   10993              :             }
   10994              :         }
   10995              :     }
   10996            1 : }
   10997              : 
   10998            1 : void WaterThermalTankData::SizeTankForSupplySide(EnergyPlusData &state)
   10999              : {
   11000              : 
   11001              :     // SUBROUTINE INFORMATION:
   11002              :     //       AUTHOR         Brent Griffith
   11003              :     //       DATE WRITTEN   February 2008
   11004              :     //       MODIFIED       na
   11005              :     //       RE-ENGINEERED  na
   11006              : 
   11007              :     // PURPOSE OF THIS SUBROUTINE:
   11008              :     // This subroutine is for sizing water heater tank volume and heater
   11009              :     //   at a later point in the simulation when more of the plant is ready.
   11010              : 
   11011              :     // METHODOLOGY EMPLOYED:
   11012              :     //  depending on the sizing design mode...
   11013              : 
   11014              :     // REFERENCES:
   11015              :     // BA benchmark report for residential design mode
   11016              : 
   11017              :     static constexpr std::string_view RoutineName("SizeTankForSupplySide");
   11018              : 
   11019            1 :     Real64 tmpTankVolume = this->Volume;
   11020            1 :     Real64 tmpMaxCapacity = this->MaxCapacity;
   11021              : 
   11022            1 :     if (this->Sizing.DesignMode == SizingMode::PeakDraw) {
   11023            0 :         if (this->VolumeWasAutoSized)
   11024            0 :             tmpTankVolume = this->Sizing.TankDrawTime * this->UseDesignVolFlowRate * Constant::rSecsInHour; // hours | m3/s | (3600 s/1 hour)
   11025            0 :         if (this->VolumeWasAutoSized && state.dataPlnt->PlantFirstSizesOkayToFinalize) {
   11026            0 :             this->Volume = tmpTankVolume;
   11027            0 :             if (state.dataPlnt->PlantFinalSizesOkayToReport) {
   11028            0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Tank Volume [m3]", this->Volume);
   11029              :             }
   11030            0 :             if (state.dataPlnt->PlantFirstSizesOkayToReport) {
   11031            0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Initial Tank Volume [m3]", this->Volume);
   11032              :             }
   11033              :         }
   11034            0 :         if (this->MaxCapacityWasAutoSized) {
   11035            0 :             if (this->Sizing.RecoveryTime > 0.0) {
   11036            0 :                 Real64 rho = 0.0;
   11037            0 :                 Real64 Cp = 0.0;
   11038            0 :                 constexpr Real64 Tstart = 14.44;
   11039            0 :                 constexpr Real64 Tfinish = 57.22;
   11040              : 
   11041            0 :                 if (this->SrcSidePlantLoc.loopNum > 0) {
   11042            0 :                     rho = state.dataPlnt->PlantLoop(this->SrcSidePlantLoc.loopNum).glycol->getDensity(state, ((Tfinish + Tstart) / 2.0), RoutineName);
   11043            0 :                     Cp = state.dataPlnt->PlantLoop(this->SrcSidePlantLoc.loopNum)
   11044            0 :                              .glycol->getSpecificHeat(state, ((Tfinish + Tstart) / 2.0), RoutineName);
   11045              :                 } else {
   11046            0 :                     rho = this->water->getDensity(state, ((Tfinish + Tstart) / 2.0), RoutineName);
   11047            0 :                     Cp = this->water->getSpecificHeat(state, ((Tfinish + Tstart) / 2.0), RoutineName);
   11048              :                 }
   11049            0 :                 tmpMaxCapacity = (this->Volume * rho * Cp * (Tfinish - Tstart)) /
   11050            0 :                                  (this->Sizing.RecoveryTime * Constant::rSecsInHour); // m3 | kg/m3 | J/Kg/K | K | seconds
   11051              :             } else {
   11052            0 :                 ShowFatalError(
   11053            0 :                     state, format("{}: Tank=\"{}\", requested sizing for max capacity but entered Recovery Time is zero.", RoutineName, this->Name));
   11054              :             }
   11055              :         }
   11056              : 
   11057            0 :         if (this->MaxCapacityWasAutoSized && state.dataPlnt->PlantFirstSizesOkayToFinalize) {
   11058            0 :             this->MaxCapacity = tmpMaxCapacity;
   11059            0 :             if (state.dataPlnt->PlantFinalSizesOkayToReport) {
   11060            0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Maximum Heater Capacity [W]", this->MaxCapacity);
   11061              :             }
   11062            0 :             if (state.dataPlnt->PlantFirstSizesOkayToReport) {
   11063            0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Initial Maximum Heater Capacity [W]", this->MaxCapacity);
   11064              :             }
   11065              :         }
   11066            1 :     } else if (this->Sizing.DesignMode == SizingMode::PerSolarColArea) {
   11067              : 
   11068            1 :         this->Sizing.TotalSolarCollectorArea = 0.0;
   11069              : 
   11070            1 :         for (int CollectorNum = 1; CollectorNum <= state.dataSolarCollectors->NumOfCollectors; ++CollectorNum) {
   11071            0 :             auto const &collector = state.dataSolarCollectors->Collector(CollectorNum);
   11072            0 :             this->Sizing.TotalSolarCollectorArea += state.dataSurface->Surface(collector.Surface).Area;
   11073              :         }
   11074              : 
   11075            2 :         for (int CollectorNum = 1; CollectorNum <= state.dataPhotovoltaicThermalCollector->NumPVT; ++CollectorNum) {
   11076            1 :             auto const &collector = state.dataPhotovoltaicThermalCollector->PVT(CollectorNum);
   11077            1 :             this->Sizing.TotalSolarCollectorArea += collector.AreaCol;
   11078              :         }
   11079              : 
   11080            1 :         if (this->VolumeWasAutoSized) {
   11081            1 :             if (this->Sizing.TotalSolarCollectorArea > 0) {
   11082            1 :                 tmpTankVolume = this->Sizing.TotalSolarCollectorArea * this->Sizing.TankCapacityPerCollectorArea;
   11083              :             } else {
   11084            0 :                 ShowFatalError(state,
   11085            0 :                                format("{}: Tank=\"{}\", requested sizing for volume with PerSolarCollectorArea but total found "
   11086              :                                       "area of Collectors is zero.",
   11087              :                                       RoutineName,
   11088            0 :                                       this->Name));
   11089              :             }
   11090              :         }
   11091            1 :         if (this->MaxCapacityWasAutoSized) {
   11092            0 :             tmpMaxCapacity = 0.0;
   11093              :         }
   11094            1 :         if (this->VolumeWasAutoSized && state.dataPlnt->PlantFirstSizesOkayToFinalize) {
   11095            1 :             this->Volume = tmpTankVolume;
   11096            1 :             if (state.dataPlnt->PlantFinalSizesOkayToReport) {
   11097            1 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Tank Volume [m3]", this->Volume);
   11098              :             }
   11099            1 :             if (state.dataPlnt->PlantFirstSizesOkayToReport) {
   11100            0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Initial Tank Volume [m3]", this->Volume);
   11101              :             }
   11102              :         }
   11103            1 :         if (this->MaxCapacityWasAutoSized && state.dataPlnt->PlantFirstSizesOkayToFinalize) {
   11104            0 :             this->MaxCapacity = tmpMaxCapacity;
   11105            0 :             if (state.dataPlnt->PlantFinalSizesOkayToReport) {
   11106            0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Maximum Heater Capacity [W]", this->MaxCapacity);
   11107              :             }
   11108            0 :             if (state.dataPlnt->PlantFirstSizesOkayToReport) {
   11109            0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Initial Maximum Heater Capacity [W]", this->MaxCapacity);
   11110              :             }
   11111              :         }
   11112              :     }
   11113              : 
   11114            1 :     if (this->MaxCapacityWasAutoSized) {
   11115            0 :         this->setBackupElementCapacity(state);
   11116              :     }
   11117              : 
   11118            1 :     if ((this->VolumeWasAutoSized) && (this->WaterThermalTankType == DataPlant::PlantEquipmentType::WtrHeaterStratified) &&
   11119            0 :         state.dataPlnt->PlantFirstSizesOkayToFinalize) { // might set height
   11120            0 :         if ((this->HeightWasAutoSized) && (!this->VolumeWasAutoSized)) {
   11121            0 :             this->Height = std::pow((4.0 * this->Volume * pow_2(this->Sizing.HeightAspectRatio)) / Constant::Pi, 0.3333333333333333);
   11122            0 :             if (state.dataPlnt->PlantFinalSizesOkayToReport) {
   11123            0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Tank Height [m]", this->Height);
   11124              :             }
   11125            0 :             if (state.dataPlnt->PlantFirstSizesOkayToReport) {
   11126            0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Initial Tank Height [m]", this->Height);
   11127              :             }
   11128              :         }
   11129              :     }
   11130            1 : }
   11131              : 
   11132            1 : void WaterThermalTankData::SizeDemandSidePlantConnections(EnergyPlusData &state)
   11133              : {
   11134              : 
   11135              :     // SUBROUTINE INFORMATION:
   11136              :     //       AUTHOR         Brent Griffith
   11137              :     //       DATE WRITTEN   October 2007
   11138              :     //       MODIFIED       na
   11139              :     //       RE-ENGINEERED  na
   11140              : 
   11141              :     // PURPOSE OF THIS SUBROUTINE:
   11142              :     // This subroutine is for sizing water heater plant connection flow rates
   11143              :     // on the demand side that have not been specified in the input.
   11144              : 
   11145              :     // METHODOLOGY EMPLOYED:
   11146              :     // For water heater sides on the Demand side, hot water flow rates are modeled entirely from user input data
   11147              :     // because the plant loop is not yet set up nor is plant sizing info populated.
   11148              :     // sizing is done by calculating an initial
   11149              :     //  recovery rate that if continued would reheat tank in user specified amount of time.
   11150              :     //  initial and final tank temperatures are 14.44 and reheat to 57.22 (values from CalcStandardRatings routine)
   11151              : 
   11152              :     static constexpr std::string_view RoutineName("SizeDemandSidePlantConnections");
   11153              : 
   11154            1 :     auto &PlantSizData = state.dataSize->PlantSizData;
   11155              : 
   11156            1 :     Real64 tankRecoverhours = this->SizingRecoveryTime;
   11157            1 :     bool ErrorsFound = false;
   11158            1 :     Real64 tmpUseDesignVolFlowRate = this->UseDesignVolFlowRate;
   11159            1 :     Real64 tmpSourceDesignVolFlowRate = this->SourceDesignVolFlowRate;
   11160              : 
   11161              :     Real64 Tstart;
   11162              :     Real64 Tfinish;
   11163            1 :     if (!this->IsChilledWaterTank) {
   11164            1 :         Tstart = 14.44;
   11165            1 :         Tfinish = 57.22;
   11166              :     } else {
   11167            0 :         Tstart = 14.44;
   11168            0 :         Tfinish = 9.0;
   11169              :     }
   11170              : 
   11171              :     // determine tank volume to use for sizing.
   11172            1 :     Real64 TankVolume = this->Volume;
   11173            1 :     if (this->VolumeWasAutoSized) {
   11174            1 :         TankVolume = this->Sizing.NominalVolForSizingDemandSideFlow;
   11175              :     }
   11176              : 
   11177            1 :     if (this->UseInletNode > 0) {
   11178            0 :         if (this->UseDesignVolFlowRateWasAutoSized) {
   11179            0 :             int PltSizNum = this->UseSidePlantSizNum;
   11180            0 :             if (PltSizNum > 0) { // we have a Plant Sizing Object
   11181            0 :                 if (this->UseSidePlantLoc.loopSideNum == DataPlant::LoopSideLocation::Demand) {
   11182              :                     // probably shouldn't come here as Use side is unlikley to be on demand side (?)
   11183              :                     // but going to treat component with symetry so if connections are reversed it'll still work
   11184              :                     // choose a flow rate that will allow the entire volume of the tank to go from 14.44 to 57.22 C
   11185              :                     // in user specified hours.
   11186              :                     //  using the plant inlet design temp for sizing.
   11187            0 :                     Real64 Tpdesign = PlantSizData(PltSizNum).ExitTemp;
   11188            0 :                     Real64 eff = this->UseEffectiveness;
   11189            0 :                     if ((Tpdesign >= 58.0) && (!this->IsChilledWaterTank)) {
   11190            0 :                         if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
   11191            0 :                             this->UseDesignVolFlowRate = -1.0 * (TankVolume / (tankRecoverhours * Constant::rSecsInHour * eff)) *
   11192            0 :                                                          std::log((Tpdesign - Tfinish) / (Tpdesign - Tstart));
   11193              :                         } else {
   11194            0 :                             tmpUseDesignVolFlowRate = -1.0 * (TankVolume / (tankRecoverhours * Constant::rSecsInHour * eff)) *
   11195            0 :                                                       std::log((Tpdesign - Tfinish) / (Tpdesign - Tstart));
   11196              :                         }
   11197            0 :                     } else if ((Tpdesign <= 8.0) && (this->IsChilledWaterTank)) {
   11198            0 :                         if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
   11199            0 :                             this->UseDesignVolFlowRate = -1.0 * (TankVolume / (tankRecoverhours * Constant::rSecsInHour * eff)) *
   11200            0 :                                                          std::log((Tpdesign - Tfinish) / (Tpdesign - Tstart));
   11201              :                         } else {
   11202            0 :                             tmpUseDesignVolFlowRate = -1.0 * (TankVolume / (tankRecoverhours * Constant::rSecsInHour * eff)) *
   11203            0 :                                                       std::log((Tpdesign - Tfinish) / (Tpdesign - Tstart));
   11204              :                         }
   11205              :                     } else {
   11206            0 :                         if (!this->IsChilledWaterTank) {
   11207              :                             // plant sizing object design temperature is set too low throw warning.
   11208            0 :                             ShowSevereError(state,
   11209              :                                             "Autosizing of Use side water heater design flow rate requires Sizing:Plant object to have an exit "
   11210              :                                             "temperature >= 58C");
   11211            0 :                             ShowContinueError(state, format("Occurs for water heater object={}", this->Name));
   11212              :                         } else {
   11213              :                             // plant sizing object design temperature is set too hi throw warning.
   11214            0 :                             ShowSevereError(state,
   11215              :                                             "Autosizing of Use side chilled water tank design flow rate requires Sizing:Plant object to have an "
   11216              :                                             "exit temperature <= 8C");
   11217            0 :                             ShowContinueError(state, format("Occurs for chilled water storage tank object={}", this->Name));
   11218              :                         }
   11219            0 :                         ErrorsFound = true;
   11220              :                     }
   11221            0 :                     if (state.dataPlnt->PlantFinalSizesOkayToReport) {
   11222            0 :                         BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Use Side Design Flow Rate [m3/s]", this->UseDesignVolFlowRate);
   11223              :                     }
   11224            0 :                     if (state.dataPlnt->PlantFirstSizesOkayToReport) {
   11225            0 :                         BaseSizer::reportSizerOutput(
   11226              :                             state, this->Type, this->Name, "Initial Use Side Design Flow Rate [m3/s]", this->UseDesignVolFlowRate);
   11227              :                     }
   11228            0 :                     if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
   11229            0 :                         PlantUtilities::RegisterPlantCompDesignFlow(state, this->UseInletNode, this->UseDesignVolFlowRate);
   11230              :                     } else {
   11231            0 :                         PlantUtilities::RegisterPlantCompDesignFlow(state, this->UseInletNode, tmpUseDesignVolFlowRate);
   11232              :                     }
   11233              :                     Real64 rho =
   11234            0 :                         state.dataPlnt->PlantLoop(this->UseSidePlantLoc.loopNum).glycol->getDensity(state, Constant::InitConvTemp, RoutineName);
   11235            0 :                     if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
   11236            0 :                         this->PlantUseMassFlowRateMax = this->UseDesignVolFlowRate * rho;
   11237              :                     } else {
   11238            0 :                         this->PlantUseMassFlowRateMax = tmpUseDesignVolFlowRate * rho;
   11239              :                     }
   11240              :                 } // Demand side
   11241              :             } else {
   11242              :                 // do nothing
   11243              :             } // plant sizing object
   11244              : 
   11245              :         } else {
   11246              :             // not autosized - report flow to RegisterPlantCompDesignFlow for supply side component sizing
   11247            0 :             PlantUtilities::RegisterPlantCompDesignFlow(state, this->UseInletNode, this->UseDesignVolFlowRate);
   11248              :             Real64 rho;
   11249            0 :             if (this->UseSidePlantLoc.loopNum > 0) {
   11250            0 :                 rho = state.dataPlnt->PlantLoop(this->UseSidePlantLoc.loopNum).glycol->getDensity(state, Constant::InitConvTemp, RoutineName);
   11251              :             } else {
   11252            0 :                 rho = this->water->getDensity(state, Constant::InitConvTemp, RoutineName);
   11253              :             }
   11254            0 :             this->PlantUseMassFlowRateMax = this->UseDesignVolFlowRate * rho;
   11255              :         } // autosizing needed.
   11256              :     }     // connected to plant
   11257              : 
   11258            1 :     if (this->SourceInletNode > 0) {
   11259            1 :         if (this->SourceDesignVolFlowRateWasAutoSized) {
   11260            0 :             int PltSizNum = this->SourceSidePlantSizNum;
   11261            0 :             if (PltSizNum > 0) {
   11262            0 :                 if (this->SrcSidePlantLoc.loopSideNum == DataPlant::LoopSideLocation::Demand) {
   11263              :                     //  choose a flow rate that will allow the entire volume of the tank to go from 14.44 to 57.22 C
   11264              :                     // in user specified hours.
   11265              :                     //  using the plant inlet design temp for sizing.
   11266            0 :                     Real64 Tpdesign = PlantSizData(PltSizNum).ExitTemp;
   11267            0 :                     Real64 eff = this->SourceEffectiveness;
   11268            0 :                     if ((Tpdesign >= 58.0) && (!this->IsChilledWaterTank)) {
   11269              : 
   11270            0 :                         if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
   11271            0 :                             this->SourceDesignVolFlowRate = -1.0 * (TankVolume / (tankRecoverhours * Constant::rSecsInHour * eff)) *
   11272            0 :                                                             std::log((Tpdesign - Tfinish) / (Tpdesign - Tstart));
   11273              :                         } else {
   11274            0 :                             tmpSourceDesignVolFlowRate = -1.0 * (TankVolume / (tankRecoverhours * Constant::rSecsInHour * eff)) *
   11275            0 :                                                          std::log((Tpdesign - Tfinish) / (Tpdesign - Tstart));
   11276              :                         }
   11277            0 :                     } else if ((Tpdesign <= 8.0) && (this->IsChilledWaterTank)) {
   11278            0 :                         if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
   11279            0 :                             this->SourceDesignVolFlowRate = -1.0 * (TankVolume / (tankRecoverhours * Constant::rSecsInHour * eff)) *
   11280            0 :                                                             std::log((Tpdesign - Tfinish) / (Tpdesign - Tstart));
   11281              :                         } else {
   11282            0 :                             tmpSourceDesignVolFlowRate = -1.0 * (TankVolume / (tankRecoverhours * Constant::rSecsInHour * eff)) *
   11283            0 :                                                          std::log((Tpdesign - Tfinish) / (Tpdesign - Tstart));
   11284              :                         }
   11285              :                     } else {
   11286            0 :                         if (!this->IsChilledWaterTank) {
   11287              :                             // plant sizing object design temperature is set too low throw warning.
   11288            0 :                             ShowSevereError(state,
   11289              :                                             "Autosizing of Source side water heater design flow rate requires Sizing:Plant object to have an "
   11290              :                                             "exit temperature >= 58C");
   11291            0 :                             ShowContinueError(state, format("Occurs for WaterHeater:Mixed object={}", this->Name));
   11292              :                         } else {
   11293              :                             // plant sizing object design temperature is set too hi throw warning.
   11294            0 :                             ShowSevereError(state,
   11295              :                                             "Autosizing of Source side chilled water tank design flow rate requires Sizing:Plant object to have "
   11296              :                                             "an exit temperature <= 8C");
   11297            0 :                             ShowContinueError(state, format("Occurs for chilled water storage tank object={}", this->Name));
   11298              :                         }
   11299            0 :                         ErrorsFound = true;
   11300              :                     }
   11301            0 :                     if (state.dataPlnt->PlantFinalSizesOkayToReport) {
   11302            0 :                         BaseSizer::reportSizerOutput(
   11303              :                             state, this->Type, this->Name, "Source Side Design Flow Rate [m3/s]", this->SourceDesignVolFlowRate);
   11304              :                     }
   11305            0 :                     if (state.dataPlnt->PlantFirstSizesOkayToReport) {
   11306            0 :                         BaseSizer::reportSizerOutput(
   11307              :                             state, this->Type, this->Name, "Initial Source Side Design Flow Rate [m3/s]", this->SourceDesignVolFlowRate);
   11308              :                     }
   11309            0 :                     if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
   11310            0 :                         PlantUtilities::RegisterPlantCompDesignFlow(state, this->SourceInletNode, this->SourceDesignVolFlowRate);
   11311              :                     } else {
   11312            0 :                         PlantUtilities::RegisterPlantCompDesignFlow(state, this->SourceInletNode, tmpSourceDesignVolFlowRate);
   11313              :                     }
   11314              :                     Real64 rho =
   11315            0 :                         state.dataPlnt->PlantLoop(this->SrcSidePlantLoc.loopNum).glycol->getDensity(state, Constant::InitConvTemp, RoutineName);
   11316            0 :                     if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
   11317            0 :                         this->PlantSourceMassFlowRateMax = this->SourceDesignVolFlowRate * rho;
   11318              :                     } else {
   11319            0 :                         this->PlantSourceMassFlowRateMax = tmpSourceDesignVolFlowRate * rho;
   11320              :                     }
   11321              :                 } // demand side
   11322              :             } else {
   11323              :                 // do nothing
   11324              :             } // plant sizing object
   11325              : 
   11326              :         } else {
   11327              :             // not autosized - report flow to RegisterPlantCompDesignFlow for supply side component sizing
   11328            1 :             PlantUtilities::RegisterPlantCompDesignFlow(state, this->SourceInletNode, this->SourceDesignVolFlowRate);
   11329              :             Real64 rho;
   11330            1 :             if (this->SrcSidePlantLoc.loopNum > 0) {
   11331            1 :                 rho = state.dataPlnt->PlantLoop(this->SrcSidePlantLoc.loopNum).glycol->getDensity(state, Constant::InitConvTemp, RoutineName);
   11332              :             } else {
   11333            0 :                 rho = this->water->getDensity(state, Constant::InitConvTemp, RoutineName);
   11334              :             }
   11335            1 :             this->PlantSourceMassFlowRateMax = this->SourceDesignVolFlowRate * rho;
   11336              :         } // autosizing needed.
   11337              :     }     // connected to plant
   11338              : 
   11339            1 :     if (ErrorsFound) {
   11340            0 :         ShowFatalError(state, "Preceding sizing errors cause program termination");
   11341              :     }
   11342            1 : }
   11343              : 
   11344            0 : void WaterThermalTankData::SizeStandAloneWaterHeater(EnergyPlusData &state)
   11345              : {
   11346              : 
   11347              :     // SUBROUTINE INFORMATION:
   11348              :     //       AUTHOR         B. Griffith
   11349              :     //       DATE WRITTEN   October 2013
   11350              :     //       MODIFIED       na
   11351              :     //       RE-ENGINEERED  na
   11352              : 
   11353              :     // PURPOSE OF THIS SUBROUTINE:
   11354              :     // allow autosizing of tank volume and heat capacity for stand alone tanks
   11355              : 
   11356              :     // METHODOLOGY EMPLOYED:
   11357              :     // same as for plant connected water heaters, only draws are scheduled.
   11358              : 
   11359              :     // SUBROUTINE PARAMETER DEFINITIONS:
   11360            0 :     Real64 constexpr GalTocubicMeters(0.0037854);
   11361            0 :     Real64 constexpr kBtuPerHrToWatts(293.1);
   11362              :     static constexpr std::string_view routineName = "SizeStandAloneWaterHeater";
   11363              : 
   11364            0 :     Real64 Tstart = 14.44;
   11365            0 :     Real64 Tfinish = 57.22;
   11366            0 :     Real64 tmpTankVolume = this->Volume;
   11367            0 :     Real64 tmpMaxCapacity = this->MaxCapacity;
   11368              : 
   11369            0 :     if (this->VolumeWasAutoSized || this->MaxCapacityWasAutoSized) {
   11370              : 
   11371            0 :         switch (this->Sizing.DesignMode) {
   11372              : 
   11373            0 :         case SizingMode::PeakDraw: {
   11374              :             // get draw rate from maximum in schedule
   11375              : 
   11376            0 :             Real64 rho = this->water->getDensity(state, Constant::InitConvTemp, routineName);
   11377            0 :             Real64 DrawDesignVolFlowRate = this->flowRateSched->getCurrentVal() * this->MassFlowRateMax / rho;
   11378              : 
   11379            0 :             if (this->VolumeWasAutoSized) {
   11380            0 :                 tmpTankVolume = this->Sizing.TankDrawTime * DrawDesignVolFlowRate * Constant::rSecsInHour; // hours | m3/s | (3600 s/1 hour)
   11381            0 :                 this->Volume = tmpTankVolume;
   11382            0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Tank Volume [m3]", this->Volume);
   11383              :             }
   11384            0 :             if (this->MaxCapacityWasAutoSized) {
   11385            0 :                 if (this->Sizing.RecoveryTime > 0.0) {
   11386            0 :                     rho = this->water->getDensity(state, ((Tfinish + Tstart) / 2.0), routineName);
   11387            0 :                     Real64 Cp = this->water->getSpecificHeat(state, ((Tfinish + Tstart) / 2.0), routineName);
   11388              : 
   11389            0 :                     tmpMaxCapacity = (this->Volume * rho * Cp * (Tfinish - Tstart)) /
   11390            0 :                                      (this->Sizing.RecoveryTime * Constant::rSecsInHour); // m3 | kg/m3 | J/Kg/K | K | seconds
   11391              :                 } else {
   11392            0 :                     ShowFatalError(
   11393              :                         state,
   11394            0 :                         format("{}: Tank=\"{}\", requested sizing for max capacity but entered Recovery Time is zero.", routineName, this->Name));
   11395              :                 }
   11396            0 :                 this->MaxCapacity = tmpMaxCapacity;
   11397            0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Maximum Heater Capacity [W]", this->MaxCapacity);
   11398              :             }
   11399              : 
   11400            0 :             break;
   11401              :         }
   11402            0 :         case SizingMode::ResidentialMin: {
   11403              :             // assume can propagate rules for gas to other fuels.
   11404            0 :             bool FuelTypeIsLikeGas = false;
   11405            0 :             switch (this->FuelType) {
   11406            0 :             case Constant::eFuel::NaturalGas:
   11407              :             case Constant::eFuel::Diesel:
   11408              :             case Constant::eFuel::Gasoline:
   11409              :             case Constant::eFuel::Coal:
   11410              :             case Constant::eFuel::FuelOilNo1:
   11411              :             case Constant::eFuel::FuelOilNo2:
   11412              :             case Constant::eFuel::Propane:
   11413              :             case Constant::eFuel::OtherFuel1:
   11414              :             case Constant::eFuel::OtherFuel2:
   11415              :             case Constant::eFuel::DistrictHeatingWater:
   11416              :             case Constant::eFuel::DistrictHeatingSteam:
   11417            0 :                 FuelTypeIsLikeGas = true;
   11418            0 :                 break;
   11419            0 :             default: // FuelTypeIsLikeGas stays false
   11420            0 :                 break;
   11421              :             }
   11422              : 
   11423            0 :             if (this->Sizing.NumberOfBedrooms == 1) {
   11424            0 :                 if (this->FuelType == Constant::eFuel::Electricity) {
   11425            0 :                     if (this->VolumeWasAutoSized) tmpTankVolume = 20.0 * GalTocubicMeters;
   11426            0 :                     if (this->MaxCapacityWasAutoSized) tmpMaxCapacity = 2.5 * 1000.0; // 2.5 kW
   11427            0 :                 } else if (FuelTypeIsLikeGas) {
   11428            0 :                     if (this->VolumeWasAutoSized) tmpTankVolume = 20.0 * GalTocubicMeters;
   11429            0 :                     if (this->MaxCapacityWasAutoSized) tmpMaxCapacity = 27.0 * kBtuPerHrToWatts; // 27kBtu/hr
   11430              :                 }
   11431              : 
   11432            0 :             } else if (this->Sizing.NumberOfBedrooms == 2) {
   11433            0 :                 if (this->Sizing.NumberOfBathrooms <= 1.5) {
   11434            0 :                     if (this->FuelType == Constant::eFuel::Electricity) {
   11435            0 :                         if (this->VolumeWasAutoSized) tmpTankVolume = 30.0 * GalTocubicMeters;
   11436            0 :                         if (this->MaxCapacityWasAutoSized) tmpMaxCapacity = 3.5 * 1000.0; // 3.5 kW
   11437            0 :                     } else if (FuelTypeIsLikeGas) {
   11438            0 :                         if (this->VolumeWasAutoSized) tmpTankVolume = 30.0 * GalTocubicMeters;
   11439            0 :                         if (this->MaxCapacityWasAutoSized) tmpMaxCapacity = 36.0 * kBtuPerHrToWatts; // 36 kBtu/hr
   11440              :                     }
   11441            0 :                 } else if ((this->Sizing.NumberOfBathrooms > 1.5) && (this->Sizing.NumberOfBathrooms < 3.0)) {
   11442            0 :                     if (this->FuelType == Constant::eFuel::Electricity) {
   11443            0 :                         if (this->VolumeWasAutoSized) tmpTankVolume = 40.0 * GalTocubicMeters;
   11444            0 :                         if (this->MaxCapacityWasAutoSized) tmpMaxCapacity = 4.5 * 1000.0; // 4.5 kW
   11445            0 :                     } else if (FuelTypeIsLikeGas) {
   11446            0 :                         if (this->VolumeWasAutoSized) tmpTankVolume = 30.0 * GalTocubicMeters;
   11447            0 :                         if (this->MaxCapacityWasAutoSized) tmpMaxCapacity = 36.0 * kBtuPerHrToWatts; // 36 kBtu/hr
   11448              :                     }
   11449            0 :                 } else if (this->Sizing.NumberOfBathrooms >= 3.0) {
   11450            0 :                     if (this->FuelType == Constant::eFuel::Electricity) {
   11451            0 :                         if (this->VolumeWasAutoSized) tmpTankVolume = 50.0 * GalTocubicMeters;
   11452            0 :                         if (this->MaxCapacityWasAutoSized) tmpMaxCapacity = 5.5 * 1000.0; // 5.5 kW
   11453            0 :                     } else if (FuelTypeIsLikeGas) {
   11454            0 :                         if (this->VolumeWasAutoSized) tmpTankVolume = 40.0 * GalTocubicMeters;
   11455            0 :                         if (this->MaxCapacityWasAutoSized) tmpMaxCapacity = 36.0 * kBtuPerHrToWatts; // 36 kBtu/hr
   11456              :                     }
   11457              :                 }
   11458            0 :             } else if (this->Sizing.NumberOfBedrooms == 3) {
   11459            0 :                 if (this->Sizing.NumberOfBathrooms <= 1.5) {
   11460            0 :                     if (this->FuelType == Constant::eFuel::Electricity) {
   11461            0 :                         if (this->VolumeWasAutoSized) tmpTankVolume = 40.0 * GalTocubicMeters;
   11462            0 :                         if (this->MaxCapacityWasAutoSized) tmpMaxCapacity = 4.5 * 1000.0; // 4.5 kW
   11463            0 :                     } else if (FuelTypeIsLikeGas) {
   11464            0 :                         if (this->VolumeWasAutoSized) tmpTankVolume = 30.0 * GalTocubicMeters;
   11465            0 :                         if (this->MaxCapacityWasAutoSized) tmpMaxCapacity = 36.0 * kBtuPerHrToWatts; // 36 kBtu/hr
   11466              :                     }
   11467            0 :                 } else if ((this->Sizing.NumberOfBathrooms > 1.5) && (this->Sizing.NumberOfBathrooms < 3.0)) {
   11468            0 :                     if (this->FuelType == Constant::eFuel::Electricity) {
   11469            0 :                         if (this->VolumeWasAutoSized) tmpTankVolume = 50.0 * GalTocubicMeters;
   11470            0 :                         if (this->MaxCapacityWasAutoSized) tmpMaxCapacity = 5.5 * 1000.0; // 5.5 kW
   11471            0 :                     } else if (FuelTypeIsLikeGas) {
   11472            0 :                         if (this->VolumeWasAutoSized) tmpTankVolume = 40.0 * GalTocubicMeters;
   11473            0 :                         if (this->MaxCapacityWasAutoSized) tmpMaxCapacity = 36.0 * kBtuPerHrToWatts; // 36 kBtu/hr
   11474              :                     }
   11475            0 :                 } else if (this->Sizing.NumberOfBathrooms >= 3.0) {
   11476            0 :                     if (this->FuelType == Constant::eFuel::Electricity) {
   11477            0 :                         if (this->VolumeWasAutoSized) tmpTankVolume = 50.0 * GalTocubicMeters;
   11478            0 :                         if (this->MaxCapacityWasAutoSized) tmpMaxCapacity = 5.5 * 1000.0; // 5.5 kW
   11479            0 :                     } else if (FuelTypeIsLikeGas) {
   11480            0 :                         if (this->VolumeWasAutoSized) tmpTankVolume = 40.0 * GalTocubicMeters;
   11481            0 :                         if (this->MaxCapacityWasAutoSized) tmpMaxCapacity = 38.0 * kBtuPerHrToWatts; // 38 kBtu/hr
   11482              :                     }
   11483              :                 }
   11484            0 :             } else if (this->Sizing.NumberOfBedrooms == 4) {
   11485            0 :                 if (this->Sizing.NumberOfBathrooms <= 1.5) {
   11486            0 :                     if (this->FuelType == Constant::eFuel::Electricity) {
   11487            0 :                         if (this->VolumeWasAutoSized) tmpTankVolume = 50.0 * GalTocubicMeters;
   11488            0 :                         if (this->MaxCapacityWasAutoSized) tmpMaxCapacity = 5.5 * 1000.0; // 5.5 kW
   11489            0 :                     } else if (FuelTypeIsLikeGas) {
   11490            0 :                         if (this->VolumeWasAutoSized) tmpTankVolume = 40.0 * GalTocubicMeters;
   11491            0 :                         if (this->MaxCapacityWasAutoSized) tmpMaxCapacity = 36.0 * kBtuPerHrToWatts; // 36 kBtu/hr
   11492              :                     }
   11493            0 :                 } else if ((this->Sizing.NumberOfBathrooms > 1.5) && (this->Sizing.NumberOfBathrooms < 3.0)) {
   11494            0 :                     if (this->FuelType == Constant::eFuel::Electricity) {
   11495            0 :                         if (this->VolumeWasAutoSized) tmpTankVolume = 50.0 * GalTocubicMeters;
   11496            0 :                         if (this->MaxCapacityWasAutoSized) tmpMaxCapacity = 5.5 * 1000.0; // 5.5 kW
   11497            0 :                     } else if (FuelTypeIsLikeGas) {
   11498            0 :                         if (this->VolumeWasAutoSized) tmpTankVolume = 40.0 * GalTocubicMeters;
   11499            0 :                         if (this->MaxCapacityWasAutoSized) tmpMaxCapacity = 38.0 * kBtuPerHrToWatts; // 38 kBtu/hr
   11500              :                     }
   11501            0 :                 } else if (this->Sizing.NumberOfBathrooms >= 3.0) {
   11502            0 :                     if (this->FuelType == Constant::eFuel::Electricity) {
   11503            0 :                         if (this->VolumeWasAutoSized) tmpTankVolume = 66.0 * GalTocubicMeters;
   11504            0 :                         if (this->MaxCapacityWasAutoSized) tmpMaxCapacity = 5.5 * 1000.0; // 5.5 kW
   11505            0 :                     } else if (FuelTypeIsLikeGas) {
   11506            0 :                         if (this->VolumeWasAutoSized) tmpTankVolume = 50.0 * GalTocubicMeters;
   11507            0 :                         if (this->MaxCapacityWasAutoSized) tmpMaxCapacity = 38.0 * kBtuPerHrToWatts; // 38 kBtu/hr
   11508              :                     }
   11509              :                 }
   11510            0 :             } else if (this->Sizing.NumberOfBedrooms == 5) {
   11511            0 :                 if (this->FuelType == Constant::eFuel::Electricity) {
   11512            0 :                     if (this->VolumeWasAutoSized) tmpTankVolume = 66.0 * GalTocubicMeters;
   11513            0 :                     if (this->MaxCapacityWasAutoSized) tmpMaxCapacity = 5.5 * 1000.0; // 5.5 kW
   11514            0 :                 } else if (FuelTypeIsLikeGas) {
   11515            0 :                     if (this->VolumeWasAutoSized) tmpTankVolume = 50.0 * GalTocubicMeters;
   11516            0 :                     if (this->MaxCapacityWasAutoSized) tmpMaxCapacity = 47.0 * kBtuPerHrToWatts; // 47 kBtu/hr
   11517              :                 }
   11518            0 :             } else if (this->Sizing.NumberOfBedrooms >= 6) {
   11519            0 :                 if (this->FuelType == Constant::eFuel::Electricity) {
   11520            0 :                     if (this->VolumeWasAutoSized) tmpTankVolume = 66.0 * GalTocubicMeters;
   11521            0 :                     if (this->MaxCapacityWasAutoSized) tmpMaxCapacity = 5.5 * 1000.0; // 5.5 kW
   11522            0 :                 } else if (FuelTypeIsLikeGas) {
   11523            0 :                     if (this->VolumeWasAutoSized) tmpTankVolume = 50.0 * GalTocubicMeters;
   11524            0 :                     if (this->MaxCapacityWasAutoSized) tmpMaxCapacity = 50.0 * kBtuPerHrToWatts; // 50 kBtu/hr
   11525              :                 }
   11526              :             }
   11527            0 :             if (this->VolumeWasAutoSized) {
   11528            0 :                 this->Volume = tmpTankVolume;
   11529            0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Tank Volume [m3]", this->Volume);
   11530              :             }
   11531            0 :             if (this->MaxCapacityWasAutoSized) {
   11532            0 :                 this->MaxCapacity = tmpMaxCapacity;
   11533            0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Maximum Heater Capacity [W]", this->MaxCapacity);
   11534              :             }
   11535              : 
   11536            0 :             break;
   11537              :         }
   11538            0 :         case SizingMode::PerPerson: {
   11539              :             // how to get number of people?
   11540              : 
   11541              :             // MJW TODO: this won't compile now: Real64 SumPeopleAllZones = sum(state.dataHeatBal->Zone, &DataHeatBalance::ZoneData::TotOccupants);
   11542            0 :             Real64 SumPeopleAllZones = 0.0;
   11543            0 :             for (auto const &thisZone : state.dataHeatBal->Zone) {
   11544            0 :                 SumPeopleAllZones += thisZone.TotOccupants;
   11545              :             }
   11546            0 :             if (this->VolumeWasAutoSized) {
   11547            0 :                 tmpTankVolume = this->Sizing.TankCapacityPerPerson * SumPeopleAllZones;
   11548              :             }
   11549            0 :             if (this->MaxCapacityWasAutoSized) {
   11550            0 :                 Real64 rho = this->water->getDensity(state, ((Tfinish + Tstart) / 2.0), routineName);
   11551            0 :                 Real64 Cp = this->water->getSpecificHeat(state, ((Tfinish + Tstart) / 2.0), routineName);
   11552            0 :                 tmpMaxCapacity = SumPeopleAllZones * this->Sizing.RecoveryCapacityPerPerson * (Tfinish - Tstart) * (1.0 / Constant::rSecsInHour) *
   11553              :                                  rho * Cp; // m3/hr/person | delta T  in K | 1 hr/ 3600 s | kg/m3 | J/Kg/k
   11554              :             }
   11555              : 
   11556            0 :             if (this->VolumeWasAutoSized) {
   11557            0 :                 this->Volume = tmpTankVolume;
   11558            0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Tank Volume [m3]", this->Volume);
   11559              :             }
   11560            0 :             if (this->MaxCapacityWasAutoSized) {
   11561            0 :                 this->MaxCapacity = tmpMaxCapacity;
   11562            0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Maximum Heater Capacity [W]", this->MaxCapacity);
   11563              :             }
   11564              : 
   11565            0 :             break;
   11566              :         }
   11567            0 :         case SizingMode::PerFloorArea: {
   11568              : 
   11569              :             // MJW TODO: this won't compile now: Real64 SumFloorAreaAllZones = sum(state.dataHeatBal->Zone, &DataHeatBalance::ZoneData::FloorArea);
   11570            0 :             Real64 SumFloorAreaAllZones = 0.0;
   11571            0 :             for (auto const &thisZone : state.dataHeatBal->Zone) {
   11572            0 :                 SumFloorAreaAllZones += thisZone.FloorArea;
   11573              :             }
   11574            0 :             if (this->VolumeWasAutoSized) {
   11575            0 :                 tmpTankVolume = this->Sizing.TankCapacityPerArea * SumFloorAreaAllZones;
   11576              :             }
   11577              : 
   11578            0 :             if (this->MaxCapacityWasAutoSized) {
   11579            0 :                 Real64 rho = this->water->getDensity(state, ((Tfinish + Tstart) / 2.0), routineName);
   11580            0 :                 Real64 Cp = this->water->getSpecificHeat(state, ((Tfinish + Tstart) / 2.0), routineName);
   11581            0 :                 tmpMaxCapacity = SumFloorAreaAllZones * this->Sizing.RecoveryCapacityPerArea * (Tfinish - Tstart) * (1.0 / Constant::rSecsInHour) *
   11582              :                                  rho * Cp; // m2 | m3/hr/m2 | delta T  in K | 1 hr/ 3600 s | kg/m3 | J/Kg/k
   11583              :             }
   11584            0 :             if (this->VolumeWasAutoSized) {
   11585            0 :                 this->Volume = tmpTankVolume;
   11586            0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Tank Volume [m3]", this->Volume);
   11587              :             }
   11588            0 :             if (this->MaxCapacityWasAutoSized) {
   11589            0 :                 this->MaxCapacity = tmpMaxCapacity;
   11590            0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Maximum Heater Capacity [W]", this->MaxCapacity);
   11591              :             }
   11592            0 :             break;
   11593              :         }
   11594            0 :         case SizingMode::PerUnit: {
   11595              : 
   11596            0 :             if (this->VolumeWasAutoSized) tmpTankVolume = this->Sizing.TankCapacityPerUnit * this->Sizing.NumberOfUnits;
   11597              : 
   11598            0 :             if (this->MaxCapacityWasAutoSized) {
   11599            0 :                 Real64 rho = this->water->getDensity(state, ((Tfinish + Tstart) / 2.0), routineName);
   11600            0 :                 Real64 Cp = this->water->getSpecificHeat(state, ((Tfinish + Tstart) / 2.0), routineName);
   11601            0 :                 tmpMaxCapacity = this->Sizing.NumberOfUnits * this->Sizing.RecoveryCapacityPerUnit * (Tfinish - Tstart) *
   11602            0 :                                  (1.0 / Constant::rSecsInHour) * rho * Cp; // m3/hr/ea | delta T  in K | 1 hr/ 3600 s | kg/m3 | J/Kg/k
   11603              :             }
   11604              : 
   11605            0 :             if (this->VolumeWasAutoSized) {
   11606            0 :                 this->Volume = tmpTankVolume;
   11607            0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Tank Volume [m3]", this->Volume);
   11608              :             }
   11609            0 :             if (this->MaxCapacityWasAutoSized) {
   11610            0 :                 this->MaxCapacity = tmpMaxCapacity;
   11611            0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Maximum Heater Capacity [W]", this->MaxCapacity);
   11612              :             }
   11613            0 :             break;
   11614              :         }
   11615            0 :         case SizingMode::PerSolarColArea: {
   11616              : 
   11617            0 :             this->Sizing.TotalSolarCollectorArea = 0.0;
   11618              : 
   11619            0 :             for (int CollectorNum = 1; CollectorNum <= state.dataSolarCollectors->NumOfCollectors; ++CollectorNum) {
   11620            0 :                 auto const &collector = state.dataSolarCollectors->Collector(CollectorNum);
   11621            0 :                 this->Sizing.TotalSolarCollectorArea += state.dataSurface->Surface(collector.Surface).Area;
   11622              :             }
   11623              : 
   11624            0 :             for (int CollectorNum = 1; CollectorNum <= state.dataPhotovoltaicThermalCollector->NumPVT; ++CollectorNum) {
   11625            0 :                 auto const &collector = state.dataPhotovoltaicThermalCollector->PVT(CollectorNum);
   11626            0 :                 this->Sizing.TotalSolarCollectorArea += collector.AreaCol;
   11627              :             }
   11628              : 
   11629            0 :             if (this->VolumeWasAutoSized) {
   11630            0 :                 if (this->Sizing.TotalSolarCollectorArea > 0) {
   11631            0 :                     tmpTankVolume = this->Sizing.TotalSolarCollectorArea * this->Sizing.TankCapacityPerCollectorArea;
   11632              :                 } else {
   11633            0 :                     ShowFatalError(state,
   11634            0 :                                    format("{}: Tank=\"{}\", requested sizing for volume with PerSolarCollectorArea but total found "
   11635              :                                           "area of Collectors is zero.",
   11636              :                                           routineName,
   11637            0 :                                           this->Name));
   11638              :                 }
   11639              :             }
   11640            0 :             if (this->MaxCapacityWasAutoSized) {
   11641            0 :                 tmpMaxCapacity = 0.0;
   11642              :             }
   11643              : 
   11644            0 :             if (this->VolumeWasAutoSized) {
   11645            0 :                 this->Volume = tmpTankVolume;
   11646            0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Tank Volume [m3]", this->Volume);
   11647              :             }
   11648            0 :             if (this->MaxCapacityWasAutoSized) {
   11649            0 :                 this->MaxCapacity = tmpMaxCapacity;
   11650            0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Maximum Heater Capacity [W]", this->MaxCapacity);
   11651              :             }
   11652            0 :             break;
   11653              :         }
   11654            0 :         default:
   11655            0 :             if (this->MaxCapacityWasAutoSized) {
   11656            0 :                 this->setBackupElementCapacity(state);
   11657              :             }
   11658            0 :             break;
   11659              :         }
   11660              :     }
   11661            0 : }
   11662              : 
   11663            7 : void WaterThermalTankData::UpdateWaterThermalTank(EnergyPlusData &state)
   11664              : {
   11665              : 
   11666              :     // SUBROUTINE INFORMATION:
   11667              :     //       AUTHOR         Brandon Anderson
   11668              :     //       DATE WRITTEN   May 2000
   11669              :     //       MODIFIED       na
   11670              :     //                      Nov 2011, BAN; removed the use and source heat rate re-calculation for stratified tank
   11671              :     //                                     for energy conservation verification.
   11672              :     //       RE-ENGINEERED  Feb 2004, PGE
   11673              : 
   11674              :     // PURPOSE OF THIS SUBROUTINE:
   11675              :     // Updates the node variables with local variables.
   11676              : 
   11677            7 :     if (this->UseInletNode > 0 && this->UseOutletNode > 0) {
   11678            6 :         state.dataLoopNodes->Node(UseOutletNode) = state.dataLoopNodes->Node(this->UseInletNode); // this could wipe out setpoints on outlet node
   11679              : 
   11680            6 :         state.dataLoopNodes->Node(this->UseOutletNode).Temp = this->UseOutletTemp;
   11681              :     }
   11682              : 
   11683            7 :     if (this->SourceInletNode > 0 && this->SourceOutletNode > 0) {
   11684            7 :         state.dataLoopNodes->Node(this->SourceOutletNode) = state.dataLoopNodes->Node(this->SourceInletNode);
   11685              : 
   11686            7 :         state.dataLoopNodes->Node(this->SourceOutletNode).Temp = this->SourceOutletTemp;
   11687              :     }
   11688            7 : }
   11689              : 
   11690            1 : void WaterThermalTankData::ReportWaterThermalTank(EnergyPlusData &state)
   11691              : {
   11692              : 
   11693              :     // SUBROUTINE INFORMATION:
   11694              :     //       AUTHOR         Brandon Anderson
   11695              :     //       DATE WRITTEN   May 2000
   11696              :     //       MODIFIED       na
   11697              :     //       RE-ENGINEERED  Feb 2004, PGE
   11698              : 
   11699            1 :     Real64 SecInTimeStep = state.dataHVACGlobal->TimeStepSysSec;
   11700              : 
   11701            1 :     this->UnmetEnergy = this->UnmetRate * SecInTimeStep;
   11702            1 :     this->LossEnergy = this->LossRate * SecInTimeStep;
   11703            1 :     this->FlueLossEnergy = this->FlueLossRate * SecInTimeStep;
   11704            1 :     this->UseEnergy = this->UseRate * SecInTimeStep;
   11705            1 :     this->TotalDemandEnergy = this->TotalDemandRate * SecInTimeStep;
   11706            1 :     this->SourceEnergy = this->SourceRate * SecInTimeStep;
   11707            1 :     this->HeaterEnergy = this->HeaterRate * SecInTimeStep;
   11708            1 :     this->HeaterEnergy1 = this->HeaterRate1 * SecInTimeStep;
   11709            1 :     this->HeaterEnergy2 = this->HeaterRate2 * SecInTimeStep;
   11710            1 :     this->FuelEnergy = this->FuelRate * SecInTimeStep;
   11711            1 :     this->VentEnergy = this->VentRate * SecInTimeStep;
   11712            1 :     this->OffCycParaFuelEnergy = this->OffCycParaFuelRate * SecInTimeStep;
   11713            1 :     this->OffCycParaEnergyToTank = this->OffCycParaRateToTank * SecInTimeStep;
   11714            1 :     this->OnCycParaFuelEnergy = this->OnCycParaFuelRate * SecInTimeStep;
   11715            1 :     this->OnCycParaEnergyToTank = this->OnCycParaRateToTank * SecInTimeStep;
   11716            1 :     this->NetHeatTransferEnergy = this->NetHeatTransferRate * SecInTimeStep;
   11717            1 :     this->VolumeConsumed = this->VolFlowRate * SecInTimeStep;
   11718            1 : }
   11719              : 
   11720            8 : void WaterThermalTankData::CalcStandardRatings(EnergyPlusData &state)
   11721              : {
   11722              : 
   11723              :     // SUBROUTINE INFORMATION:
   11724              :     //       AUTHOR         Peter Graham Ellis
   11725              :     //       DATE WRITTEN   January 2005
   11726              :     //       MODIFIED       R. Raustad, July 2005 - added HPWH to ratings procedure
   11727              :     //       RE-ENGINEERED  na
   11728              : 
   11729              :     // PURPOSE OF THIS SUBROUTINE:
   11730              :     // Calculates the water heater standard ratings, such as Energy Factor and Recovery Efficiency.  Results are written
   11731              :     // to the EIO file.  Standard ratings are not calculated for storage-only tanks, i.e., MaxCapacity = 0, nor for Integrated Heat Pumps
   11732              : 
   11733              :     // METHODOLOGY EMPLOYED:
   11734              :     // Water heater inputs are set to the specified test conditions. For HPWHs, the heating capacity and COP are assumed
   11735              :     // to be the primary element in the water heater and are used during the rating procedure.  CalcWaterThermalTankMixed
   11736              :     // is iteratively called in a self-contained, 24 hour simulation of the standard test procedure.
   11737              : 
   11738              :     // REFERENCES:
   11739              :     // Title 10, Code of Federal Regulations, Part 430- Energy Conservation Program for Consumer Products, Appendix E to
   11740              :     // Subpart B- Uniform Test Procedure for Measuring the Energy Consumption of Water Heaters, January 1, 2004.
   11741              : 
   11742            8 :     if (this->AlreadyRated) { // bail we already did this one
   11743            1 :         return;
   11744              :     }
   11745              : 
   11746              :     bool FirstTimeFlag; // used during HPWH rating procedure
   11747            7 :     bool bIsVSCoil = false;
   11748              :     Real64 RecoveryEfficiency;
   11749              :     Real64 EnergyFactor;
   11750            7 :     Real64 RatedDXCoilTotalCapacity = 0.0;
   11751            7 :     if (this->MaxCapacity > 0.0 || this->HeatPumpNum > 0) {
   11752              :         // Set test conditions
   11753            5 :         this->AmbientTemp = 19.7222;   // 67.5 F
   11754            5 :         this->UseInletTemp = 14.4444;  // 58 F
   11755            5 :         this->SetPointTemp = 57.2222;  // 135 F
   11756            5 :         this->SetPointTemp2 = 57.2222; // 135 F
   11757            5 :         this->TankTemp = 57.2222;      // Initialize tank temperature
   11758            5 :         if (this->Nodes > 0)
   11759           13 :             for (auto &e : this->Node)
   11760           12 :                 e.Temp = 57.2222;
   11761              : 
   11762            5 :         Real64 TotalDrawMass = 0.243402 * Psychrometrics::RhoH2O(Constant::InitConvTemp); // 64.3 gal * rho
   11763            5 :         Real64 DrawMass = TotalDrawMass / 6.0;                                            // 6 equal draws
   11764            5 :         Real64 SecInTimeStep = state.dataHVACGlobal->TimeStepSysSec;
   11765            5 :         Real64 DrawMassFlowRate = DrawMass / SecInTimeStep;
   11766            5 :         Real64 FuelEnergy_loc = 0.0;
   11767            5 :         FirstTimeFlag = true;
   11768              : 
   11769            5 :         int TimeStepPerHour = int(1.0 / state.dataHVACGlobal->TimeStepSys);
   11770              :         // Simulate 24 hour test
   11771         1541 :         for (int Step = 1; Step <= TimeStepPerHour * 24; ++Step) {
   11772              : 
   11773         1536 :             if (Step == 1 || Step == (1 + TimeStepPerHour) || Step == (1 + TimeStepPerHour * 2) || Step == (1 + TimeStepPerHour * 3) ||
   11774         1516 :                 Step == (1 + TimeStepPerHour * 4) || Step == (1 + TimeStepPerHour * 5)) { // Hour 1 | Hour 2 | Hour 3 | Hour 4 | Hour 5 | Hour 6
   11775              : 
   11776           30 :                 this->UseMassFlowRate = DrawMassFlowRate;
   11777              :             } else {
   11778         1506 :                 this->UseMassFlowRate = 0.0;
   11779              :             }
   11780              : 
   11781         1536 :             this->SavedTankTemp = this->TankTemp;
   11782         1536 :             this->SavedMode = this->Mode;
   11783         1536 :             if (this->Nodes > 0) {
   11784        18720 :                 for (auto &e : this->Node)
   11785        17280 :                     e.SavedTemp = e.Temp;
   11786         1440 :                 this->SavedHeaterOn1 = this->HeaterOn1;
   11787         1440 :                 this->SavedHeaterOn2 = this->HeaterOn2;
   11788              :             }
   11789              : 
   11790         1536 :             if (this->HeatPumpNum == 0) {
   11791              : 
   11792         1464 :                 if (this->WaterThermalTankType == DataPlant::PlantEquipmentType::WtrHeaterMixed) {
   11793           24 :                     this->CalcWaterThermalTankMixed(state);
   11794              : 
   11795         1440 :                 } else if (this->WaterThermalTankType == DataPlant::PlantEquipmentType::WtrHeaterStratified) {
   11796         1440 :                     this->CalcWaterThermalTankStratified(state);
   11797              :                 }
   11798              : 
   11799              :             } else {
   11800              : 
   11801           72 :                 int HPNum = this->HeatPumpNum;  // Convenience variable
   11802           72 :                 Real64 AmbientHumRat = 0.00717; // Humidity ratio at 67.5 F / 50% RH
   11803              : 
   11804              :                 //       set the heat pump air- and water-side mass flow rate
   11805           72 :                 Real64 MdotWater = state.dataWaterThermalTanks->HPWaterHeater(HPNum).OperatingWaterFlowRate * Psychrometrics::RhoH2O(this->TankTemp);
   11806           72 :                 Real64 mdotAir = state.dataWaterThermalTanks->HPWaterHeater(HPNum).OperatingAirMassFlowRate;
   11807              : 
   11808              :                 // ?? why is HPWH condenser inlet node temp reset inside the for loop? shouldn't it chnage with the tank temp throughout these
   11809              :                 // iterations?
   11810           72 :                 if (state.dataWaterThermalTanks->HPWaterHeater(HPNum).HPWHType == DataPlant::PlantEquipmentType::HeatPumpWtrHeaterPumped) {
   11811              :                     // set the condenser inlet node mass flow rate and temperature
   11812           72 :                     state.dataLoopNodes->Node(state.dataWaterThermalTanks->HPWaterHeater(HPNum).CondWaterInletNode).MassFlowRate = MdotWater;
   11813           72 :                     state.dataLoopNodes->Node(state.dataWaterThermalTanks->HPWaterHeater(HPNum).CondWaterInletNode).Temp = this->TankTemp;
   11814              :                 }
   11815              : 
   11816              :                 //       initialize temperatures for HPWH DX Coil heating capacity and COP curves
   11817           72 :                 state.dataHVACGlobal->HPWHInletDBTemp = this->AmbientTemp;
   11818          144 :                 state.dataHVACGlobal->HPWHInletWBTemp =
   11819           72 :                     Psychrometrics::PsyTwbFnTdbWPb(state, state.dataHVACGlobal->HPWHInletDBTemp, AmbientHumRat, state.dataEnvrn->OutBaroPress);
   11820              : 
   11821              :                 //       set up full air flow on DX coil inlet node
   11822           72 :                 if (state.dataWaterThermalTanks->HPWaterHeater(HPNum).InletAirMixerNode > 0) {
   11823            0 :                     state.dataLoopNodes->Node(state.dataWaterThermalTanks->HPWaterHeater(HPNum).InletAirMixerNode).MassFlowRate = mdotAir;
   11824            0 :                     state.dataLoopNodes->Node(state.dataWaterThermalTanks->HPWaterHeater(HPNum).InletAirMixerNode).MassFlowRateMaxAvail = mdotAir;
   11825            0 :                     state.dataLoopNodes->Node(state.dataWaterThermalTanks->HPWaterHeater(HPNum).InletAirMixerNode).Temp = this->AmbientTemp;
   11826            0 :                     state.dataLoopNodes->Node(state.dataWaterThermalTanks->HPWaterHeater(HPNum).InletAirMixerNode).HumRat = AmbientHumRat;
   11827            0 :                     state.dataLoopNodes->Node(state.dataWaterThermalTanks->HPWaterHeater(HPNum).InletAirMixerNode).Enthalpy =
   11828            0 :                         Psychrometrics::PsyHFnTdbW(this->AmbientTemp, AmbientHumRat);
   11829              :                 } else {
   11830           72 :                     if (state.dataWaterThermalTanks->HPWaterHeater(HPNum).OutsideAirNode == 0) {
   11831           24 :                         state.dataLoopNodes->Node(state.dataWaterThermalTanks->HPWaterHeater(HPNum).HeatPumpAirInletNode).MassFlowRate = mdotAir;
   11832           24 :                         state.dataLoopNodes->Node(state.dataWaterThermalTanks->HPWaterHeater(HPNum).HeatPumpAirInletNode).MassFlowRateMaxAvail =
   11833              :                             mdotAir;
   11834           24 :                         state.dataLoopNodes->Node(state.dataWaterThermalTanks->HPWaterHeater(HPNum).HeatPumpAirInletNode).Temp = this->AmbientTemp;
   11835           24 :                         state.dataLoopNodes->Node(state.dataWaterThermalTanks->HPWaterHeater(HPNum).HeatPumpAirInletNode).HumRat = AmbientHumRat;
   11836           24 :                         state.dataLoopNodes->Node(state.dataWaterThermalTanks->HPWaterHeater(HPNum).HeatPumpAirInletNode).Enthalpy =
   11837           24 :                             Psychrometrics::PsyHFnTdbW(this->AmbientTemp, AmbientHumRat);
   11838              :                     } else {
   11839           48 :                         state.dataLoopNodes->Node(state.dataWaterThermalTanks->HPWaterHeater(HPNum).OutsideAirNode).MassFlowRate = mdotAir;
   11840           48 :                         state.dataLoopNodes->Node(state.dataWaterThermalTanks->HPWaterHeater(HPNum).OutsideAirNode).MassFlowRateMaxAvail = mdotAir;
   11841           48 :                         state.dataLoopNodes->Node(state.dataWaterThermalTanks->HPWaterHeater(HPNum).OutsideAirNode).Temp = this->AmbientTemp;
   11842           48 :                         state.dataLoopNodes->Node(state.dataWaterThermalTanks->HPWaterHeater(HPNum).OutsideAirNode).HumRat = AmbientHumRat;
   11843           48 :                         state.dataLoopNodes->Node(state.dataWaterThermalTanks->HPWaterHeater(HPNum).OutsideAirNode).Enthalpy =
   11844           48 :                             Psychrometrics::PsyHFnTdbW(this->AmbientTemp, AmbientHumRat);
   11845              :                     }
   11846              :                 }
   11847              : 
   11848           72 :                 state.dataHVACGlobal->HPWHCrankcaseDBTemp = this->AmbientTemp;
   11849              : 
   11850           72 :                 if (Util::SameString(state.dataWaterThermalTanks->HPWaterHeater(HPNum).DXCoilType,
   11851          144 :                                      "Coil:WaterHeating:AirToWaterHeatPump:VariableSpeed") ||
   11852           72 :                     (state.dataWaterThermalTanks->HPWaterHeater(HPNum).bIsIHP)) {
   11853            0 :                     bIsVSCoil = true;
   11854            0 :                     std::string VSCoilName = state.dataWaterThermalTanks->HPWaterHeater(HPNum).DXCoilName;
   11855            0 :                     int VSCoilNum = state.dataWaterThermalTanks->HPWaterHeater(HPNum).DXCoilNum;
   11856            0 :                     if (state.dataWaterThermalTanks->HPWaterHeater(HPNum).bIsIHP) {
   11857            0 :                         VSCoilNum =
   11858            0 :                             state.dataIntegratedHP->IntegratedHeatPumps(state.dataWaterThermalTanks->HPWaterHeater(HPNum).DXCoilNum).SCWHCoilIndex;
   11859              :                         VSCoilName =
   11860            0 :                             state.dataIntegratedHP->IntegratedHeatPumps(state.dataWaterThermalTanks->HPWaterHeater(HPNum).DXCoilNum).SCWHCoilName;
   11861              :                     }
   11862              : 
   11863            0 :                     Real64 RhoWater = Psychrometrics::RhoH2O(this->TankTemp);
   11864            0 :                     auto &HPWH = state.dataWaterThermalTanks->HPWaterHeater(HPNum);
   11865            0 :                     this->SetVSHPWHFlowRates(
   11866              :                         state,
   11867              :                         HPWH,
   11868            0 :                         state.dataVariableSpeedCoils->VarSpeedCoil(state.dataWaterThermalTanks->HPWaterHeater(HPNum).DXCoilNum).NormSpedLevel,
   11869              :                         1.0,
   11870              :                         RhoWater,
   11871              :                         MdotWater,
   11872              :                         true);
   11873              :                     //       simulate the HPWH coil/fan to find heating capacity
   11874            0 :                     if (state.dataWaterThermalTanks->HPWaterHeater(HPNum).fanPlace == HVAC::FanPlace::BlowThru) {
   11875              :                         //   simulate fan and DX coil twice
   11876            0 :                         state.dataFans->fans(state.dataWaterThermalTanks->HPWaterHeater(HPNum).FanNum)->simulate(state, true, _, _);
   11877              : 
   11878            0 :                         VariableSpeedCoils::SimVariableSpeedCoils(
   11879              :                             state,
   11880              :                             VSCoilName,
   11881              :                             VSCoilNum,
   11882              :                             HVAC::FanOp::Cycling,
   11883              :                             HVAC::CompressorOp::On,
   11884              :                             1.0,
   11885            0 :                             state.dataVariableSpeedCoils->VarSpeedCoil(state.dataWaterThermalTanks->HPWaterHeater(HPNum).DXCoilNum).NormSpedLevel,
   11886              :                             1.0,
   11887              :                             0.0,
   11888              :                             0.0,
   11889              :                             1.0);
   11890              : 
   11891            0 :                         state.dataFans->fans(state.dataWaterThermalTanks->HPWaterHeater(HPNum).FanNum)->simulate(state, true, _, _);
   11892              : 
   11893            0 :                         VariableSpeedCoils::SimVariableSpeedCoils(
   11894              :                             state,
   11895              :                             VSCoilName,
   11896              :                             VSCoilNum,
   11897              :                             HVAC::FanOp::Cycling,
   11898              :                             HVAC::CompressorOp::On,
   11899              :                             1.0,
   11900            0 :                             state.dataVariableSpeedCoils->VarSpeedCoil(state.dataWaterThermalTanks->HPWaterHeater(HPNum).DXCoilNum).NormSpedLevel,
   11901              :                             1.0,
   11902              :                             0.0,
   11903              :                             0.0,
   11904              :                             1.0);
   11905              :                     } else {
   11906              :                         //   simulate DX coil and fan twice to pass fan power (FanElecPower) to DX coil
   11907            0 :                         VariableSpeedCoils::SimVariableSpeedCoils(
   11908              :                             state,
   11909              :                             VSCoilName,
   11910              :                             VSCoilNum,
   11911              :                             HVAC::FanOp::Cycling,
   11912              :                             HVAC::CompressorOp::On,
   11913              :                             1.0,
   11914            0 :                             state.dataVariableSpeedCoils->VarSpeedCoil(state.dataWaterThermalTanks->HPWaterHeater(HPNum).DXCoilNum).NormSpedLevel,
   11915              :                             1.0,
   11916              :                             0.0,
   11917              :                             0.0,
   11918              :                             1.0);
   11919              : 
   11920            0 :                         state.dataFans->fans(state.dataWaterThermalTanks->HPWaterHeater(HPNum).FanNum)->simulate(state, true, _, _);
   11921              : 
   11922            0 :                         VariableSpeedCoils::SimVariableSpeedCoils(
   11923              :                             state,
   11924              :                             VSCoilName,
   11925              :                             VSCoilNum,
   11926              :                             HVAC::FanOp::Cycling,
   11927              :                             HVAC::CompressorOp::On,
   11928              :                             1.0,
   11929            0 :                             state.dataVariableSpeedCoils->VarSpeedCoil(state.dataWaterThermalTanks->HPWaterHeater(HPNum).DXCoilNum).NormSpedLevel,
   11930              :                             1.0,
   11931              :                             0.0,
   11932              :                             0.0,
   11933              :                             1.0);
   11934              : 
   11935            0 :                         state.dataFans->fans(state.dataWaterThermalTanks->HPWaterHeater(HPNum).FanNum)->simulate(state, true, _, _);
   11936              :                     }
   11937              : 
   11938            0 :                     this->MaxCapacity = state.dataVariableSpeedCoils->VSHPWHHeatingCapacity;
   11939            0 :                     this->MinCapacity = state.dataVariableSpeedCoils->VSHPWHHeatingCapacity;
   11940            0 :                     this->Efficiency = state.dataVariableSpeedCoils->VSHPWHHeatingCOP;
   11941            0 :                 } else {
   11942           72 :                     bIsVSCoil = false;
   11943              :                     //       simulate the HPWH coil/fan to find heating capacity
   11944           72 :                     if (state.dataWaterThermalTanks->HPWaterHeater(HPNum).fanPlace == HVAC::FanPlace::BlowThru) {
   11945            0 :                         if (FirstTimeFlag) { // first time DXCoils::DXCoil is called, it's sized at the RatedCondenserWaterInlet temp, size and
   11946              :                                              // reset water inlet temp. If already sized, no harm.
   11947            0 :                             state.dataFans->fans(state.dataWaterThermalTanks->HPWaterHeater(HPNum).FanNum)->simulate(state, true, _, _);
   11948              : 
   11949            0 :                             DXCoils::SimDXCoil(state,
   11950            0 :                                                state.dataWaterThermalTanks->HPWaterHeater(HPNum).DXCoilName,
   11951              :                                                HVAC::CompressorOp::On,
   11952              :                                                true,
   11953            0 :                                                state.dataWaterThermalTanks->HPWaterHeater(HPNum).DXCoilNum,
   11954              :                                                HVAC::FanOp::Cycling,
   11955            0 :                                                1.0);
   11956            0 :                             state.dataLoopNodes->Node(state.dataWaterThermalTanks->HPWaterHeater(HPNum).CondWaterInletNode).Temp = this->TankTemp;
   11957              :                         }
   11958              :                         // ?? should only need to call twice if PLR<1 since this might affect OnOffFanPartLoadFraction which impacts fan energy.
   11959              :                         // PLR=1 here.
   11960            0 :                         state.dataFans->fans(state.dataWaterThermalTanks->HPWaterHeater(HPNum).FanNum)->simulate(state, true, _, _);
   11961              : 
   11962            0 :                         DXCoils::SimDXCoil(state,
   11963            0 :                                            state.dataWaterThermalTanks->HPWaterHeater(HPNum).DXCoilName,
   11964              :                                            HVAC::CompressorOp::On,
   11965              :                                            true,
   11966            0 :                                            state.dataWaterThermalTanks->HPWaterHeater(HPNum).DXCoilNum,
   11967              :                                            HVAC::FanOp::Cycling,
   11968            0 :                                            1.0);
   11969              : 
   11970            0 :                         state.dataFans->fans(state.dataWaterThermalTanks->HPWaterHeater(HPNum).FanNum)->simulate(state, true, _, _);
   11971              : 
   11972            0 :                         DXCoils::SimDXCoil(state,
   11973            0 :                                            state.dataWaterThermalTanks->HPWaterHeater(HPNum).DXCoilName,
   11974              :                                            HVAC::CompressorOp::On,
   11975              :                                            true,
   11976            0 :                                            state.dataWaterThermalTanks->HPWaterHeater(HPNum).DXCoilNum,
   11977              :                                            HVAC::FanOp::Cycling,
   11978            0 :                                            1.0);
   11979              :                     } else {
   11980           72 :                         if (FirstTimeFlag) { // first time DXCoils::DXCoil is called, it's sized at the RatedCondenserWaterInlet temp, size and
   11981              :                                              // reset water inlet temp. If already sized, no harm.
   11982            9 :                             DXCoils::SimDXCoil(state,
   11983            3 :                                                state.dataWaterThermalTanks->HPWaterHeater(HPNum).DXCoilName,
   11984              :                                                HVAC::CompressorOp::On,
   11985              :                                                true,
   11986            3 :                                                state.dataWaterThermalTanks->HPWaterHeater(HPNum).DXCoilNum,
   11987              :                                                HVAC::FanOp::Cycling,
   11988            6 :                                                1.0);
   11989            3 :                             state.dataLoopNodes->Node(state.dataWaterThermalTanks->HPWaterHeater(HPNum).CondWaterInletNode).Temp = this->TankTemp;
   11990              :                         }
   11991              :                         // ?? should only need to call twice if PLR<1 since this might affect OnOffFanPartLoadFraction which impacts fan energy.
   11992              :                         // PLR=1 here.
   11993          216 :                         DXCoils::SimDXCoil(state,
   11994           72 :                                            state.dataWaterThermalTanks->HPWaterHeater(HPNum).DXCoilName,
   11995              :                                            HVAC::CompressorOp::On,
   11996              :                                            true,
   11997           72 :                                            state.dataWaterThermalTanks->HPWaterHeater(HPNum).DXCoilNum,
   11998              :                                            HVAC::FanOp::Cycling,
   11999          144 :                                            1.0);
   12000              : 
   12001           72 :                         state.dataFans->fans(state.dataWaterThermalTanks->HPWaterHeater(HPNum).FanNum)->simulate(state, true, _, _);
   12002              : 
   12003          216 :                         DXCoils::SimDXCoil(state,
   12004           72 :                                            state.dataWaterThermalTanks->HPWaterHeater(HPNum).DXCoilName,
   12005              :                                            HVAC::CompressorOp::On,
   12006              :                                            true,
   12007           72 :                                            state.dataWaterThermalTanks->HPWaterHeater(HPNum).DXCoilNum,
   12008              :                                            HVAC::FanOp::Cycling,
   12009          144 :                                            1.0);
   12010              : 
   12011           72 :                         state.dataFans->fans(state.dataWaterThermalTanks->HPWaterHeater(HPNum).FanNum)->simulate(state, true, _, _);
   12012              :                     }
   12013              : 
   12014           72 :                     this->MaxCapacity = state.dataDXCoils->HPWHHeatingCapacity;
   12015           72 :                     this->MinCapacity = state.dataDXCoils->HPWHHeatingCapacity;
   12016           72 :                     this->Efficiency = state.dataDXCoils->HPWHHeatingCOP;
   12017              :                 }
   12018              : 
   12019           72 :                 if (FirstTimeFlag) {
   12020            3 :                     RatedDXCoilTotalCapacity = state.dataHVACGlobal->DXCoilTotalCapacity;
   12021            3 :                     FirstTimeFlag = false;
   12022              :                 }
   12023              : 
   12024              :                 //       Switch the HPWH info with the tank info and call CalcWaterThermalTankMixed to get Standard Rating
   12025              :                 //       (backup element is assumed to be disabled during the rating procedure)
   12026           72 :                 this->SourceMassFlowRate = 0.0;
   12027           72 :                 this->OnCycParaLoad = state.dataWaterThermalTanks->HPWaterHeater(HPNum).OnCycParaLoad;
   12028           72 :                 this->OffCycParaLoad = state.dataWaterThermalTanks->HPWaterHeater(HPNum).OffCycParaLoad;
   12029           72 :                 this->OffCycParaFracToTank = 0.0;
   12030           72 :                 this->OnCycParaFracToTank = 0.0;
   12031           72 :                 this->PLFCurve = state.dataWaterThermalTanks->HPWaterHeater(HPNum).DXCoilPLFFPLR;
   12032              : 
   12033           72 :                 if (this->WaterThermalTankType == DataPlant::PlantEquipmentType::WtrHeaterMixed) {
   12034           72 :                     if (this->Efficiency > 0.0) this->CalcWaterThermalTankMixed(state);
   12035              : 
   12036            0 :                 } else if (this->WaterThermalTankType == DataPlant::PlantEquipmentType::WtrHeaterStratified) {
   12037            0 :                     if (this->Efficiency > 0.0) this->CalcWaterThermalTankStratified(state);
   12038              :                 }
   12039              : 
   12040              :                 //       reset the water heater data to original values
   12041           72 :                 this->MaxCapacity = state.dataWaterThermalTanks->HPWaterHeater(HPNum).BackupElementCapacity;
   12042           72 :                 this->MinCapacity = state.dataWaterThermalTanks->HPWaterHeater(HPNum).BackupElementCapacity;
   12043           72 :                 this->Efficiency = state.dataWaterThermalTanks->HPWaterHeater(HPNum).BackupElementEfficiency;
   12044           72 :                 this->OnCycParaLoad = state.dataWaterThermalTanks->HPWaterHeater(HPNum).WHOnCycParaLoad;
   12045           72 :                 this->OffCycParaLoad = state.dataWaterThermalTanks->HPWaterHeater(HPNum).WHOffCycParaLoad;
   12046           72 :                 this->OnCycParaFracToTank = state.dataWaterThermalTanks->HPWaterHeater(HPNum).WHOnCycParaFracToTank;
   12047           72 :                 this->OffCycParaFracToTank = state.dataWaterThermalTanks->HPWaterHeater(HPNum).WHOffCycParaFracToTank;
   12048           72 :                 this->PLFCurve = state.dataWaterThermalTanks->HPWaterHeater(HPNum).WHPLFCurve;
   12049              :             }
   12050              : 
   12051         1536 :             FuelEnergy_loc += (this->FuelRate + this->OffCycParaFuelRate + this->OnCycParaFuelRate) * SecInTimeStep;
   12052              : 
   12053              :         } // Step
   12054              : 
   12055            5 :         if (this->FirstRecoveryDone && this->FirstRecoveryFuel > 0.0) {
   12056              :             // Calculate Recovery Efficiency based on energy used to recover from the first draw
   12057              :             // FirstRecoveryFuel is recorded inside the CalcWaterThermalTank subroutine
   12058            3 :             RecoveryEfficiency = DrawMass * Psychrometrics::CPHW(57.2222) * (57.2222 - 14.4444) / this->FirstRecoveryFuel;
   12059              : 
   12060              :             // Calculate Energy Factor based on total energy (including parasitics) used over entire test
   12061            3 :             EnergyFactor = TotalDrawMass * Psychrometrics::CPHW(57.2222) * (57.2222 - 14.4444) / FuelEnergy_loc;
   12062              : 
   12063              :         } else {
   12064            2 :             RecoveryEfficiency = 0.0;
   12065            2 :             EnergyFactor = 0.0;
   12066              :             // If this a regular tank, or an HPWH that's not an Integrated one
   12067            2 :             if ((this->HeatPumpNum == 0) || !state.dataWaterThermalTanks->HPWaterHeater(this->HeatPumpNum).bIsIHP) {
   12068            4 :                 ShowWarningError(
   12069              :                     state,
   12070            4 :                     format("Water heater = {}:  Recovery Efficiency and Energy Factor could not be calculated during the test for standard ratings",
   12071            2 :                            this->Name));
   12072            6 :                 ShowContinueError(state, "Setpoint was never recovered and/or heater never turned on");
   12073              :             }
   12074              :         }
   12075              : 
   12076            5 :     } else {
   12077              : 
   12078              :         // Storage-only tank
   12079            2 :         RecoveryEfficiency = 0.0;
   12080            2 :         EnergyFactor = 0.0;
   12081              : 
   12082              :     } // WaterThermalTank(WaterThermalTankNum)%MaxCapacity > 0.0
   12083              : 
   12084              :     // create predefined report
   12085              :     // Store values for the input verification and summary report
   12086            7 :     std::string equipName;
   12087            7 :     if (this->HeatPumpNum == 0) {
   12088            4 :         equipName = this->Name;
   12089            4 :         OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchSWHType, equipName, this->Type);
   12090            4 :         OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchSWHVol, equipName, this->Volume);
   12091            4 :         OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchSWHHeatIn, equipName, this->MaxCapacity);
   12092            4 :         OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchSWHThEff, equipName, this->Efficiency);
   12093            4 :         OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchSWHRecEff, equipName, RecoveryEfficiency);
   12094            4 :         OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchSWHEnFac, equipName, EnergyFactor);
   12095              :     } else {
   12096            3 :         equipName = state.dataWaterThermalTanks->HPWaterHeater(this->HeatPumpNum).Name;
   12097            6 :         OutputReportPredefined::PreDefTableEntry(
   12098            6 :             state, state.dataOutRptPredefined->pdchSWHType, equipName, state.dataWaterThermalTanks->HPWaterHeater(this->HeatPumpNum).Type);
   12099            3 :         OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchSWHVol, equipName, this->Volume);
   12100            3 :         if (bIsVSCoil) {
   12101            0 :             OutputReportPredefined::PreDefTableEntry(
   12102            0 :                 state, state.dataOutRptPredefined->pdchSWHHeatIn, equipName, state.dataVariableSpeedCoils->VSHPWHHeatingCapacity);
   12103              :         } else {
   12104            9 :             OutputReportPredefined::PreDefTableEntry(
   12105            6 :                 state, state.dataOutRptPredefined->pdchSWHHeatIn, equipName, state.dataDXCoils->HPWHHeatingCapacity);
   12106              :         }
   12107            3 :         OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchSWHThEff, equipName, this->Efficiency);
   12108            3 :         OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchSWHRecEff, equipName, RecoveryEfficiency);
   12109            3 :         OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchSWHEnFac, equipName, EnergyFactor);
   12110              :     }
   12111              : 
   12112              :     // Write test results
   12113            7 :     if (this->HeatPumpNum == 0) {
   12114              :         Real64 MaxCapacity_loc;
   12115            4 :         if (this->WaterThermalTankType == DataPlant::PlantEquipmentType::WtrHeaterStratified) {
   12116            1 :             if (this->StratifiedControlMode == PriorityControlMode::MasterSlave) {
   12117            1 :                 MaxCapacity_loc = max(this->MaxCapacity, this->MaxCapacity2);
   12118              :             } else { // PrioritySimultaneous
   12119            0 :                 MaxCapacity_loc = this->MaxCapacity + this->MaxCapacity2;
   12120              :             }
   12121              :         } else { // WaterHeaterMixed
   12122            3 :             MaxCapacity_loc = this->MaxCapacity;
   12123              :         }
   12124              : 
   12125              :         static constexpr std::string_view Format_720("Water Heater Information,{},{},{:.4T},{:.1T},{:.3T},{:.4T}\n");
   12126            4 :         print(state.files.eio, Format_720, this->Type, this->Name, this->Volume, MaxCapacity_loc, RecoveryEfficiency, EnergyFactor);
   12127              :     } else {
   12128              :         static constexpr std::string_view Format_721("Heat Pump Water Heater Information,{},{},{:.4T},{:.1T},{:.3T},{:.4T},{:.0T}\n");
   12129            3 :         print(state.files.eio,
   12130              :               Format_721,
   12131            3 :               state.dataWaterThermalTanks->HPWaterHeater(this->HeatPumpNum).Type,
   12132            3 :               state.dataWaterThermalTanks->HPWaterHeater(this->HeatPumpNum).Name,
   12133            3 :               this->Volume,
   12134            3 :               state.dataDXCoils->HPWHHeatingCapacity,
   12135              :               RecoveryEfficiency,
   12136              :               EnergyFactor,
   12137              :               RatedDXCoilTotalCapacity);
   12138              :     }
   12139              : 
   12140            7 :     this->AlreadyRated = true;
   12141            7 : }
   12142              : 
   12143            0 : void WaterThermalTankData::ReportCWTankInits(EnergyPlusData &state)
   12144              : {
   12145              : 
   12146              :     // SUBROUTINE INFORMATION:
   12147              :     //       AUTHOR         B. Griffith
   12148              :     //       DATE WRITTEN   March 2009
   12149              :     //       MODIFIED       na
   12150              :     //       RE-ENGINEERED  na
   12151              : 
   12152              :     // PURPOSE OF THIS SUBROUTINE:
   12153              :     // send chilled water tank info to EIO
   12154              : 
   12155            0 :     if (this->myOneTimeInitFlag) {
   12156            0 :         this->setupOutputVars(state);
   12157            0 :         this->myOneTimeInitFlag = false;
   12158              :     }
   12159              : 
   12160            0 :     if (this->AlreadyReported) { // bail we already did this one
   12161            0 :         return;
   12162              :     }
   12163              : 
   12164              :     static constexpr std::string_view Format_728("Chilled Water Tank Information,{},{},{:.4T},{:.4T},{:.4T}\n");
   12165            0 :     print(state.files.eio, Format_728, this->Type, this->Name, this->Volume, this->UseDesignVolFlowRate, this->SourceDesignVolFlowRate);
   12166              : 
   12167            0 :     this->AlreadyReported = true;
   12168              : }
   12169              : 
   12170            7 : Real64 WaterThermalTankData::FindStratifiedTankSensedTemp(EnergyPlusData &state, bool UseAverage)
   12171              : {
   12172              : 
   12173              :     // FUNCTION INFORMATION:
   12174              :     //       AUTHOR         B. Griffith
   12175              :     //       DATE WRITTEN   March 2012
   12176              :     //       MODIFIED       na
   12177              :     //       RE-ENGINEERED  Noel Merket, April 2015
   12178              : 
   12179              :     // PURPOSE OF THIS FUNCTION:
   12180              :     // find tank temperature depending on how sensed
   12181              : 
   12182              :     // FUNCTION LOCAL VARIABLE DECLARATIONS:
   12183            7 :     HeatPumpWaterHeaterData const &HPWH = state.dataWaterThermalTanks->HPWaterHeater(this->HeatPumpNum);
   12184              :     Real64 ControlSensor1Temp;
   12185              :     Real64 ControlSensor2Temp;
   12186              : 
   12187            7 :     if (UseAverage) {
   12188            1 :         ControlSensor1Temp = this->Node(HPWH.ControlSensor1Node).TempAvg;
   12189            1 :         ControlSensor2Temp = this->Node(HPWH.ControlSensor2Node).TempAvg;
   12190              :     } else {
   12191            6 :         ControlSensor1Temp = this->Node(HPWH.ControlSensor1Node).Temp;
   12192            6 :         ControlSensor2Temp = this->Node(HPWH.ControlSensor2Node).Temp;
   12193              :     }
   12194              : 
   12195            7 :     Real64 SensedTemp = ControlSensor1Temp * HPWH.ControlSensor1Weight + ControlSensor2Temp * HPWH.ControlSensor2Weight;
   12196              : 
   12197            7 :     return SensedTemp;
   12198              : }
   12199              : 
   12200          361 : Real64 WaterThermalTankData::getDeadBandTemp()
   12201              : {
   12202          361 :     if (this->IsChilledWaterTank) {
   12203            1 :         return (this->SetPointTemp + this->DeadBandDeltaTemp);
   12204              :     } else {
   12205          360 :         return (this->SetPointTemp - this->DeadBandDeltaTemp);
   12206              :     }
   12207              : }
   12208            0 : void WaterThermalTankData::oneTimeInit(EnergyPlusData &state)
   12209              : {
   12210            0 :     if (this->myOneTimeInitFlag) {
   12211            0 :         this->setupOutputVars(state);
   12212            0 :         this->myOneTimeInitFlag = false;
   12213              :     }
   12214            0 : }
   12215              : 
   12216            6 : void WaterThermalTankData::setBackupElementCapacity(EnergyPlusData &state)
   12217              : {
   12218              :     // Fix for #9001: The BackupElementCapacity was not being reset from the autosize value (-99999) which resulted in
   12219              :     // negative electric consumption.  Using a test for any negative numbers here instead of just -99999 for safety.
   12220              :     // Only reset the backup element capacity if a problem has been occured.
   12221            6 :     if (this->HeatPumpNum > 0) {
   12222            3 :         if (state.dataWaterThermalTanks->HPWaterHeater(this->HeatPumpNum).HPWHType == DataPlant::PlantEquipmentType::HeatPumpWtrHeaterWrapped) return;
   12223            2 :         if (state.dataWaterThermalTanks->HPWaterHeater(this->HeatPumpNum).BackupElementCapacity < 0.0) {
   12224            1 :             state.dataWaterThermalTanks->HPWaterHeater(this->HeatPumpNum).BackupElementCapacity = this->MaxCapacity;
   12225              :         }
   12226            3 :     } else if (this->DesuperheaterNum > 0) {
   12227            2 :         if (state.dataWaterThermalTanks->WaterHeaterDesuperheater(this->DesuperheaterNum).BackupElementCapacity < 0.0) {
   12228            1 :             state.dataWaterThermalTanks->WaterHeaterDesuperheater(this->DesuperheaterNum).BackupElementCapacity = this->MaxCapacity;
   12229              :         }
   12230              :     }
   12231              : }
   12232              : 
   12233           42 : bool GetHeatPumpWaterHeaterNodeNumber(EnergyPlusData &state, int const NodeNumber)
   12234              : {
   12235              :     // PURPOSE OF THIS FUNCTION:
   12236              :     // Check if a node is used by a heat pump water heater
   12237              :     // and can be excluded from an airflow network.
   12238              : 
   12239              :     // Return value
   12240              :     bool HeatPumpWaterHeaterNodeException;
   12241              : 
   12242              :     int HeatPumpWaterHeaterIndex;
   12243              : 
   12244           42 :     if (state.dataWaterThermalTanks->getWaterThermalTankInputFlag) {
   12245            5 :         GetWaterThermalTankInput(state);
   12246            5 :         state.dataWaterThermalTanks->getWaterThermalTankInputFlag = false;
   12247              :     }
   12248              : 
   12249           42 :     HeatPumpWaterHeaterNodeException = false;
   12250              : 
   12251           46 :     for (HeatPumpWaterHeaterIndex = 1; HeatPumpWaterHeaterIndex <= state.dataWaterThermalTanks->numHeatPumpWaterHeater; ++HeatPumpWaterHeaterIndex) {
   12252              : 
   12253              :         // Get heat pump water heater data
   12254            6 :         HeatPumpWaterHeaterData &HPWH = state.dataWaterThermalTanks->HPWaterHeater(HeatPumpWaterHeaterIndex);
   12255              : 
   12256              :         // "Zone and outdoor air" configuration is expected break the conservation of mass
   12257            6 :         if (HPWH.InletAirConfiguration != WTTAmbientTemp::ZoneAndOA) {
   12258              : 
   12259              :             // Air outlet node
   12260            3 :             if (NodeNumber == HPWH.HeatPumpAirOutletNode) {
   12261            0 :                 HeatPumpWaterHeaterNodeException = true;
   12262            0 :                 break;
   12263              :             }
   12264              : 
   12265              :             // Air inlet node
   12266            3 :             if (NodeNumber == HPWH.HeatPumpAirInletNode) {
   12267            0 :                 HeatPumpWaterHeaterNodeException = true;
   12268            0 :                 break;
   12269              :             }
   12270              : 
   12271              :             // Get fan inlet node index
   12272            3 :             int FanInletNodeIndex = state.dataFans->fans(HPWH.FanNum)->inletNodeNum;
   12273              : 
   12274              :             // Fan inlet node
   12275            3 :             if (NodeNumber == FanInletNodeIndex) {
   12276            1 :                 HeatPumpWaterHeaterNodeException = true;
   12277            1 :                 break;
   12278              :             }
   12279              : 
   12280              :             // Fan outlet node
   12281            2 :             if (NodeNumber == HPWH.FanOutletNode) {
   12282            1 :                 HeatPumpWaterHeaterNodeException = true;
   12283            1 :                 break;
   12284              :             }
   12285              : 
   12286              :             // Outside air node
   12287            1 :             if (NodeNumber == HPWH.OutsideAirNode) {
   12288            0 :                 HeatPumpWaterHeaterNodeException = true;
   12289            0 :                 break;
   12290              :             }
   12291              : 
   12292              :             // Exhaust air node
   12293            1 :             if (NodeNumber == HPWH.ExhaustAirNode) {
   12294            0 :                 HeatPumpWaterHeaterNodeException = true;
   12295            0 :                 break;
   12296              :             }
   12297              :         }
   12298              :     }
   12299              : 
   12300           42 :     return HeatPumpWaterHeaterNodeException;
   12301              : }
   12302              : 
   12303            0 : int getHeatPumpWaterHeaterIndex(EnergyPlusData &state, std::string_view CompName)
   12304              : {
   12305            0 :     if (state.dataWaterThermalTanks->getWaterThermalTankInputFlag) {
   12306            0 :         GetWaterThermalTankInput(state);
   12307            0 :         state.dataWaterThermalTanks->getWaterThermalTankInputFlag = false;
   12308              :     }
   12309              : 
   12310            0 :     for (int HPNum = 1; HPNum <= state.dataWaterThermalTanks->numHeatPumpWaterHeater; ++HPNum) {
   12311            0 :         if (Util::SameString(state.dataWaterThermalTanks->HPWaterHeater(HPNum).Name, CompName)) {
   12312            0 :             return HPNum;
   12313              :         }
   12314              :     }
   12315              : 
   12316            0 :     return 0;
   12317              : }
   12318              : 
   12319              : } // namespace EnergyPlus::WaterThermalTanks
        

Generated by: LCOV version 2.0-1