LCOV - code coverage report
Current view: top level - EnergyPlus - WaterThermalTanks.cc (source / functions) Coverage Total Hit
Test: lcov.output.filtered Lines: 67.2 % 6679 4485
Test Date: 2025-06-02 07:23:51 Functions: 92.9 % 70 65

            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          146 : PlantComponent *WaterThermalTankData::factory(EnergyPlusData &state, std::string const &objectName)
     136              : {
     137              :     // Process the input data
     138          146 :     if (state.dataWaterThermalTanks->getWaterThermalTankInputFlag) {
     139           12 :         GetWaterThermalTankInput(state);
     140           12 :         state.dataWaterThermalTanks->getWaterThermalTankInputFlag = false;
     141              :     }
     142              : 
     143              :     // Now look for this object in the list
     144          167 :     for (auto &tank : state.dataWaterThermalTanks->WaterThermalTank) {
     145          167 :         if (tank.Name == objectName) {
     146          146 :             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          791 : void WaterThermalTankData::onInitLoopEquip(EnergyPlusData &state, const PlantLocation &calledFromLocation)
     156              : {
     157          791 :     this->initialize(state, true);
     158          791 :     this->MinePlantStructForInfo(state);
     159          791 :     if (calledFromLocation.loopNum > 0) {
     160          791 :         if ((this->SrcSidePlantLoc.loopNum == calledFromLocation.loopNum) || (this->UseSidePlantLoc.loopNum == calledFromLocation.loopNum)) {
     161          786 :             this->SizeTankForDemandSide(state);
     162          786 :             this->SizeDemandSidePlantConnections(state);
     163          786 :             this->SizeSupplySidePlantConnections(state, calledFromLocation.loopNum);
     164          786 :             this->SizeTankForSupplySide(state);
     165              :         } else {
     166            5 :             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          786 :     if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
     176          170 :         if (!this->IsChilledWaterTank) {
     177          160 :             this->CalcStandardRatings(state);
     178              :         } else {
     179           10 :             this->ReportCWTankInits(state);
     180              :         }
     181              :     }
     182              : }
     183              : 
     184          741 : void WaterThermalTankData::getDesignCapacities([[maybe_unused]] EnergyPlusData &state,
     185              :                                                [[maybe_unused]] const PlantLocation &calledFromLocation,
     186              :                                                Real64 &MaxLoad,
     187              :                                                Real64 &MinLoad,
     188              :                                                Real64 &OptLoad)
     189              : {
     190          741 :     MinLoad = 0.0;
     191          741 :     MaxLoad = this->MaxCapacity;
     192          741 :     OptLoad = this->MaxCapacity;
     193          741 : }
     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         5022 : int getHPTankIDX(EnergyPlusData &state, std::string_view CompName, int &CompIndex)
     235              : {
     236         5022 :     if (state.dataWaterThermalTanks->getWaterThermalTankInputFlag) {
     237            0 :         GetWaterThermalTankInput(state);
     238            0 :         state.dataWaterThermalTanks->getWaterThermalTankInputFlag = false;
     239              :     }
     240              : 
     241              :     int CompNum;
     242              : 
     243         5022 :     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         5022 :         CompNum = CompIndex;
     251         5022 :         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         5022 :         if (state.dataWaterThermalTanks->HPWaterHeater(CompNum).CheckHPWHEquipName) {
     259            1 :             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            1 :             state.dataWaterThermalTanks->HPWaterHeater(CompNum).CheckHPWHEquipName = false;
     267              :         }
     268              :     }
     269              : 
     270         5022 :     return CompNum;
     271              : }
     272              : 
     273      5928161 : 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      5928161 :     this->callerLoopNum = calledFromLocation.loopNum;
     284              : 
     285      5928161 :     this->oneTimeInit(state);
     286              : 
     287      5928161 :     if (this->MyOneTimeFlagWH) {
     288          178 :         this->MyOneTimeFlagWH = false;
     289              :     } else {
     290      5927983 :         if (this->MyTwoTimeFlagWH) {
     291          178 :             this->MinePlantStructForInfo(state); // call it again to get control types filled out
     292          178 :             this->MyTwoTimeFlagWH = false;
     293              :         }
     294              :     }
     295      5928161 :     this->UseSideLoadRequested = std::abs(CurLoad);
     296     11528958 :     if (this->UseSidePlantLoc.loopNum > 0 && this->UseSidePlantLoc.loopSideNum != DataPlant::LoopSideLocation::Invalid &&
     297      5600797 :         !state.dataGlobal->KickOffSimulation) {
     298      5579848 :         this->UseCurrentFlowLock = state.dataPlnt->PlantLoop(this->UseSidePlantLoc.loopNum).LoopSide(this->UseSidePlantLoc.loopSideNum).FlowLock;
     299              :     } else {
     300       348313 :         this->UseCurrentFlowLock = DataPlant::FlowLock::Locked;
     301              :     }
     302      5928161 :     this->initialize(state, FirstHVACIteration);
     303              :     //       Plant connected water heaters may have a desuperheater heating coil attached
     304      5928161 :     if (this->DesuperheaterNum == 0) {
     305      5898677 :         if ((this->WaterThermalTankType == DataPlant::PlantEquipmentType::WtrHeaterMixed) ||
     306       628188 :             (this->WaterThermalTankType == DataPlant::PlantEquipmentType::ChilledWaterTankMixed)) {
     307      5660149 :             this->CalcWaterThermalTankMixed(state);
     308       238528 :         } else if ((this->WaterThermalTankType == DataPlant::PlantEquipmentType::WtrHeaterStratified) ||
     309       155633 :                    (this->WaterThermalTankType == DataPlant::PlantEquipmentType::ChilledWaterTankStratified)) {
     310       238528 :             this->CalcWaterThermalTankStratified(state);
     311              :         }
     312        29484 :     } else if (this->DesuperheaterNum > 0) {
     313        29484 :         this->CalcDesuperheaterWaterHeater(state, FirstHVACIteration);
     314              :     }
     315      5928161 :     this->UpdateWaterThermalTank(state);
     316      5928161 :     this->ReportWaterThermalTank(state);
     317              :     // reset the caller loop num to mimic what was happening in PlantLoopEquip
     318      5928161 :     this->callerLoopNum = 0;
     319      5928161 : }
     320              : 
     321           10 : PlantComponent *HeatPumpWaterHeaterData::factory(EnergyPlusData &state, std::string const &objectName)
     322              : {
     323              :     // Process the input data
     324           10 :     if (state.dataWaterThermalTanks->getWaterThermalTankInputFlag) {
     325            3 :         GetWaterThermalTankInput(state);
     326            3 :         state.dataWaterThermalTanks->getWaterThermalTankInputFlag = false;
     327              :     }
     328              : 
     329              :     // Now look for this object in the list
     330           28 :     for (auto &HPWH : state.dataWaterThermalTanks->HPWaterHeater) {
     331           28 :         if (HPWH.Name == objectName) {
     332           10 :             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           50 : void HeatPumpWaterHeaterData::onInitLoopEquip(EnergyPlusData &state, const PlantLocation &calledFromLocation)
     342              : {
     343           50 :     auto &Tank = state.dataWaterThermalTanks->WaterThermalTank(this->WaterHeaterTankNum);
     344           50 :     Tank.onInitLoopEquip(state, calledFromLocation);
     345           50 : }
     346              : 
     347           50 : void HeatPumpWaterHeaterData::getDesignCapacities([[maybe_unused]] EnergyPlusData &state,
     348              :                                                   [[maybe_unused]] const PlantLocation &calledFromLocation,
     349              :                                                   Real64 &MaxLoad,
     350              :                                                   Real64 &MinLoad,
     351              :                                                   Real64 &OptLoad)
     352              : {
     353           50 :     MinLoad = 0.0;
     354           50 :     MaxLoad = this->Capacity;
     355           50 :     OptLoad = this->Capacity;
     356           50 : }
     357              : 
     358       408468 : 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       408468 :     auto &Tank = state.dataWaterThermalTanks->WaterThermalTank(this->WaterHeaterTankNum);
     368              : 
     369              :     // set caller loop num to mimic what plantloopequip was doing
     370       408468 :     Tank.callerLoopNum = calledFromLocation.loopNum;
     371              : 
     372       408468 :     if (this->myOneTimeInitFlag) {
     373           23 :         if (Tank.myOneTimeInitFlag) {
     374           23 :             Tank.setupOutputVars(state);
     375           23 :             Tank.myOneTimeInitFlag = false;
     376              :         }
     377           23 :         this->myOneTimeInitFlag = false;
     378              :     }
     379              : 
     380       408468 :     if (this->MyOneTimeFlagHP) {
     381           23 :         this->MyOneTimeFlagHP = false;
     382              :     } else {
     383       408445 :         if (this->MyTwoTimeFlagHP) {
     384           23 :             Tank.MinePlantStructForInfo(state); // call it again to get control types filled out
     385           23 :             this->MyTwoTimeFlagHP = false;
     386              :         }
     387              :     }
     388       408468 :     Tank.UseSideLoadRequested = std::abs(CurLoad);
     389       742982 :     if (Tank.UseSidePlantLoc.loopNum > 0 && Tank.UseSidePlantLoc.loopSideNum != DataPlant::LoopSideLocation::Invalid &&
     390       334514 :         !state.dataGlobal->KickOffSimulation) {
     391       333134 :         Tank.UseCurrentFlowLock = state.dataPlnt->PlantLoop(Tank.UseSidePlantLoc.loopNum).LoopSide(Tank.UseSidePlantLoc.loopSideNum).FlowLock;
     392              :     } else {
     393        75334 :         Tank.UseCurrentFlowLock = DataPlant::FlowLock::Locked;
     394              :     }
     395              : 
     396       408468 :     Tank.initialize(state, FirstHVACIteration);
     397              : 
     398       408468 :     int InletNodeSav = this->HeatPumpAirInletNode;
     399       408468 :     int OutletNodeSav = this->HeatPumpAirOutletNode;
     400       408468 :     int DXINletNodeSav = this->DXCoilAirInletNode;
     401       408468 :     int IHPFanIndexSav = this->FanNum;
     402       408468 :     std::string IHPFanNameSave = this->FanName;
     403       408468 :     HVAC::FanPlace IHPFanplaceSav = this->fanPlace;
     404              : 
     405       408468 :     if (this->bIsIHP) // pass the tank indexes to the IHP object
     406              :     {
     407        10046 :         state.dataIntegratedHP->IntegratedHeatPumps(this->DXCoilNum).WHtankType = this->HPWHType;
     408        10046 :         state.dataIntegratedHP->IntegratedHeatPumps(this->DXCoilNum).WHtankName = this->Name;
     409        10046 :         state.dataIntegratedHP->IntegratedHeatPumps(this->DXCoilNum).WHtankID = this->WaterHeaterTankNum;
     410        10046 :         IntegratedHeatPump::IHPOperationMode IHPMode = IntegratedHeatPump::GetCurWorkMode(state, this->DXCoilNum);
     411              : 
     412        10046 :         if ((IntegratedHeatPump::IHPOperationMode::DedicatedWaterHtg == IHPMode) ||
     413         7643 :             (IntegratedHeatPump::IHPOperationMode::SpaceClgDedicatedWaterHtg == IHPMode) ||
     414         7643 :             (IntegratedHeatPump::IHPOperationMode::SHDWHElecHeatOff == IHPMode) ||
     415              :             (IntegratedHeatPump::IHPOperationMode::SHDWHElecHeatOn == IHPMode)) { // default is to specify the air nodes for SCWH mode
     416         2403 :             bool bDWHCoilReading = false;
     417         2403 :             this->HeatPumpAirInletNode =
     418         2403 :                 VariableSpeedCoils::GetCoilInletNodeVariableSpeed(state,
     419              :                                                                   "COIL:WATERHEATING:AIRTOWATERHEATPUMP:VARIABLESPEED",
     420         2403 :                                                                   state.dataIntegratedHP->IntegratedHeatPumps(this->DXCoilNum).DWHCoilName,
     421              :                                                                   bDWHCoilReading);
     422         2403 :             this->HeatPumpAirOutletNode =
     423         2403 :                 VariableSpeedCoils::GetCoilOutletNodeVariableSpeed(state,
     424              :                                                                    "COIL:WATERHEATING:AIRTOWATERHEATPUMP:VARIABLESPEED",
     425         2403 :                                                                    state.dataIntegratedHP->IntegratedHeatPumps(this->DXCoilNum).DWHCoilName,
     426              :                                                                    bDWHCoilReading);
     427         2403 :             this->DXCoilAirInletNode = this->HeatPumpAirInletNode;
     428         2403 :         } else // default is to input outdoor fan to the HPWH
     429              :         {
     430         7643 :             this->FanNum = state.dataIntegratedHP->IntegratedHeatPumps(this->DXCoilNum).IDFanID;
     431         7643 :             this->FanName = state.dataIntegratedHP->IntegratedHeatPumps(this->DXCoilNum).IDFanName;
     432         7643 :             this->fanPlace = state.dataIntegratedHP->IntegratedHeatPumps(this->DXCoilNum).fanPlace;
     433              :         }
     434              :     }
     435              : 
     436       408468 :     Tank.CalcHeatPumpWaterHeater(state, FirstHVACIteration);
     437       408468 :     Tank.UpdateWaterThermalTank(state);
     438       408468 :     Tank.ReportWaterThermalTank(state);
     439              : 
     440       408468 :     this->HeatPumpAirInletNode = InletNodeSav;
     441       408468 :     this->HeatPumpAirOutletNode = OutletNodeSav;
     442       408468 :     this->DXCoilAirInletNode = DXINletNodeSav;
     443       408468 :     this->FanNum = IHPFanIndexSav;
     444       408468 :     this->FanName = IHPFanNameSave;
     445       408468 :     this->fanPlace = IHPFanplaceSav;
     446              :     // reset caller loop num to 0 to mimic what plantloopequip was doing
     447       408468 :     Tank.callerLoopNum = 0;
     448       408468 : }
     449            0 : void HeatPumpWaterHeaterData::oneTimeInit([[maybe_unused]] EnergyPlusData &state)
     450              : {
     451            0 : }
     452              : 
     453      1410236 : 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      1410236 :     if (state.dataWaterThermalTanks->getWaterThermalTankInputFlag) {
     474            7 :         GetWaterThermalTankInput(state);
     475            7 :         state.dataWaterThermalTanks->getWaterThermalTankInputFlag = false;
     476              :     }
     477              : 
     478      1410236 :     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      1410236 :     if (Tank.StandAlone) {
     482       284584 :         bool localRunFlag = true;
     483       284584 :         PlantLocation A(0, DataPlant::LoopSideLocation::Invalid, 0, 0);
     484       284584 :         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      1125652 :     } 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       124634 :         auto &HPWaterHtr = state.dataWaterThermalTanks->HPWaterHeater(Tank.HeatPumpNum);
     494              : 
     495       124634 :         if (HPWaterHtr.StandAlone &&
     496        68688 :             (HPWaterHtr.InletAirConfiguration == WTTAmbientTemp::OutsideAir || HPWaterHtr.InletAirConfiguration == WTTAmbientTemp::Schedule)) {
     497        36856 :             bool LocalRunFlag = true;
     498        36856 :             PlantLocation A(0, DataPlant::LoopSideLocation::Invalid, 0, 0);
     499        36856 :             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      1001018 :     } else if (Tank.DesuperheaterNum > 0) {
     505        29484 :         if (state.dataWaterThermalTanks->WaterHeaterDesuperheater(Tank.DesuperheaterNum).StandAlone) {
     506        29484 :             bool localRunFlag = true;
     507        29484 :             PlantLocation A(0, DataPlant::LoopSideLocation::Invalid, 0, 0);
     508        29484 :             Tank.simulate(state, A, FirstHVACIteration, MyLoad, localRunFlag);
     509              :         }
     510              :     }
     511      1410236 : }
     512              : 
     513       124230 : 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       124230 :     if (state.dataWaterThermalTanks->getWaterThermalTankInputFlag) {
     534            0 :         GetWaterThermalTankInput(state);
     535            0 :         state.dataWaterThermalTanks->getWaterThermalTankInputFlag = false;
     536              :     }
     537              : 
     538              :     // Find the correct Heat Pump Water Heater
     539              :     int HeatPumpNum;
     540       124230 :     if (CompIndex == 0) {
     541           10 :         HeatPumpNum = Util::FindItemInList(CompName, state.dataWaterThermalTanks->HPWaterHeater);
     542           10 :         if (HeatPumpNum == 0) {
     543            0 :             ShowFatalError(state, format("SimHeatPumpWaterHeater: Unit not found={}", CompName));
     544              :         }
     545           10 :         CompIndex = HeatPumpNum;
     546              :     } else {
     547       124220 :         HeatPumpNum = CompIndex;
     548       124220 :         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       124230 :     if (state.dataGlobal->DoingSizing) {
     563           10 :         return;
     564              :     }
     565              : 
     566              :     // For HPWHs, StandAlone means not connected to a plant loop (use nodes are not used, source nodes are connected to a HPWH)
     567       124220 :     if (state.dataWaterThermalTanks->HPWaterHeater(HeatPumpNum).StandAlone) {
     568        32076 :         bool LocalRunFlag = true;
     569              :         Real64 MyLoad;
     570              : 
     571        32076 :         PlantLocation A(0, DataPlant::LoopSideLocation::Invalid, 0, 0);
     572        32076 :         state.dataWaterThermalTanks->HPWaterHeater(HeatPumpNum).simulate(state, A, FirstHVACIteration, MyLoad, LocalRunFlag);
     573              : 
     574        32076 :         SensLoadMet = state.dataWaterThermalTanks->HPWaterHeater(HeatPumpNum).HPWaterHeaterSensibleCapacity;
     575        32076 :         LatLoadMet = state.dataWaterThermalTanks->HPWaterHeater(HeatPumpNum).HPWaterHeaterLatentCapacity;
     576              :     } else {
     577              :         // HPWH is plant connected and will get simulated when called from plant SimWaterThermalTank, but need to update loads met here
     578        92144 :         SensLoadMet = state.dataWaterThermalTanks->HPWaterHeater(HeatPumpNum).HPWaterHeaterSensibleCapacity;
     579        92144 :         LatLoadMet = state.dataWaterThermalTanks->HPWaterHeater(HeatPumpNum).HPWaterHeaterLatentCapacity;
     580              :     }
     581              : }
     582              : 
     583      2828408 : void CalcWaterThermalTankZoneGains(EnergyPlusData &state)
     584              : {
     585              : 
     586              :     // SUBROUTINE INFORMATION:
     587              :     //       AUTHOR         Peter Graham Ellis
     588              :     //       DATE WRITTEN   March 2005
     589              :     //       MODIFIED       B. Griffith November 2011, new internal gains structure
     590              :     //       RE-ENGINEERED  na
     591              : 
     592              :     // PURPOSE OF THIS SUBROUTINE:
     593              :     // Calculates the zone internal gains due to water heater skin losses during sizing.
     594              :     // initializes gains to zone at begin environment.
     595              : 
     596              :     // METHODOLOGY EMPLOYED:
     597              :     // Sums the tank losses from all of the water heaters in the zone to add as a gain to the zone.
     598              :     // Now used to determine tank losses during sizing.  Internal gains are summed in a centralized way now
     599              : 
     600      2828408 :     if (state.dataWaterThermalTanks->numWaterThermalTank == 0) {
     601              : 
     602      2294948 :         if (!state.dataGlobal->DoingSizing) {
     603      1690040 :             return;
     604              :         } else {
     605       604908 :             if (state.dataWaterThermalTanks->getWaterThermalTankInputFlag) {
     606          428 :                 GetWaterThermalTankInput(state);
     607          428 :                 state.dataWaterThermalTanks->getWaterThermalTankInputFlag = false;
     608              :             }
     609       604908 :             if (state.dataWaterThermalTanks->numWaterThermalTank == 0) {
     610       604794 :                 return;
     611              :             }
     612              :         }
     613              :     }
     614              : 
     615       533574 :     if (state.dataGlobal->BeginEnvrnFlag && state.dataWaterThermalTanks->calcWaterThermalTankZoneGainsMyEnvrnFlag) {
     616         3375 :         for (auto &e : state.dataWaterThermalTanks->WaterThermalTank) {
     617         2018 :             e.AmbientZoneGain = 0.0;
     618         2018 :             e.FuelEnergy = 0.0;
     619         2018 :             e.OffCycParaFuelEnergy = 0.0;
     620         2018 :             e.OnCycParaFuelEnergy = 0.0;
     621              :         }
     622         1357 :         state.dataWaterThermalTanks->calcWaterThermalTankZoneGainsMyEnvrnFlag = false;
     623              :     }
     624              : 
     625       533574 :     if (!state.dataGlobal->BeginEnvrnFlag) {
     626       532217 :         state.dataWaterThermalTanks->calcWaterThermalTankZoneGainsMyEnvrnFlag = true;
     627              :     }
     628              : 
     629      1246939 :     for (int WaterThermalTankNum = 1; WaterThermalTankNum <= state.dataWaterThermalTanks->numWaterThermalTank; ++WaterThermalTankNum) {
     630       713365 :         auto &Tank = state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum);
     631       713365 :         if (Tank.AmbientTempZone == 0) {
     632       471594 :             continue;
     633              :         }
     634       241771 :         auto const &thisZoneHB = state.dataZoneTempPredictorCorrector->zoneHeatBalance(Tank.AmbientTempZone);
     635       241771 :         if (state.dataGlobal->DoingSizing) {
     636              :             // Initialize tank temperature to setpoint
     637              :             // (use HPWH or Desuperheater heating coil set point if applicable)
     638       107106 :             Sched::Schedule *sched = nullptr;
     639       107106 :             if (Tank.HeatPumpNum > 0) {
     640        14844 :                 sched = state.dataWaterThermalTanks->HPWaterHeater(Tank.HeatPumpNum).setptTempSched;
     641        92262 :             } else if (Tank.DesuperheaterNum > 0) {
     642         1350 :                 sched = state.dataWaterThermalTanks->WaterHeaterDesuperheater(Tank.DesuperheaterNum).setptTempSched;
     643              :             } else {
     644        90912 :                 sched = Tank.setptTempSched;
     645              :             }
     646              : 
     647       107106 :             Real64 TankTemp = (sched != nullptr) ? sched->getCurrentVal() : 20.0;
     648              : 
     649       107106 :             Real64 QLossToZone = 0.0;
     650       107106 :             switch (Tank.WaterThermalTankType) {
     651        90918 :             case DataPlant::PlantEquipmentType::WtrHeaterMixed: {
     652        90918 :                 QLossToZone = max(Tank.OnCycLossCoeff * Tank.OnCycLossFracToZone, Tank.OffCycLossCoeff * Tank.OffCycLossFracToZone) *
     653        90918 :                               (TankTemp - thisZoneHB.MAT);
     654        90918 :                 break;
     655              :             }
     656         8094 :             case DataPlant::PlantEquipmentType::WtrHeaterStratified: {
     657         8094 :                 QLossToZone = max(Tank.Node(1).OnCycLossCoeff * Tank.SkinLossFracToZone, Tank.Node(1).OffCycLossCoeff * Tank.SkinLossFracToZone) *
     658         8094 :                               (TankTemp - thisZoneHB.MAT);
     659         8094 :                 break;
     660              :             }
     661         4050 :             case DataPlant::PlantEquipmentType::ChilledWaterTankMixed: {
     662         4050 :                 QLossToZone = Tank.OffCycLossCoeff * Tank.OffCycLossFracToZone * (TankTemp - thisZoneHB.MAT);
     663         4050 :                 break;
     664              :             }
     665         4044 :             case DataPlant::PlantEquipmentType::ChilledWaterTankStratified: {
     666         4044 :                 QLossToZone = Tank.Node(1).OffCycLossCoeff * Tank.SkinLossFracToZone * (TankTemp - thisZoneHB.MAT);
     667         4044 :                 break;
     668              :             }
     669            0 :             default:
     670            0 :                 break;
     671              :             }
     672       107106 :             Tank.AmbientZoneGain = QLossToZone;
     673              :         }
     674              :     }
     675              : }
     676              : 
     677            6 : bool getDesuperHtrInput(EnergyPlusData &state)
     678              : {
     679            6 :     bool ErrorsFound = false;
     680              :     static constexpr std::string_view routineName = "getDesuperHtrInput";
     681              :     // Make local copies of IPShortCut because other getinputs might overwrite the ones in state <-- need to fix this idiom
     682            6 :     std::string cCurrentModuleObject = state.dataIPShortCut->cCurrentModuleObject;
     683            6 :     Array1D<std::string> cAlphaArgs = state.dataIPShortCut->cAlphaArgs;
     684            6 :     Array1D<Real64> rNumericArgs = state.dataIPShortCut->rNumericArgs;
     685            6 :     Array1D<bool> lNumericFieldBlanks = state.dataIPShortCut->lNumericFieldBlanks;
     686            6 :     Array1D<bool> lAlphaFieldBlanks = state.dataIPShortCut->lAlphaFieldBlanks;
     687            6 :     Array1D<std::string> cAlphaFieldNames = state.dataIPShortCut->cAlphaFieldNames;
     688            6 :     Array1D<std::string> cNumericFieldNames = state.dataIPShortCut->cNumericFieldNames;
     689              : 
     690            6 :     cCurrentModuleObject = cCoilDesuperheater;
     691           12 :     for (int DesuperheaterNum = 1; DesuperheaterNum <= state.dataWaterThermalTanks->numWaterHeaterDesuperheater; ++DesuperheaterNum) {
     692              :         int NumAlphas;
     693              :         int NumNums;
     694              :         int IOStat;
     695            6 :         state.dataInputProcessing->inputProcessor->getObjectItem(state,
     696              :                                                                  cCurrentModuleObject,
     697              :                                                                  DesuperheaterNum,
     698              :                                                                  cAlphaArgs,
     699              :                                                                  NumAlphas,
     700              :                                                                  rNumericArgs,
     701              :                                                                  NumNums,
     702              :                                                                  IOStat,
     703              :                                                                  lNumericFieldBlanks,
     704              :                                                                  lAlphaFieldBlanks,
     705              :                                                                  cAlphaFieldNames,
     706              :                                                                  cNumericFieldNames);
     707              : 
     708            6 :         ErrorObjectHeader eoh{routineName, cCurrentModuleObject, cAlphaArgs(1)};
     709              : 
     710            6 :         Util::IsNameEmpty(state, cAlphaArgs(1), cCurrentModuleObject, ErrorsFound);
     711              : 
     712              :         // ErrorsFound will be set to True if problem was found, left untouched otherwise
     713            6 :         GlobalNames::VerifyUniqueCoilName(state, cCurrentModuleObject, cAlphaArgs(1), ErrorsFound, cCurrentModuleObject + " Name");
     714              : 
     715            6 :         auto &DesupHtr = state.dataWaterThermalTanks->WaterHeaterDesuperheater(DesuperheaterNum);
     716              : 
     717            6 :         DesupHtr.Name = cAlphaArgs(1);
     718            6 :         DesupHtr.Type = cCurrentModuleObject;
     719              : 
     720              :         //       convert availability schedule name to pointer
     721            6 :         if (lAlphaFieldBlanks(2)) {
     722            0 :             DesupHtr.availSched = Sched::GetScheduleAlwaysOn(state);
     723            6 :         } else if ((DesupHtr.availSched = Sched::GetSchedule(state, cAlphaArgs(2))) == nullptr) {
     724            0 :             ShowSevereItemNotFound(state, eoh, cAlphaFieldNames(2), cAlphaArgs(2));
     725            0 :             ErrorsFound = true;
     726              :         }
     727              : 
     728              :         // convert schedule name to pointer
     729            6 :         if (lAlphaFieldBlanks(3)) {
     730            6 :         } else if ((DesupHtr.setptTempSched = Sched::GetSchedule(state, cAlphaArgs(3))) == nullptr) {
     731            0 :             ShowSevereItemNotFound(state, eoh, cAlphaFieldNames(3), cAlphaArgs(3));
     732            0 :             ErrorsFound = true;
     733              :         }
     734              : 
     735            6 :         DesupHtr.DeadBandTempDiff = rNumericArgs(1);
     736            6 :         if (DesupHtr.DeadBandTempDiff <= 0.0 || DesupHtr.DeadBandTempDiff > 20.0) {
     737            0 :             ShowSevereError(state,
     738            0 :                             format("{} = {}: {} must be > 0 and <= 20. {} = {:.1T}",
     739              :                                    cCurrentModuleObject,
     740            0 :                                    DesupHtr.Name,
     741              :                                    cNumericFieldNames(1),
     742              :                                    cNumericFieldNames(1),
     743              :                                    rNumericArgs(1)));
     744            0 :             ErrorsFound = true;
     745              :         }
     746              : 
     747              :         // Error limits on heat reclaim efficiency applied after source type identified
     748              : 
     749            6 :         DesupHtr.RatedInletWaterTemp = rNumericArgs(3);
     750            6 :         DesupHtr.RatedOutdoorAirTemp = rNumericArgs(4);
     751            6 :         DesupHtr.MaxInletWaterTemp = rNumericArgs(5);
     752              : 
     753            6 :         if (!lAlphaFieldBlanks(4)) {
     754            6 :             DesupHtr.HEffFTemp = Curve::GetCurveIndex(state, cAlphaArgs(4));
     755            6 :             if (DesupHtr.HEffFTemp == 0) {
     756            0 :                 ShowSevereError(state,
     757            0 :                                 format("{} = {}:  {} not found = {}", cCurrentModuleObject, DesupHtr.Name, cAlphaFieldNames(4), cAlphaArgs(4)));
     758            0 :                 ErrorsFound = true;
     759              :             } else {
     760           12 :                 ErrorsFound |= Curve::CheckCurveDims(state,
     761              :                                                      DesupHtr.HEffFTemp,   // Curve index
     762              :                                                      {2},                  // Valid dimensions
     763              :                                                      routineName,          // Routine name
     764              :                                                      cCurrentModuleObject, // Object Type
     765              :                                                      DesupHtr.Name,        // Object Name
     766            6 :                                                      cAlphaFieldNames(4)); // Field Name
     767            6 :                 if (!ErrorsFound) {
     768            6 :                     if (DesupHtr.HEffFTemp > 0) {
     769            6 :                         Real64 HEffFTemp = min(
     770            6 :                             1.0, max(0.0, Curve::CurveValue(state, DesupHtr.HEffFTemp, DesupHtr.RatedInletWaterTemp, DesupHtr.RatedOutdoorAirTemp)));
     771            6 :                         if (std::abs(HEffFTemp - 1.0) > 0.05) {
     772            0 :                             ShowWarningError(state, format("{}, \"{}\":", cCurrentModuleObject, DesupHtr.Name));
     773            0 :                             ShowContinueError(state, format("The {} should be normalized ", cAlphaFieldNames(4)));
     774            0 :                             ShowContinueError(state, format(" to 1.0 at the rating point. Curve output at the rating point = {:.3T}", HEffFTemp));
     775            0 :                             ShowContinueError(state, " The simulation continues using the user-specified curve.");
     776              :                         }
     777              :                     }
     778              :                 }
     779              :             }
     780              :         }
     781              : 
     782            6 :         DesupHtr.WaterInletNode = NodeInputManager::GetOnlySingleNode(state,
     783            6 :                                                                       cAlphaArgs(5),
     784              :                                                                       ErrorsFound,
     785              :                                                                       DataLoopNode::ConnectionObjectType::CoilWaterHeatingDesuperheater,
     786            6 :                                                                       cAlphaArgs(1),
     787              :                                                                       DataLoopNode::NodeFluidType::Water,
     788              :                                                                       DataLoopNode::ConnectionType::Inlet,
     789              :                                                                       NodeInputManager::CompFluidStream::Primary,
     790              :                                                                       DataLoopNode::ObjectIsParent);
     791              : 
     792            6 :         DesupHtr.WaterOutletNode = NodeInputManager::GetOnlySingleNode(state,
     793            6 :                                                                        cAlphaArgs(6),
     794              :                                                                        ErrorsFound,
     795              :                                                                        DataLoopNode::ConnectionObjectType::CoilWaterHeatingDesuperheater,
     796            6 :                                                                        cAlphaArgs(1),
     797              :                                                                        DataLoopNode::NodeFluidType::Water,
     798              :                                                                        DataLoopNode::ConnectionType::Outlet,
     799              :                                                                        NodeInputManager::CompFluidStream::Primary,
     800              :                                                                        DataLoopNode::ObjectIsParent);
     801              : 
     802            6 :         DesupHtr.InletNodeName1 = cAlphaArgs(5);
     803            6 :         DesupHtr.OutletNodeName1 = cAlphaArgs(6);
     804              : 
     805            6 :         DesupHtr.TankType = cAlphaArgs(7);
     806              : 
     807            6 :         if (!Util::SameString(DesupHtr.TankType, cMixedWHModuleObj) && !Util::SameString(DesupHtr.TankType, cStratifiedWHModuleObj)) {
     808              : 
     809            0 :             ShowSevereError(state, format("{} = {}:", cCurrentModuleObject, state.dataWaterThermalTanks->HPWaterHeater(DesuperheaterNum).Name));
     810            0 :             ShowContinueError(state, format("Desuperheater can only be used with {} or {}.", cMixedWHModuleObj, cStratifiedWHModuleObj));
     811            0 :             ErrorsFound = true;
     812              :         }
     813              : 
     814            6 :         DesupHtr.TankName = cAlphaArgs(8);
     815              : 
     816              :         // Set up comp set for water side nodes (reverse inlet/outlet for water heater)
     817            6 :         BranchNodeConnections::SetUpCompSets(state, DesupHtr.Type, DesupHtr.Name, DesupHtr.TankType, DesupHtr.TankName, cAlphaArgs(6), cAlphaArgs(5));
     818              : 
     819            6 :         std::string const heatSourceObjType = cAlphaArgs(9);
     820              : 
     821           11 :         if ((Util::SameString(heatSourceObjType, "Refrigeration:Condenser:AirCooled")) ||
     822           11 :             (Util::SameString(heatSourceObjType, "Refrigeration:Condenser:EvaporativeCooled")) ||
     823           11 :             (Util::SameString(heatSourceObjType, "Refrigeration:Condenser:WaterCooled"))) {
     824            1 :             if (lNumericFieldBlanks(2)) {
     825            0 :                 DesupHtr.HeatReclaimRecoveryEff = 0.8;
     826              :             } else {
     827            1 :                 DesupHtr.HeatReclaimRecoveryEff = rNumericArgs(2);
     828            1 :                 if (DesupHtr.HeatReclaimRecoveryEff <= 0.0 || DesupHtr.HeatReclaimRecoveryEff > 0.9) {
     829            0 :                     ShowSevereError(state,
     830            0 :                                     format("{} = {}: {} must be > 0.0 and <= 0.9, Efficiency = {:.3T}",
     831              :                                            cCurrentModuleObject,
     832            0 :                                            DesupHtr.Name,
     833              :                                            cNumericFieldNames(2),
     834            0 :                                            DesupHtr.HeatReclaimRecoveryEff));
     835            0 :                     ErrorsFound = true;
     836              :                 }
     837              :             } // Blank Num(2)
     838              :         } else { // max is 0.3 for all other sources
     839            5 :             if (lNumericFieldBlanks(2)) {
     840            0 :                 DesupHtr.HeatReclaimRecoveryEff = 0.25;
     841              :             } else {
     842            5 :                 DesupHtr.HeatReclaimRecoveryEff = rNumericArgs(2);
     843            5 :                 if (DesupHtr.HeatReclaimRecoveryEff <= 0.0 || DesupHtr.HeatReclaimRecoveryEff > 0.3) {
     844            0 :                     ShowSevereError(state,
     845            0 :                                     format("{} = {}: {} must be > 0.0 and <= 0.3, {} = {:.3T}",
     846              :                                            cCurrentModuleObject,
     847            0 :                                            DesupHtr.Name,
     848              :                                            cNumericFieldNames(2),
     849              :                                            cNumericFieldNames(2),
     850            0 :                                            DesupHtr.HeatReclaimRecoveryEff));
     851            0 :                     ErrorsFound = true;
     852              :                 }
     853              :             } // Blank Num(2)
     854              :         } // setting limits on heat recovery efficiency
     855              : 
     856              :         //       Find the Refrigeration equipment index associated with the desuperheater heating coil.
     857            6 :         bool errFlag = false;
     858            6 :         DesupHtr.HeatingSourceType = heatSourceObjType;
     859            6 :         DesupHtr.HeatingSourceName = cAlphaArgs(10);
     860            6 :         if (Util::SameString(heatSourceObjType, "Refrigeration:CompressorRack")) {
     861            0 :             DesupHtr.ReclaimHeatingSource = ReclaimHeatObjectType::CompressorRackRefrigeratedCase;
     862            0 :             for (int RackNum = 1; RackNum <= state.dataRefrigCase->NumRefrigeratedRacks; ++RackNum) {
     863            0 :                 if (!Util::SameString(state.dataHeatBal->HeatReclaimRefrigeratedRack(RackNum).Name, cAlphaArgs(10))) {
     864            0 :                     continue;
     865              :                 }
     866            0 :                 DesupHtr.ReclaimHeatingSourceIndexNum = RackNum;
     867            0 :                 if (allocated(state.dataHeatBal->HeatReclaimRefrigeratedRack)) {
     868              :                     DataHeatBalance::HeatReclaimDataBase &HeatReclaim =
     869            0 :                         state.dataHeatBal->HeatReclaimRefrigeratedRack(DesupHtr.ReclaimHeatingSourceIndexNum);
     870            0 :                     if (!allocated(HeatReclaim.WaterHeatingDesuperheaterReclaimedHeat)) {
     871            0 :                         HeatReclaim.WaterHeatingDesuperheaterReclaimedHeat.allocate(state.dataWaterThermalTanks->numWaterHeaterDesuperheater);
     872            0 :                         for (auto &num : HeatReclaim.WaterHeatingDesuperheaterReclaimedHeat) {
     873            0 :                             num = 0.0;
     874              :                         }
     875              :                     }
     876            0 :                     DesupHtr.ValidSourceType = true;
     877            0 :                     HeatReclaim.ReclaimEfficiencyTotal += DesupHtr.HeatReclaimRecoveryEff;
     878            0 :                     if (HeatReclaim.ReclaimEfficiencyTotal > 0.3) {
     879            0 :                         ShowSevereError(
     880              :                             state,
     881            0 :                             format("{} = {}:  sum of heat reclaim recovery efficiencies from the same source coil: \"{}\" cannot be over 0.3",
     882              :                                    cCurrentModuleObject,
     883            0 :                                    DesupHtr.Name,
     884            0 :                                    DesupHtr.HeatingSourceName));
     885            0 :                         ErrorsFound = true;
     886              :                     }
     887              :                 }
     888            0 :                 break;
     889              :             }
     890           11 :         } else if ((Util::SameString(heatSourceObjType, "Refrigeration:Condenser:AirCooled")) ||
     891           11 :                    (Util::SameString(heatSourceObjType, "Refrigeration:Condenser:EvaporativeCooled")) ||
     892           11 :                    (Util::SameString(heatSourceObjType, "Refrigeration:Condenser:WaterCooled"))) {
     893            1 :             DesupHtr.ReclaimHeatingSource = ReclaimHeatObjectType::CondenserRefrigeration;
     894            2 :             for (int CondNum = 1; CondNum <= state.dataRefrigCase->NumRefrigCondensers; ++CondNum) {
     895            2 :                 if (!Util::SameString(state.dataHeatBal->HeatReclaimRefrigCondenser(CondNum).Name, cAlphaArgs(10))) {
     896            1 :                     continue;
     897              :                 }
     898            1 :                 DesupHtr.ReclaimHeatingSourceIndexNum = CondNum;
     899            1 :                 if (allocated(state.dataHeatBal->HeatReclaimRefrigCondenser)) {
     900              :                     DataHeatBalance::HeatReclaimDataBase &HeatReclaim =
     901            1 :                         state.dataHeatBal->HeatReclaimRefrigCondenser(DesupHtr.ReclaimHeatingSourceIndexNum);
     902            1 :                     if (!allocated(HeatReclaim.WaterHeatingDesuperheaterReclaimedHeat)) {
     903            1 :                         HeatReclaim.WaterHeatingDesuperheaterReclaimedHeat.allocate(state.dataWaterThermalTanks->numWaterHeaterDesuperheater);
     904            2 :                         for (auto &num : HeatReclaim.WaterHeatingDesuperheaterReclaimedHeat) {
     905            1 :                             num = 0.0;
     906              :                         }
     907              :                     }
     908            1 :                     DesupHtr.ValidSourceType = true;
     909            1 :                     HeatReclaim.ReclaimEfficiencyTotal += DesupHtr.HeatReclaimRecoveryEff;
     910            1 :                     if (HeatReclaim.ReclaimEfficiencyTotal > 0.9) {
     911            0 :                         ShowSevereError(
     912              :                             state,
     913            0 :                             format("{} = {}:  sum of heat reclaim recovery efficiencies from the same source coil: \"{}\" cannot be over 0.9",
     914              :                                    cCurrentModuleObject,
     915            0 :                                    DesupHtr.Name,
     916            0 :                                    DesupHtr.HeatingSourceName));
     917            0 :                         ErrorsFound = true;
     918              :                     }
     919              :                 }
     920            1 :                 break;
     921              :             }
     922            8 :         } else if (Util::SameString(heatSourceObjType, "Coil:Cooling:DX:SingleSpeed") ||
     923            6 :                    Util::SameString(heatSourceObjType, "Coil:Cooling:DX:TwoSpeed") ||
     924           11 :                    Util::SameString(heatSourceObjType, "Coil:Cooling:DX:MultiSpeed") ||
     925            8 :                    Util::SameString(heatSourceObjType, "Coil:Cooling:DX:TwoStageWithHumidityControlMode")) {
     926              : 
     927            2 :             if (Util::SameString(heatSourceObjType, "Coil:Cooling:DX:SingleSpeed")) {
     928            2 :                 DesupHtr.ReclaimHeatingSource = ReclaimHeatObjectType::DXCooling;
     929            0 :             } else if (Util::SameString(heatSourceObjType, "Coil:Cooling:DX:TwoStageWithHumidityControlMode")) {
     930            0 :                 DesupHtr.ReclaimHeatingSource = ReclaimHeatObjectType::DXMultiMode;
     931              :             } else {
     932            0 :                 DesupHtr.ReclaimHeatingSource = ReclaimHeatObjectType::DXMultiSpeed;
     933              :             }
     934            2 :             DXCoils::GetDXCoilIndex(state, DesupHtr.HeatingSourceName, DesupHtr.ReclaimHeatingSourceIndexNum, errFlag, cCurrentModuleObject);
     935            2 :             if (allocated(state.dataHeatBal->HeatReclaimDXCoil)) {
     936            2 :                 DataHeatBalance::HeatReclaimDataBase &HeatReclaim = state.dataHeatBal->HeatReclaimDXCoil(DesupHtr.ReclaimHeatingSourceIndexNum);
     937            2 :                 if (!allocated(HeatReclaim.WaterHeatingDesuperheaterReclaimedHeat)) {
     938            2 :                     HeatReclaim.WaterHeatingDesuperheaterReclaimedHeat.allocate(state.dataWaterThermalTanks->numWaterHeaterDesuperheater);
     939            4 :                     for (auto &num : HeatReclaim.WaterHeatingDesuperheaterReclaimedHeat) {
     940            2 :                         num = 0.0;
     941              :                     }
     942              :                 }
     943            2 :                 DesupHtr.ValidSourceType = true;
     944            2 :                 HeatReclaim.ReclaimEfficiencyTotal += DesupHtr.HeatReclaimRecoveryEff;
     945            2 :                 if (HeatReclaim.ReclaimEfficiencyTotal > 0.3) {
     946            0 :                     ShowSevereError(state,
     947            0 :                                     format("{} = {}:  sum of heat reclaim recovery efficiencies from the same source coil: \"{}\" cannot be over 0.3",
     948              :                                            cCurrentModuleObject,
     949            0 :                                            DesupHtr.Name,
     950            0 :                                            DesupHtr.HeatingSourceName));
     951            0 :                     ErrorsFound = true;
     952              :                 }
     953              :             }
     954            5 :         } else if (Util::SameString(heatSourceObjType, "Coil:Cooling:DX:VariableSpeed") ||
     955            5 :                    Util::SameString(heatSourceObjType, "Coil:Cooling:WaterToAirHeatPump:VariableSpeedEquationFit")) {
     956              : 
     957            1 :             if (Util::SameString(heatSourceObjType, "Coil:Cooling:DX:VariableSpeed")) {
     958            1 :                 DesupHtr.ReclaimHeatingSource = ReclaimHeatObjectType::DXVariableCooling;
     959              :             } else {
     960            0 :                 DesupHtr.ReclaimHeatingSource = ReclaimHeatObjectType::AirWaterHeatPumpVSEQ;
     961              :             }
     962            1 :             DesupHtr.ReclaimHeatingSourceIndexNum = VariableSpeedCoils::GetCoilIndexVariableSpeed(state, heatSourceObjType, cAlphaArgs(10), errFlag);
     963            1 :             if (allocated(state.dataHeatBal->HeatReclaimVS_Coil)) {
     964            1 :                 DataHeatBalance::HeatReclaimDataBase &HeatReclaim = state.dataHeatBal->HeatReclaimVS_Coil(DesupHtr.ReclaimHeatingSourceIndexNum);
     965            1 :                 if (!allocated(HeatReclaim.WaterHeatingDesuperheaterReclaimedHeat)) {
     966            1 :                     HeatReclaim.WaterHeatingDesuperheaterReclaimedHeat.allocate(state.dataWaterThermalTanks->numWaterHeaterDesuperheater);
     967            2 :                     for (auto &num : HeatReclaim.WaterHeatingDesuperheaterReclaimedHeat) {
     968            1 :                         num = 0.0;
     969              :                     }
     970              :                 }
     971            1 :                 DesupHtr.ValidSourceType = true;
     972            1 :                 HeatReclaim.ReclaimEfficiencyTotal += DesupHtr.HeatReclaimRecoveryEff;
     973            1 :                 if (HeatReclaim.ReclaimEfficiencyTotal > 0.3) {
     974            0 :                     ShowSevereError(state,
     975            0 :                                     format("{} = {}:  sum of heat reclaim recovery efficiencies from the same source coil: \"{}\" cannot be over 0.3",
     976              :                                            cCurrentModuleObject,
     977            0 :                                            DesupHtr.Name,
     978            0 :                                            DesupHtr.HeatingSourceName));
     979            0 :                     ErrorsFound = true;
     980              :                 }
     981              :             }
     982            2 :         } else if (Util::SameString(heatSourceObjType, "Coil:Cooling:WaterToAirHeatPump:EquationFit")) {
     983            1 :             DesupHtr.ReclaimHeatingSource = ReclaimHeatObjectType::AirWaterHeatPumpEQ;
     984            1 :             DesupHtr.ReclaimHeatingSourceIndexNum = WaterToAirHeatPumpSimple::GetCoilIndex(state, heatSourceObjType, cAlphaArgs(10), errFlag);
     985            1 :             if (allocated(state.dataHeatBal->HeatReclaimSimple_WAHPCoil)) {
     986              :                 DataHeatBalance::HeatReclaimDataBase &HeatReclaim =
     987            1 :                     state.dataHeatBal->HeatReclaimSimple_WAHPCoil(DesupHtr.ReclaimHeatingSourceIndexNum);
     988            1 :                 if (!allocated(HeatReclaim.WaterHeatingDesuperheaterReclaimedHeat)) {
     989            1 :                     HeatReclaim.WaterHeatingDesuperheaterReclaimedHeat.allocate(state.dataWaterThermalTanks->numWaterHeaterDesuperheater);
     990            2 :                     for (auto &num : HeatReclaim.WaterHeatingDesuperheaterReclaimedHeat) {
     991            1 :                         num = 0.0;
     992              :                     }
     993              :                 }
     994            1 :                 DesupHtr.ValidSourceType = true;
     995            1 :                 HeatReclaim.ReclaimEfficiencyTotal += DesupHtr.HeatReclaimRecoveryEff;
     996            1 :                 if (HeatReclaim.ReclaimEfficiencyTotal > 0.3) {
     997            0 :                     ShowSevereError(state,
     998            0 :                                     format("{} = {}:  sum of heat reclaim recovery efficiencies from the same source coil: \"{}\" cannot be over 0.3",
     999              :                                            cCurrentModuleObject,
    1000            0 :                                            DesupHtr.Name,
    1001            0 :                                            DesupHtr.HeatingSourceName));
    1002            0 :                     ErrorsFound = true;
    1003              :                 }
    1004              :             }
    1005            1 :         } else if (Util::SameString(heatSourceObjType, "Coil:Cooling:DX")) {
    1006            1 :             DesupHtr.ReclaimHeatingSource = ReclaimHeatObjectType::CoilCoolingDX;
    1007            1 :             DesupHtr.ReclaimHeatingSourceIndexNum = CoilCoolingDX::factory(state, cAlphaArgs(10));
    1008            1 :             if (DesupHtr.ReclaimHeatingSourceIndexNum < 0) {
    1009            0 :                 ShowSevereError(
    1010              :                     state,
    1011            0 :                     format("{}={}, could not find desuperheater coil {}={}", cCurrentModuleObject, DesupHtr.Name, cAlphaArgs(9), cAlphaArgs(10)));
    1012            0 :                 ErrorsFound = true;
    1013              :             } else {
    1014              :                 DataHeatBalance::HeatReclaimDataBase &HeatReclaim =
    1015            1 :                     state.dataCoilCoolingDX->coilCoolingDXs[DesupHtr.ReclaimHeatingSourceIndexNum].reclaimHeat;
    1016            1 :                 if (!allocated(HeatReclaim.WaterHeatingDesuperheaterReclaimedHeat)) {
    1017            1 :                     HeatReclaim.WaterHeatingDesuperheaterReclaimedHeat.allocate(state.dataWaterThermalTanks->numWaterHeaterDesuperheater);
    1018            2 :                     for (auto &num : HeatReclaim.WaterHeatingDesuperheaterReclaimedHeat) {
    1019            1 :                         num = 0.0;
    1020              :                     }
    1021              :                 }
    1022            1 :                 DesupHtr.ValidSourceType = true;
    1023            1 :                 HeatReclaim.ReclaimEfficiencyTotal += DesupHtr.HeatReclaimRecoveryEff;
    1024            1 :                 if (HeatReclaim.ReclaimEfficiencyTotal > 0.3) {
    1025            0 :                     ShowSevereError(
    1026              :                         state,
    1027            0 :                         format("{}, \"{}\" sum of heat reclaim recovery efficiencies from the same source coil: \"{}\" cannot be over 0.3",
    1028              :                                cCurrentModuleObject,
    1029            0 :                                DesupHtr.Name,
    1030            0 :                                DesupHtr.HeatingSourceName));
    1031            0 :                     ErrorsFound = true;
    1032              :                 }
    1033              :             }
    1034              :         } else {
    1035            0 :             ShowSevereError(state, format("{} = {}:", cCurrentModuleObject, DesupHtr.Name));
    1036            0 :             ShowContinueError(state, " desuperheater can only be used with Coil:Cooling:DX:SingleSpeed, ");
    1037            0 :             ShowContinueError(state,
    1038              :                               " Coil:Cooling:DX:TwoSpeed, Coil:Cooling:DX:MultiSpeed, Coil:Cooling:DX:TwoStageWithHumidityControlMode, "
    1039              :                               "Coil:Cooling:DX:VariableSpeed, Coil:Cooling:WaterToAirHeatPump:VariableSpeedEquationFit, "
    1040              :                               "Coil:Cooling:WaterToAirHeatPump:EquationFit, Refrigeration:CompressorRack,");
    1041            0 :             ShowContinueError(state, " Refrigeration:Condenser:AirCooled ,Refrigeration:Condenser:EvaporativeCooled, ");
    1042            0 :             ShowContinueError(state, " or Refrigeration:Condenser:WaterCooled.");
    1043            0 :             ShowContinueError(state, format(" Invalid desuperheater heat source object: {} \"{}\"", heatSourceObjType, cAlphaArgs(10)));
    1044            0 :             ErrorsFound = true;
    1045              :         }
    1046            6 :         if (errFlag) {
    1047            0 :             ShowContinueError(state, format("...occurs in {}={}", cCurrentModuleObject, DesupHtr.Name));
    1048            0 :             ErrorsFound = true;
    1049              :         }
    1050              : 
    1051            6 :         if (DesupHtr.ReclaimHeatingSourceIndexNum == 0 && DesupHtr.ReclaimHeatingSource != ReclaimHeatObjectType::CoilCoolingDX) {
    1052            0 :             ShowSevereError(state,
    1053            0 :                             format("{}, \"{}\" desuperheater heat source object not found: {} \"{}\"",
    1054              :                                    cCurrentModuleObject,
    1055            0 :                                    DesupHtr.Name,
    1056              :                                    heatSourceObjType,
    1057              :                                    cAlphaArgs(10)));
    1058            0 :             ErrorsFound = true;
    1059              :         }
    1060              : 
    1061            6 :         DesupHtr.OperatingWaterFlowRate = rNumericArgs(6);
    1062            6 :         if (DesupHtr.OperatingWaterFlowRate <= 0.0) {
    1063            0 :             ShowSevereError(state,
    1064            0 :                             format("{} = {}: {} must be greater than 0. {} = {:.6T}",
    1065              :                                    cCurrentModuleObject,
    1066            0 :                                    DesupHtr.Name,
    1067              :                                    cNumericFieldNames(6),
    1068              :                                    cNumericFieldNames(6),
    1069              :                                    rNumericArgs(6)));
    1070            0 :             ErrorsFound = true;
    1071              :         }
    1072              : 
    1073            6 :         DesupHtr.PumpElecPower = rNumericArgs(7);
    1074            6 :         if (DesupHtr.PumpElecPower < 0.0) {
    1075            0 :             ShowSevereError(state,
    1076            0 :                             format("{} = {}: {} must be >= 0. {} = {:.2T}",
    1077              :                                    cCurrentModuleObject,
    1078            0 :                                    DesupHtr.Name,
    1079              :                                    cNumericFieldNames(7),
    1080              :                                    cNumericFieldNames(7),
    1081              :                                    rNumericArgs(7)));
    1082            0 :             ErrorsFound = true;
    1083              :         }
    1084              : 
    1085            6 :         if ((DesupHtr.PumpElecPower / DesupHtr.OperatingWaterFlowRate) > 7.9264e6) {
    1086            0 :             ShowWarningError(state,
    1087            0 :                              format("{} = {}: {} to {} ratio > 7.9264E6. {} to {} = {:.3T}",
    1088              :                                     cCurrentModuleObject,
    1089            0 :                                     DesupHtr.Name,
    1090              :                                     cNumericFieldNames(7),
    1091              :                                     cNumericFieldNames(6),
    1092              :                                     cNumericFieldNames(7),
    1093              :                                     cNumericFieldNames(6),
    1094            0 :                                     (DesupHtr.PumpElecPower / DesupHtr.OperatingWaterFlowRate)));
    1095            0 :             ShowContinueError(state, format(" Suggest reducing {} or increasing {}.", cNumericFieldNames(7), cNumericFieldNames(6)));
    1096            0 :             ShowContinueError(state, " The simulation will continue using the user defined values.");
    1097              :         }
    1098              : 
    1099            6 :         DesupHtr.PumpFracToWater = rNumericArgs(8);
    1100            6 :         if (DesupHtr.PumpFracToWater < 0.0 || DesupHtr.PumpFracToWater > 1.0) {
    1101            0 :             ShowSevereError(state,
    1102            0 :                             format("{} = {}: {} must be >= 0 or <= 1. {} = {:.3T}",
    1103              :                                    cCurrentModuleObject,
    1104            0 :                                    DesupHtr.Name,
    1105              :                                    cNumericFieldNames(8),
    1106              :                                    cNumericFieldNames(8),
    1107              :                                    rNumericArgs(8)));
    1108            0 :             ErrorsFound = true;
    1109              :         }
    1110              : 
    1111            6 :         DesupHtr.OnCycParaLoad = rNumericArgs(9);
    1112            6 :         if (DesupHtr.OnCycParaLoad < 0.0) {
    1113            0 :             ShowSevereError(state,
    1114            0 :                             format("{} = {}: {} must be >= 0. {} = {:.2T}",
    1115              :                                    cCurrentModuleObject,
    1116            0 :                                    DesupHtr.Name,
    1117              :                                    cNumericFieldNames(9),
    1118              :                                    cNumericFieldNames(9),
    1119              :                                    rNumericArgs(9)));
    1120            0 :             ErrorsFound = true;
    1121              :         }
    1122              : 
    1123            6 :         DesupHtr.OffCycParaLoad = rNumericArgs(10);
    1124            6 :         if (DesupHtr.OffCycParaLoad < 0.0) {
    1125            0 :             ShowSevereError(state,
    1126            0 :                             format("{} = {}: {} must be >= 0. {} = {:.2T}",
    1127              :                                    cCurrentModuleObject,
    1128            0 :                                    DesupHtr.Name,
    1129              :                                    cNumericFieldNames(10),
    1130              :                                    cNumericFieldNames(10),
    1131              :                                    rNumericArgs(10)));
    1132            0 :             ErrorsFound = true;
    1133              :         }
    1134            6 :     }
    1135              : 
    1136            6 :     if (ErrorsFound) {
    1137            0 :         ShowFatalError(state, format("Errors found in getting {} input. Preceding condition causes termination.", cCurrentModuleObject));
    1138              :     }
    1139              : 
    1140            6 :     return ErrorsFound;
    1141              : 
    1142            6 : } // namespace WaterThermalTanks
    1143              : 
    1144            9 : bool getHPWaterHeaterInput(EnergyPlusData &state)
    1145              : {
    1146              : 
    1147              :     static constexpr std::string_view routineName = "getHPWaterHeaterInput";
    1148            9 :     bool ErrorsFound = false;
    1149              : 
    1150            9 :     int const NumPumpedCondenser = state.dataInputProcessing->inputProcessor->getNumObjectsFound(
    1151              :         state, cHPWHPumpedCondenser); // number of WaterHeater:HeatPump:PumpedCondenser objects
    1152              :     int nAlphaOffset;                 // the difference of array location between alpha items between pumped and wrapped condensers
    1153              :     int nNumericOffset;               // the difference of array location between numeric items between pumped and wrapped condensers
    1154              :     int nNumPossibleNumericArgs;      // the number of possible numeric arguments in the idd
    1155              :     int nNumPossibleAlphaArgs;        // the number of possible numeric arguments in the idd
    1156              : 
    1157              :     // For looking up in IDF/epJSON, you need the index that corresponds to the actual object type (Pumped or Wrapped)
    1158              :     int HPWaterHeaterNumOfSpecificType;
    1159              : 
    1160           32 :     for (int HPWaterHeaterNum = 1; HPWaterHeaterNum <= state.dataWaterThermalTanks->numHeatPumpWaterHeater; ++HPWaterHeaterNum) {
    1161              : 
    1162              :         // Create reference to current HPWH object in array.
    1163           23 :         HeatPumpWaterHeaterData &HPWH = state.dataWaterThermalTanks->HPWaterHeater(HPWaterHeaterNum);
    1164              : 
    1165              :         // Initialize the offsets to zero
    1166           23 :         nAlphaOffset = 0;
    1167           23 :         nNumericOffset = 0;
    1168              : 
    1169              :         DataLoopNode::ConnectionObjectType objType;
    1170              : 
    1171           23 :         if (HPWaterHeaterNum <= NumPumpedCondenser) {
    1172              :             // Pumped Condenser
    1173           20 :             state.dataIPShortCut->cCurrentModuleObject = cHPWHPumpedCondenser;
    1174           20 :             objType = DataLoopNode::ConnectionObjectType::WaterHeaterHeatPumpPumpedCondenser;
    1175           20 :             HPWH.HPWHType = DataPlant::PlantEquipmentType::HeatPumpWtrHeaterPumped;
    1176           20 :             nNumPossibleAlphaArgs = 29;
    1177           20 :             nNumPossibleNumericArgs = 9;
    1178              :             // Actual index of Pumped type
    1179           20 :             HPWaterHeaterNumOfSpecificType = HPWaterHeaterNum;
    1180              :         } else {
    1181              :             // Wrapped Condenser
    1182            3 :             state.dataIPShortCut->cCurrentModuleObject = cHPWHWrappedCondenser;
    1183            3 :             objType = DataLoopNode::ConnectionObjectType::WaterHeaterHeatPumpWrappedCondenser;
    1184            3 :             HPWH.HPWHType = DataPlant::PlantEquipmentType::HeatPumpWtrHeaterWrapped;
    1185            3 :             nNumPossibleAlphaArgs = 27;
    1186            3 :             nNumPossibleNumericArgs = 10;
    1187              :             // Actual index of Wrapped type
    1188            3 :             HPWaterHeaterNumOfSpecificType = HPWaterHeaterNum - NumPumpedCondenser;
    1189              :         }
    1190              : 
    1191              :         int NumAlphas;
    1192              :         int NumNums;
    1193              :         int IOStat;
    1194           46 :         state.dataInputProcessing->inputProcessor->getObjectItem(state,
    1195           23 :                                                                  state.dataIPShortCut->cCurrentModuleObject,
    1196              :                                                                  HPWaterHeaterNumOfSpecificType,
    1197           23 :                                                                  state.dataIPShortCut->cAlphaArgs,
    1198              :                                                                  NumAlphas,
    1199           23 :                                                                  state.dataIPShortCut->rNumericArgs,
    1200              :                                                                  NumNums,
    1201              :                                                                  IOStat,
    1202           23 :                                                                  state.dataIPShortCut->lNumericFieldBlanks,
    1203           23 :                                                                  state.dataIPShortCut->lAlphaFieldBlanks,
    1204           23 :                                                                  state.dataIPShortCut->cAlphaFieldNames,
    1205           23 :                                                                  state.dataIPShortCut->cNumericFieldNames);
    1206              : 
    1207           23 :         ErrorObjectHeader eoh{routineName, state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)};
    1208              : 
    1209              :         // Copy those lists into C++ std::maps // Why, no really why?  This is really dumb
    1210           23 :         std::map<int, std::string> hpwhAlpha;
    1211           23 :         std::map<int, Real64> hpwhNumeric;
    1212           23 :         std::map<int, bool> hpwhAlphaBlank;
    1213           23 :         std::map<int, bool> hpwhNumericBlank;
    1214           23 :         std::map<int, std::string> hpwhAlphaFieldNames;
    1215           23 :         std::map<int, std::string> hpwhNumericFieldNames;
    1216          204 :         for (int i = 1; i <= NumNums; ++i) {
    1217          181 :             hpwhNumeric[i] = state.dataIPShortCut->rNumericArgs(i);
    1218          181 :             hpwhNumericBlank[i] = state.dataIPShortCut->lNumericFieldBlanks(i);
    1219          181 :             hpwhNumericFieldNames[i] = state.dataIPShortCut->cNumericFieldNames(i);
    1220              :         }
    1221           55 :         for (int i = NumNums + 1; i <= nNumPossibleNumericArgs; ++i) {
    1222           32 :             hpwhNumericBlank[i] = true;
    1223              :         }
    1224          642 :         for (int i = 1; i <= NumAlphas; ++i) {
    1225          619 :             hpwhAlpha[i] = state.dataIPShortCut->cAlphaArgs(i);
    1226          619 :             hpwhAlphaBlank[i] = state.dataIPShortCut->lAlphaFieldBlanks(i);
    1227          619 :             hpwhAlphaFieldNames[i] = state.dataIPShortCut->cAlphaFieldNames(i);
    1228              :         }
    1229           65 :         for (int i = NumAlphas + 1; i <= nNumPossibleAlphaArgs; ++i) {
    1230           42 :             hpwhAlphaBlank[i] = true;
    1231              :         }
    1232           23 :         Util::IsNameEmpty(state, hpwhAlpha[1], state.dataIPShortCut->cCurrentModuleObject, ErrorsFound);
    1233              : 
    1234              :         // Name and type
    1235           23 :         HPWH.Name = hpwhAlpha[1];
    1236           23 :         HPWH.Type = state.dataIPShortCut->cCurrentModuleObject;
    1237              : 
    1238              :         // Availability Schedule
    1239              :         // convert schedule name to pointer
    1240           23 :         if (hpwhAlphaBlank[2]) {
    1241            0 :             HPWH.availSched = Sched::GetScheduleAlwaysOn(state);
    1242           23 :         } else if ((HPWH.availSched = Sched::GetSchedule(state, hpwhAlpha[2])) == nullptr) {
    1243            0 :             ShowSevereItemNotFound(state, eoh, hpwhAlphaFieldNames[2], hpwhAlpha[2]);
    1244            0 :             ErrorsFound = true;
    1245              :         }
    1246              : 
    1247              :         // Compressor Setpoint Temperature Schedule
    1248              :         // convert schedule name to pointer
    1249           23 :         if (hpwhAlphaBlank[3]) {
    1250            0 :             ShowSevereEmptyField(state, eoh, hpwhAlphaFieldNames[3]);
    1251            0 :             ErrorsFound = true;
    1252           23 :         } else if ((HPWH.setptTempSched = Sched::GetSchedule(state, hpwhAlpha[3])) == nullptr) {
    1253            0 :             ShowSevereItemNotFound(state, eoh, hpwhAlphaFieldNames[3], hpwhAlpha[3]);
    1254            0 :             ErrorsFound = true;
    1255              :         }
    1256              : 
    1257              :         // Dead Band Temperature Difference
    1258           23 :         HPWH.DeadBandTempDiff = hpwhNumeric[1 + nNumericOffset];
    1259           23 :         if (HPWH.DeadBandTempDiff <= 0.0 || HPWH.DeadBandTempDiff > 20.0) {
    1260            0 :             ShowSevereError(state, format("{}=\"{}\", ", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    1261            0 :             ShowContinueError(state,
    1262            0 :                               format("{}{}",
    1263            0 :                                      hpwhNumericFieldNames[1 + nNumericOffset],
    1264            0 :                                      format(" difference must be > 0 and <= 20. Dead band = {:.1T}", hpwhNumeric[1 + nNumericOffset])));
    1265            0 :             ErrorsFound = true;
    1266              :         }
    1267              : 
    1268           23 :         if (HPWH.HPWHType == DataPlant::PlantEquipmentType::HeatPumpWtrHeaterPumped) {
    1269              : 
    1270              :             // Condenser Inlet/Outlet Nodes
    1271           20 :             HPWH.CondWaterInletNode = NodeInputManager::GetOnlySingleNode(state,
    1272           20 :                                                                           hpwhAlpha[4],
    1273              :                                                                           ErrorsFound,
    1274              :                                                                           objType,
    1275           20 :                                                                           HPWH.Name,
    1276              :                                                                           DataLoopNode::NodeFluidType::Water,
    1277              :                                                                           DataLoopNode::ConnectionType::Inlet,
    1278              :                                                                           NodeInputManager::CompFluidStream::Secondary,
    1279              :                                                                           DataLoopNode::ObjectIsParent);
    1280           20 :             HPWH.InletNodeName1 = hpwhAlpha[4];
    1281           20 :             HPWH.CondWaterOutletNode = NodeInputManager::GetOnlySingleNode(state,
    1282           20 :                                                                            hpwhAlpha[5],
    1283              :                                                                            ErrorsFound,
    1284              :                                                                            objType,
    1285           20 :                                                                            HPWH.Name,
    1286              :                                                                            DataLoopNode::NodeFluidType::Water,
    1287              :                                                                            DataLoopNode::ConnectionType::Outlet,
    1288              :                                                                            NodeInputManager::CompFluidStream::Secondary,
    1289              :                                                                            DataLoopNode::ObjectIsParent);
    1290           20 :             HPWH.OutletNodeName1 = hpwhAlpha[5];
    1291              : 
    1292              :             // Condenser Water Flow Rate
    1293           20 :             HPWH.OperatingWaterFlowRate = hpwhNumeric[2];
    1294           20 :             if (HPWH.OperatingWaterFlowRate <= 0.0 && hpwhNumeric[2] != Constant::AutoCalculate) {
    1295            0 :                 ShowSevereError(state, format("{}=\"{}\", ", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    1296            0 :                 ShowContinueError(state,
    1297            0 :                                   format("{} must be greater than 0. Condenser water flow rate = {:.6T}", hpwhNumericFieldNames[2], hpwhNumeric[2]));
    1298            0 :                 ErrorsFound = true;
    1299              :             }
    1300              : 
    1301            3 :         } else if (HPWH.HPWHType == DataPlant::PlantEquipmentType::HeatPumpWtrHeaterWrapped) {
    1302              : 
    1303              :             // Wrapped Condenser Location
    1304            3 :             HPWH.WrappedCondenserBottomLocation = hpwhNumeric[2 + nNumericOffset];
    1305            3 :             HPWH.WrappedCondenserTopLocation = hpwhNumeric[3 + nNumericOffset];
    1306              : 
    1307            3 :             if (HPWH.WrappedCondenserBottomLocation < 0.0) {
    1308            0 :                 ShowSevereError(state, format("{}=\"{}\", ", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    1309            0 :                 ShowContinueError(state,
    1310            0 :                                   format("{} must be greater than 0. Condenser bottom location = {:.6T}",
    1311            0 :                                          hpwhNumericFieldNames[2],
    1312            0 :                                          HPWH.WrappedCondenserBottomLocation));
    1313            0 :                 ErrorsFound = true;
    1314              :             }
    1315              : 
    1316            3 :             if (HPWH.WrappedCondenserBottomLocation >= HPWH.WrappedCondenserTopLocation) {
    1317            0 :                 ShowSevereError(state, format("{}=\"{}\", ", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    1318            0 :                 ShowContinueError(state,
    1319            0 :                                   format("{} ({:.6T}) must be greater than {} ({:.6T}).",
    1320            0 :                                          HPWH.WrappedCondenserTopLocation,
    1321            0 :                                          hpwhNumericFieldNames[2],
    1322            0 :                                          hpwhNumericFieldNames[3],
    1323            0 :                                          HPWH.WrappedCondenserBottomLocation));
    1324            0 :                 ErrorsFound = true;
    1325              :             }
    1326              : 
    1327              :             // Reset the offset
    1328            3 :             nAlphaOffset = -2;
    1329            3 :             nNumericOffset = 1;
    1330              : 
    1331              :         } else {
    1332            0 :             assert(0);
    1333              :         }
    1334              : 
    1335              :         // Evaporator Air Flow Rate
    1336           23 :         HPWH.OperatingAirFlowRate = hpwhNumeric[3 + nNumericOffset];
    1337           23 :         if (HPWH.OperatingAirFlowRate <= 0.0 && hpwhNumeric[3 + nNumericOffset] != Constant::AutoCalculate) {
    1338            0 :             ShowSevereError(state, format("{}=\"{}\", ", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    1339            0 :             ShowContinueError(state,
    1340            0 :                               format("{}{}",
    1341            0 :                                      hpwhNumericFieldNames[3 + nNumericOffset],
    1342            0 :                                      format(" must be greater than 0. Evaporator air flow rate = {:.6T}", hpwhNumeric[3 + nNumericOffset])));
    1343            0 :             ErrorsFound = true;
    1344              :         }
    1345              : 
    1346              :         // Inlet Air Configuration
    1347           23 :         HPWH.InletAirConfiguration = static_cast<WTTAmbientTemp>(getEnumValue(HPWHAmbientTempNamesUC, Util::makeUPPER(hpwhAlpha[6 + nAlphaOffset])));
    1348           23 :         switch (HPWH.InletAirConfiguration) {
    1349            3 :         case WTTAmbientTemp::Schedule: {
    1350              : 
    1351              :             // Inlet Air Temperature Schedule
    1352            3 :             if (hpwhAlphaBlank[11 + nAlphaOffset]) {
    1353            0 :                 ShowSevereEmptyField(state, eoh, hpwhAlphaFieldNames[11 + nAlphaOffset]);
    1354            0 :                 ErrorsFound = true;
    1355            3 :             } else if ((HPWH.ambientTempSched = Sched::GetSchedule(state, hpwhAlpha[11 + nAlphaOffset])) == nullptr) {
    1356            0 :                 ShowSevereItemNotFound(state, eoh, hpwhAlphaFieldNames[11 + nAlphaOffset], hpwhAlpha[11 + nAlphaOffset]);
    1357            0 :                 ErrorsFound = true;
    1358              :             }
    1359              : 
    1360              :             // Inlet Air Humidity Schedule
    1361            3 :             if (hpwhAlphaBlank[12 + nAlphaOffset]) {
    1362            0 :                 ShowSevereEmptyField(state, eoh, hpwhAlphaFieldNames[12 + nAlphaOffset]);
    1363            0 :                 ErrorsFound = true;
    1364            3 :             } else if ((HPWH.ambientRHSched = Sched::GetSchedule(state, hpwhAlpha[12 + nAlphaOffset])) == nullptr) {
    1365            0 :                 ShowSevereItemNotFound(state, eoh, hpwhAlphaFieldNames[12 + nAlphaOffset], hpwhAlpha[12 + nAlphaOffset]);
    1366            0 :                 ErrorsFound = true;
    1367            3 :             } else if (!HPWH.ambientRHSched->checkMinMaxVals(state, Clusive::In, 0.0, Clusive::In, 1.0)) {
    1368            0 :                 Sched::ShowSevereBadMinMax(
    1369            0 :                     state, eoh, hpwhAlphaFieldNames[12 + nAlphaOffset], hpwhAlpha[12 + nAlphaOffset], Clusive::In, 0.0, Clusive::In, 1.0);
    1370            0 :                 ErrorsFound = true;
    1371              :             }
    1372            3 :         } break;
    1373              : 
    1374           10 :         case WTTAmbientTemp::ZoneAndOA:
    1375              :         case WTTAmbientTemp::TempZone: {
    1376              : 
    1377              :             // Inlet Air Zone
    1378           10 :             if (!hpwhAlphaBlank[13 + nAlphaOffset]) {
    1379           10 :                 HPWH.AmbientTempZone = Util::FindItemInList(hpwhAlpha[13 + nAlphaOffset], state.dataHeatBal->Zone);
    1380           10 :                 if (HPWH.AmbientTempZone == 0) {
    1381            0 :                     ShowSevereError(state, format("{}=\"{}\", not found", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    1382            0 :                     ShowContinueError(state, format("{}=\"{}\".", hpwhAlphaFieldNames[13 + nAlphaOffset], hpwhAlpha[13 + nAlphaOffset]));
    1383            0 :                     ErrorsFound = true;
    1384              :                 }
    1385              :             } else {
    1386            0 :                 ShowSevereError(state, format("{}=\"{}\", ", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    1387            0 :                 ShowContinueError(state, format("required {} is blank.", hpwhAlphaFieldNames[13 + nAlphaOffset]));
    1388            0 :                 ErrorsFound = true;
    1389              :             }
    1390           10 :             break;
    1391              :         }
    1392           10 :         default:
    1393              :         case WTTAmbientTemp::OutsideAir:
    1394           10 :             break;
    1395              :         }
    1396              : 
    1397              :         // Read air inlet nodes after mixer/splitter nodes have been read in (state.dataIPShortCut->cAlphaArgs 7-10),
    1398              :         // Node_ConnectionType differs for inlet node if mixer/splitter node exists
    1399              : 
    1400              :         // Tank Name
    1401              :         // We will verify this exists and is the right kind of tank later when the tanks are all loaded.
    1402           23 :         HPWH.TankName = hpwhAlpha[15 + nAlphaOffset];
    1403           23 :         HPWH.TankType = hpwhAlpha[14 + nAlphaOffset];
    1404              : 
    1405              :         // Use Side Inlet/Outlet
    1406              :         // Get the water heater tank use side inlet node names for HPWHs connected to a plant loop
    1407              :         // Save the name of the node for use with set up comp sets
    1408           23 :         HPWH.InletNodeName2 = hpwhAlpha[16 + nAlphaOffset];
    1409           23 :         HPWH.OutletNodeName2 = hpwhAlpha[17 + nAlphaOffset];
    1410              : 
    1411           23 :         if (!hpwhAlphaBlank[16 + nAlphaOffset] && !hpwhAlphaBlank[17 + nAlphaOffset]) {
    1412           10 :             HPWH.WHUseInletNode = NodeInputManager::GetOnlySingleNode(state,
    1413           10 :                                                                       HPWH.InletNodeName2,
    1414              :                                                                       ErrorsFound,
    1415              :                                                                       objType,
    1416           10 :                                                                       HPWH.Name,
    1417              :                                                                       DataLoopNode::NodeFluidType::Water,
    1418              :                                                                       DataLoopNode::ConnectionType::Inlet,
    1419              :                                                                       NodeInputManager::CompFluidStream::Primary,
    1420              :                                                                       DataLoopNode::ObjectIsParent);
    1421           20 :             HPWH.WHUseOutletNode = NodeInputManager::GetOnlySingleNode(state,
    1422           10 :                                                                        HPWH.OutletNodeName2,
    1423              :                                                                        ErrorsFound,
    1424              :                                                                        objType,
    1425           10 :                                                                        HPWH.Name,
    1426              :                                                                        DataLoopNode::NodeFluidType::Water,
    1427              :                                                                        DataLoopNode::ConnectionType::Outlet,
    1428              :                                                                        NodeInputManager::CompFluidStream::Primary,
    1429              :                                                                        DataLoopNode::ObjectIsParent);
    1430              :         }
    1431              : 
    1432              :         // DX Coil
    1433              :         // get Coil:DX:HeatPumpWaterHeater object
    1434           23 :         HPWH.DXCoilName = hpwhAlpha[19 + nAlphaOffset];
    1435           23 :         HPWH.DXCoilType = hpwhAlpha[18 + nAlphaOffset];
    1436              : 
    1437              :         // check that the DX Coil exists
    1438           23 :         bool DXCoilErrFlag = false;
    1439           23 :         bool bIsVScoil = false;
    1440           23 :         DXCoils::GetDXCoilIndex(state, HPWH.DXCoilName, HPWH.DXCoilNum, DXCoilErrFlag, state.dataIPShortCut->cCurrentModuleObject, true);
    1441           23 :         if (DXCoilErrFlag) {
    1442              :             // This could be a variable speed heat pump water heater
    1443            7 :             bool bVSCoilErrFlag = false;
    1444              : 
    1445            7 :             bool checkIHPFirst = IntegratedHeatPump::IHPInModel(state);
    1446            7 :             if (checkIHPFirst) {
    1447            1 :                 HPWH.DXCoilNum =
    1448            2 :                     IntegratedHeatPump::GetCoilIndexIHP(state, "COILSYSTEM:INTEGRATEDHEATPUMP:AIRSOURCE", HPWH.DXCoilName, bVSCoilErrFlag);
    1449              : 
    1450            1 :                 if (!bVSCoilErrFlag) {
    1451            1 :                     HPWH.bIsIHP = true;
    1452              :                 }
    1453              :             }
    1454              : 
    1455            7 :             if (bVSCoilErrFlag || !checkIHPFirst) {
    1456            6 :                 bVSCoilErrFlag = false;
    1457            6 :                 HPWH.DXCoilNum = VariableSpeedCoils::GetCoilIndexVariableSpeed(
    1458            6 :                     state, "Coil:WaterHeating:AirToWaterHeatPump:VariableSpeed", HPWH.DXCoilName, bVSCoilErrFlag);
    1459              : 
    1460            6 :                 if (bVSCoilErrFlag) {
    1461            0 :                     ShowContinueError(state, format("...occurs in {} ={}", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    1462            0 :                     ShowContinueError(state, format("...could not find either DXCoils::DXCoil or Variable Speed Coil {}", HPWH.DXCoilName));
    1463            0 :                     ErrorsFound = true;
    1464              :                 }
    1465              :             }
    1466              : 
    1467            7 :             bIsVScoil = true;
    1468            7 :             HPWH.DXCoilTypeNum = 0;
    1469            7 :             if (HPWH.bIsIHP) {
    1470            1 :                 HPWH.DXCoilType = "COILSYSTEM:INTEGRATEDHEATPUMP:AIRSOURCE";
    1471              :             } else {
    1472            6 :                 HPWH.DXCoilType = state.dataVariableSpeedCoils->VarSpeedCoil(HPWH.DXCoilNum).VarSpeedCoilType;
    1473              :             }
    1474              :         } else {
    1475              :             // this is a single speed coil
    1476           16 :             DXCoils::DXCoilData &Coil = state.dataDXCoils->DXCoil(HPWH.DXCoilNum);
    1477           16 :             if (!Util::SameString(HPWH.DXCoilType, Coil.DXCoilType)) {
    1478            0 :                 ShowSevereError(state, format("{}=\"{}\", ", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    1479            0 :                 ShowContinueError(state, format("specifies the coil {}=\"{}\".", HPWH.DXCoilType, HPWH.DXCoilName));
    1480            0 :                 ShowContinueError(state, format("However, {} is a coil of type {}.", HPWH.DXCoilName, Coil.DXCoilType));
    1481            0 :                 ErrorsFound = true;
    1482              :             }
    1483           16 :             HPWH.DXCoilTypeNum = Coil.DXCoilType_Num;
    1484              :         }
    1485              : 
    1486              :         // Make sure that the coil and tank are compatible.
    1487           23 :         if (bIsVScoil) {
    1488            7 :             if (HPWH.HPWHType != DataPlant::PlantEquipmentType::HeatPumpWtrHeaterPumped) {
    1489            0 :                 ShowSevereError(state, format("{}=\"{}\":", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    1490            0 :                 ShowContinueError(state,
    1491              :                                   "Coil:WaterHeating:AirToWaterHeatPump:VariableSpeed can only be used with a pumped condenser heat pump "
    1492              :                                   "water heater.");
    1493            0 :                 ErrorsFound = true;
    1494              :             }
    1495              :         } else {
    1496           16 :             if (!((HPWH.DXCoilTypeNum == HVAC::CoilDX_HeatPumpWaterHeaterPumped &&
    1497           13 :                    HPWH.HPWHType == DataPlant::PlantEquipmentType::HeatPumpWtrHeaterPumped) ||
    1498            3 :                   (HPWH.DXCoilTypeNum == HVAC::CoilDX_HeatPumpWaterHeaterWrapped &&
    1499            3 :                    HPWH.HPWHType == DataPlant::PlantEquipmentType::HeatPumpWtrHeaterWrapped))) {
    1500            0 :                 ShowSevereError(state, format("{}=\"{}\":", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    1501            0 :                 std::string ExpectedCoilType;
    1502            0 :                 if (HPWH.HPWHType == DataPlant::PlantEquipmentType::HeatPumpWtrHeaterPumped) {
    1503            0 :                     ExpectedCoilType = HVAC::cAllCoilTypes(HVAC::CoilDX_HeatPumpWaterHeaterPumped);
    1504            0 :                 } else if (HPWH.HPWHType == DataPlant::PlantEquipmentType::HeatPumpWtrHeaterWrapped) {
    1505            0 :                     ExpectedCoilType = HVAC::cAllCoilTypes(HVAC::CoilDX_HeatPumpWaterHeaterWrapped);
    1506              :                 } else {
    1507            0 :                     assert(0);
    1508              :                 }
    1509            0 :                 ShowContinueError(state, format("can only be used with {}", ExpectedCoilType));
    1510            0 :                 ErrorsFound = true;
    1511            0 :             }
    1512              :         }
    1513              : 
    1514              :         // Dummy condenser Inlet/Outlet Nodes for wrapped tanks
    1515           23 :         if (HPWH.DXCoilTypeNum == HVAC::CoilDX_HeatPumpWaterHeaterWrapped) {
    1516            3 :             DXCoils::DXCoilData &Coil = state.dataDXCoils->DXCoil(HPWH.DXCoilNum);
    1517              : 
    1518            3 :             HPWH.InletNodeName1 = "DUMMY CONDENSER INLET " + Coil.Name;
    1519            3 :             HPWH.CondWaterInletNode = NodeInputManager::GetOnlySingleNode(state,
    1520            3 :                                                                           HPWH.InletNodeName1,
    1521              :                                                                           ErrorsFound,
    1522              :                                                                           objType,
    1523            3 :                                                                           HPWH.Name,
    1524              :                                                                           DataLoopNode::NodeFluidType::Water,
    1525              :                                                                           DataLoopNode::ConnectionType::Inlet,
    1526              :                                                                           NodeInputManager::CompFluidStream::Secondary,
    1527              :                                                                           DataLoopNode::ObjectIsParent);
    1528            3 :             HPWH.OutletNodeName1 = "DUMMY CONDENSER OUTLET " + Coil.Name;
    1529            6 :             HPWH.CondWaterOutletNode = NodeInputManager::GetOnlySingleNode(state,
    1530            3 :                                                                            HPWH.OutletNodeName1,
    1531              :                                                                            ErrorsFound,
    1532              :                                                                            objType,
    1533            3 :                                                                            HPWH.Name,
    1534              :                                                                            DataLoopNode::NodeFluidType::Water,
    1535              :                                                                            DataLoopNode::ConnectionType::Outlet,
    1536              :                                                                            NodeInputManager::CompFluidStream::Secondary,
    1537              :                                                                            DataLoopNode::ObjectIsParent);
    1538              :         }
    1539              : 
    1540              :         // Minimum Inlet Air Temperature for Compressor Operation
    1541           23 :         HPWH.MinAirTempForHPOperation = hpwhNumeric[4 + nNumericOffset];
    1542              : 
    1543              :         // Maximum Inlet Air Temperature for Compressor Operation
    1544           23 :         HPWH.MaxAirTempForHPOperation = hpwhNumeric[5 + nNumericOffset];
    1545           23 :         if (HPWH.MaxAirTempForHPOperation <= HPWH.MinAirTempForHPOperation) {
    1546            0 :             ShowWarningError(state,
    1547            0 :                              format("{}=\"{}\": maximum inlet air temperature for heat pump compressor operation",
    1548            0 :                                     state.dataIPShortCut->cCurrentModuleObject,
    1549            0 :                                     HPWH.Name));
    1550            0 :             ShowContinueError(state, "must be greater than the minimum inlet air temperature for heat pump compressor operation.");
    1551            0 :             ShowContinueError(state, format("...Minimum inlet air temperature = {:.1T}", HPWH.MinAirTempForHPOperation));
    1552            0 :             ShowContinueError(state, format("...Maximum inlet air temperature = {:.1T}", HPWH.MaxAirTempForHPOperation));
    1553              :         }
    1554              : 
    1555              :         // Compressor Location
    1556           23 :         HPWH.CrankcaseTempIndicator =
    1557           23 :             static_cast<CrankcaseHeaterControlTemp>(getEnumValue(CrankcaseHeaterControlTempNamesUC, Util::makeUPPER(hpwhAlpha[20 + nAlphaOffset])));
    1558              : 
    1559           23 :         switch (HPWH.CrankcaseTempIndicator) {
    1560            3 :         case CrankcaseHeaterControlTemp::Schedule: {
    1561            3 :             if (hpwhAlphaBlank[21 + nAlphaOffset]) {
    1562            0 :                 ShowSevereEmptyField(state, eoh, hpwhAlphaFieldNames[21 + nAlphaOffset]);
    1563            0 :                 ErrorsFound = true;
    1564            3 :             } else if ((HPWH.crankcaseTempSched = Sched::GetSchedule(state, hpwhAlpha[21 + nAlphaOffset])) == nullptr) {
    1565            0 :                 ShowSevereItemNotFound(state, eoh, hpwhAlphaFieldNames[21 + nAlphaOffset], hpwhAlpha[21 + nAlphaOffset]);
    1566            0 :                 ErrorsFound = true;
    1567              :             }
    1568            3 :         } break;
    1569              : 
    1570           10 :         case CrankcaseHeaterControlTemp::Zone: {
    1571           10 :             if (HPWH.InletAirConfiguration == WTTAmbientTemp::OutsideAir || HPWH.InletAirConfiguration == WTTAmbientTemp::Schedule) {
    1572            0 :                 ShowSevereError(state,
    1573            0 :                                 format("{}=\"{}\":  Inlet Air Configuration must be Zone Air Only or Zone And",
    1574            0 :                                        state.dataIPShortCut->cCurrentModuleObject,
    1575            0 :                                        HPWH.Name));
    1576            0 :                 ShowContinueError(state, " Outdoor Air when compressor location equals ZONE.");
    1577            0 :                 ErrorsFound = true;
    1578              :             }
    1579              : 
    1580           10 :             if (!hpwhAlphaBlank[21 + nAlphaOffset]) {
    1581            0 :                 ShowWarningError(state,
    1582            0 :                                  format("{}=\"{}\"  {} was provided but will not be used based on compressor location input=\"{}\".",
    1583            0 :                                         state.dataIPShortCut->cCurrentModuleObject,
    1584            0 :                                         HPWH.Name,
    1585            0 :                                         hpwhAlphaFieldNames[21 + nAlphaOffset],
    1586            0 :                                         hpwhAlpha[20 + nAlphaOffset]));
    1587              :             }
    1588           10 :             break;
    1589              :         }
    1590           10 :         case CrankcaseHeaterControlTemp::Outdoors: {
    1591           10 :             if (!hpwhAlphaBlank[21 + nAlphaOffset]) {
    1592            0 :                 ShowWarningError(state,
    1593            0 :                                  format("{}=\"{}\"  {} was provided but will not be used based on {}=\"{}\".",
    1594            0 :                                         state.dataIPShortCut->cCurrentModuleObject,
    1595            0 :                                         HPWH.Name,
    1596            0 :                                         hpwhAlphaFieldNames[21 + nAlphaOffset],
    1597            0 :                                         hpwhAlphaFieldNames[21 + nAlphaOffset],
    1598            0 :                                         hpwhAlpha[20 + nAlphaOffset]));
    1599              :             }
    1600           10 :             break;
    1601              :         }
    1602            0 :         default:
    1603            0 :             break;
    1604              :         }
    1605              : 
    1606              :         // Fan Name
    1607           23 :         HPWH.FanName = hpwhAlpha[23 + nAlphaOffset];
    1608              : 
    1609           23 :         Real64 FanVolFlow = 0.0;
    1610           23 :         bool errFlag(false);
    1611              : 
    1612           23 :         HPWH.fanType = static_cast<HVAC::FanType>(getEnumValue(HVAC::fanTypeNamesUC, hpwhAlpha[22 + nAlphaOffset]));
    1613              : 
    1614           23 :         if ((HPWH.FanNum = Fans::GetFanIndex(state, HPWH.FanName)) == 0) {
    1615            0 :             ShowSevereItemNotFound(state, eoh, hpwhAlphaFieldNames[23 + nAlphaOffset], HPWH.FanName);
    1616            0 :             ErrorsFound = true;
    1617              :         } else {
    1618           23 :             assert(HPWH.fanType == state.dataFans->fans(HPWH.FanNum)->type);
    1619           23 :             FanVolFlow = state.dataFans->fans(HPWH.FanNum)->maxAirFlowRate;
    1620              :         }
    1621              :         // issue #5630, set fan info in coils.
    1622           23 :         if (bIsVScoil) {
    1623            7 :             VariableSpeedCoils::setVarSpeedHPWHFanType(state, HPWH.DXCoilNum, HPWH.fanType);
    1624            7 :             VariableSpeedCoils::setVarSpeedHPWHFanIndex(state, HPWH.DXCoilNum, HPWH.FanNum);
    1625              :         } else {
    1626              :             // LOL
    1627           16 :             DXCoils::SetDXCoolingCoilData(state, HPWH.DXCoilNum, errFlag, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, HPWH.FanName);
    1628           16 :             DXCoils::SetDXCoolingCoilData(state, HPWH.DXCoilNum, errFlag, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, HPWH.FanNum);
    1629           16 :             DXCoils::SetDXCoolingCoilData(
    1630           16 :                 state, HPWH.DXCoilNum, errFlag, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, HPWH.fanType);
    1631              :         }
    1632              : 
    1633           23 :         if (errFlag) {
    1634            0 :             ErrorsFound = true;
    1635           23 :         } else if (HPWH.fanType != HVAC::FanType::OnOff && HPWH.fanType != HVAC::FanType::SystemModel) {
    1636            0 :             ShowSevereError(state, format("{}=\"{}\": illegal fan type specified.", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    1637            0 :             ShowContinueError(
    1638              :                 state,
    1639            0 :                 format(" The fan object ({}) type must be Fan:SystemModel or Fan:OnOff when used with a heat pump water heater.", HPWH.FanName));
    1640            0 :             ErrorsFound = true;
    1641           23 :         } else if (HPWH.fanType != HVAC::FanType::OnOff && HPWH.fanType != HVAC::FanType::SystemModel) {
    1642            0 :             ShowSevereError(state, format("{}=\"{}\": illegal fan type specified.", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    1643            0 :             ShowContinueError(state, format(" The {} must specify that the fan object", state.dataIPShortCut->cCurrentModuleObject));
    1644            0 :             ShowContinueError(state,
    1645              :                               " is of type FanSystemModel or Fan:OnOff in addition to the fan actually being of that type and defined elsewhere.");
    1646              :         }
    1647              : 
    1648           23 :         if (FanVolFlow != DataSizing::AutoSize && !errFlag) {
    1649           21 :             if (FanVolFlow < HPWH.OperatingAirFlowRate) {
    1650            0 :                 ShowSevereError(state,
    1651            0 :                                 format("{} - air flow rate = {:.7T} in fan object {} is less than the  HPWHs evaporator air flow rate.",
    1652            0 :                                        state.dataIPShortCut->cCurrentModuleObject,
    1653              :                                        FanVolFlow,
    1654            0 :                                        HPWH.FanName));
    1655            0 :                 ShowContinueError(state, " The fan flow rate must be >= to the HPWHs evaporator volumetric air flow rate.");
    1656            0 :                 ShowContinueError(state, format(" Occurs in unit = {}", HPWH.Name));
    1657            0 :                 ErrorsFound = true;
    1658              :             }
    1659              :         }
    1660              : 
    1661              :         // Fan Placement
    1662           23 :         HPWH.fanPlace = static_cast<HVAC::FanPlace>(getEnumValue(HVAC::fanPlaceNamesUC, hpwhAlpha[24 + nAlphaOffset]));
    1663           23 :         if (HPWH.fanPlace == HVAC::FanPlace::Invalid) {
    1664            0 :             ShowSevereInvalidKey(state, eoh, hpwhAlphaFieldNames[24 + nAlphaOffset], hpwhAlpha[24 + nAlphaOffset]);
    1665            0 :             ErrorsFound = true;
    1666              :         }
    1667              : 
    1668           23 :         if (HPWH.DXCoilNum > 0 && !bIsVScoil) {
    1669              :             // get HPWH capacity, air inlet node, and PLF curve info from DX coil object
    1670           16 :             HPWH.Capacity = state.dataDXCoils->DXCoil(HPWH.DXCoilNum).RatedTotCap2;
    1671           16 :             HPWH.DXCoilAirInletNode = state.dataDXCoils->DXCoil(HPWH.DXCoilNum).AirInNode;
    1672           16 :             HPWH.DXCoilPLFFPLR = state.dataDXCoils->DXCoil(HPWH.DXCoilNum).PLFFPLR(1);
    1673              :             // check the range of condenser pump power to be <= 5 gpm/ton
    1674           16 :             if (state.dataDXCoils->DXCoil(HPWH.DXCoilNum).HPWHCondPumpElecNomPower / state.dataDXCoils->DXCoil(HPWH.DXCoilNum).RatedTotCap2 >
    1675              :                 0.1422) {
    1676            0 :                 ShowWarningError(
    1677              :                     state,
    1678            0 :                     format("{}= {}{}",
    1679            0 :                            state.dataDXCoils->DXCoil(HPWH.DXCoilNum).DXCoilType,
    1680            0 :                            state.dataDXCoils->DXCoil(HPWH.DXCoilNum).Name,
    1681            0 :                            format(": Rated condenser pump power per watt of rated heating capacity has exceeded the recommended maximum of 0.1422 "
    1682              :                                   "W/W (41.67 watt/MBH). Condenser pump power per watt = {:.4T}",
    1683            0 :                                   (state.dataDXCoils->DXCoil(HPWH.DXCoilNum).HPWHCondPumpElecNomPower /
    1684            0 :                                    state.dataDXCoils->DXCoil(HPWH.DXCoilNum).RatedTotCap2))));
    1685              :             }
    1686            7 :         } else if ((HPWH.DXCoilNum > 0) && (bIsVScoil)) {
    1687              : 
    1688            7 :             if (HPWH.bIsIHP) {
    1689            1 :                 HPWH.Capacity =
    1690            1 :                     GetDWHCoilCapacityIHP(state, HPWH.DXCoilType, HPWH.DXCoilName, IntegratedHeatPump::IHPOperationMode::SCWHMatchWH, DXCoilErrFlag);
    1691            1 :                 HPWH.DXCoilAirInletNode = IntegratedHeatPump::GetCoilInletNodeIHP(state, HPWH.DXCoilType, HPWH.DXCoilName, DXCoilErrFlag);
    1692            1 :                 HPWH.DXCoilPLFFPLR =
    1693            1 :                     GetIHPDWHCoilPLFFPLR(state, HPWH.DXCoilType, HPWH.DXCoilName, IntegratedHeatPump::IHPOperationMode::SCWHMatchWH, DXCoilErrFlag);
    1694              :             } else {
    1695            6 :                 HPWH.Capacity = VariableSpeedCoils::GetCoilCapacityVariableSpeed(state, HPWH.DXCoilType, HPWH.DXCoilName, DXCoilErrFlag);
    1696            6 :                 HPWH.DXCoilAirInletNode = VariableSpeedCoils::GetCoilInletNodeVariableSpeed(state, HPWH.DXCoilType, HPWH.DXCoilName, DXCoilErrFlag);
    1697            6 :                 HPWH.DXCoilPLFFPLR = VariableSpeedCoils::GetVSCoilPLFFPLR(state, HPWH.DXCoilType, HPWH.DXCoilName, DXCoilErrFlag);
    1698              :             }
    1699              :             //         check the range of condenser pump power to be <= 5 gpm/ton, will be checked in the coil object
    1700              :         }
    1701              : 
    1702           23 :         if (HPWH.OperatingWaterFlowRate == Constant::AutoCalculate) {
    1703            8 :             HPWH.OperatingWaterFlowRate = 0.00000004487 * HPWH.Capacity;
    1704            8 :             HPWH.WaterFlowRateAutoSized = true;
    1705              :         }
    1706              : 
    1707           23 :         if (HPWH.OperatingAirFlowRate == Constant::AutoCalculate) {
    1708           10 :             HPWH.OperatingAirFlowRate = 0.00005035 * HPWH.Capacity;
    1709           10 :             HPWH.AirFlowRateAutoSized = true;
    1710              :         }
    1711              : 
    1712              :         // On Cycle Parasitic Electric Load
    1713           23 :         HPWH.OnCycParaLoad = hpwhNumeric[6 + nNumericOffset];
    1714           23 :         if (HPWH.OnCycParaLoad < 0.0) {
    1715            0 :             ShowSevereError(state, format("{}=\"{}\",", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    1716            0 :             ShowContinueError(state,
    1717            0 :                               format("{} must be >= 0. {}{}",
    1718            0 :                                      hpwhNumericFieldNames[6 + nNumericOffset],
    1719            0 :                                      hpwhNumericFieldNames[6 + nNumericOffset],
    1720            0 :                                      format(" = {:.2T}", hpwhNumeric[6 + nNumericOffset])));
    1721            0 :             ErrorsFound = true;
    1722              :         }
    1723              : 
    1724              :         // Off Cycle Parasitic Electric Load
    1725           23 :         HPWH.OffCycParaLoad = hpwhNumeric[7 + nNumericOffset];
    1726           23 :         if (HPWH.OffCycParaLoad < 0.0) {
    1727            0 :             ShowSevereError(state, format("{}=\"{}\",", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    1728            0 :             ShowContinueError(state,
    1729            0 :                               format("{} must be >= 0. {}{}",
    1730            0 :                                      hpwhNumericFieldNames[7 + nNumericOffset],
    1731            0 :                                      hpwhNumericFieldNames[2 + nNumericOffset],
    1732            0 :                                      format(" = {:.2T}", hpwhNumeric[7 + nNumericOffset])));
    1733            0 :             ErrorsFound = true;
    1734              :         }
    1735              : 
    1736              :         // Parasitic Heat Rejection Location
    1737           23 :         if (Util::SameString(hpwhAlpha[25 + nAlphaOffset], "Zone")) {
    1738            8 :             HPWH.ParasiticTempIndicator = WTTAmbientTemp::TempZone;
    1739            8 :             if (HPWH.InletAirConfiguration == WTTAmbientTemp::OutsideAir || HPWH.InletAirConfiguration == WTTAmbientTemp::Schedule) {
    1740            0 :                 ShowSevereError(state, format("{}=\"{}\",", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    1741            0 :                 ShowContinueError(state, format("{} must be ZoneAirOnly or ZoneAndOutdoorAir", hpwhAlphaFieldNames[25 + nAlphaOffset]));
    1742            0 :                 ShowContinueError(state, " when parasitic heat rejection location equals Zone.");
    1743            0 :                 ErrorsFound = true;
    1744              :             }
    1745           15 :         } else if (Util::SameString(hpwhAlpha[25 + nAlphaOffset], "Outdoors")) {
    1746           15 :             HPWH.ParasiticTempIndicator = WTTAmbientTemp::OutsideAir;
    1747              :         } else {
    1748            0 :             ShowSevereError(state, format("{}=\"{}\":", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    1749            0 :             ShowContinueError(state, " parasitic heat rejection location must be either Zone or Outdoors.");
    1750            0 :             ErrorsFound = true;
    1751              :         }
    1752              : 
    1753              :         // Inlet Air Mixer Node
    1754              :         // get mixer/splitter nodes only when Inlet Air Configuration is ZoneAndOutdoorAir
    1755           23 :         if (!hpwhAlphaBlank[26 + nAlphaOffset]) {
    1756              :             // For the inlet air mixer node, NodeConnectionType is outlet from the HPWH inlet air node
    1757            3 :             if (HPWH.InletAirConfiguration == WTTAmbientTemp::ZoneAndOA) {
    1758            3 :                 HPWH.InletAirMixerNode = NodeInputManager::GetOnlySingleNode(state,
    1759            3 :                                                                              hpwhAlpha[26 + nAlphaOffset],
    1760              :                                                                              ErrorsFound,
    1761              :                                                                              objType,
    1762            6 :                                                                              HPWH.Name + "-INLET AIR MIXER",
    1763              :                                                                              DataLoopNode::NodeFluidType::Air,
    1764              :                                                                              DataLoopNode::ConnectionType::Outlet,
    1765              :                                                                              NodeInputManager::CompFluidStream::Primary,
    1766              :                                                                              DataLoopNode::ObjectIsNotParent);
    1767              :             } else {
    1768            0 :                 ShowWarningError(state, format("{}=\"{}\":", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    1769            0 :                 ShowContinueError(state,
    1770              :                                   "Inlet air mixer node name specified but only required when Inlet Air Configuration is selected as "
    1771              :                                   "Zone and OutdoorAir. Node name disregarded and simulation continues.");
    1772              :             }
    1773           20 :         } else if (hpwhAlphaBlank[26 + nAlphaOffset] && HPWH.InletAirConfiguration == WTTAmbientTemp::ZoneAndOA) {
    1774            0 :             ShowSevereError(state, format("{}=\"{}\":", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    1775            0 :             ShowContinueError(state, "Inlet air mixer node name required when Inlet Air Configuration is selected as ZoneAndOutdoorAir.");
    1776            0 :             ErrorsFound = true;
    1777              :         }
    1778              : 
    1779              :         // Outlet Air Splitter Node
    1780           23 :         if (!hpwhAlphaBlank[27 + nAlphaOffset]) {
    1781              :             //  For the outlet air splitter node, NodeConnectionType is inlet to the HPWH outlet air node
    1782            3 :             if (HPWH.InletAirConfiguration == WTTAmbientTemp::ZoneAndOA) {
    1783            3 :                 HPWH.OutletAirSplitterNode = NodeInputManager::GetOnlySingleNode(state,
    1784            3 :                                                                                  hpwhAlpha[27 + nAlphaOffset],
    1785              :                                                                                  ErrorsFound,
    1786              :                                                                                  objType,
    1787            6 :                                                                                  HPWH.Name + "-OUTLET AIR SPLITTER",
    1788              :                                                                                  DataLoopNode::NodeFluidType::Air,
    1789              :                                                                                  DataLoopNode::ConnectionType::Inlet,
    1790              :                                                                                  NodeInputManager::CompFluidStream::Primary,
    1791              :                                                                                  DataLoopNode::ObjectIsNotParent);
    1792              :             } else {
    1793            0 :                 ShowWarningError(state, format("{}=\"{}\":", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    1794            0 :                 ShowContinueError(state,
    1795              :                                   "Outlet air splitter node name specified but only required when Inlet Air Configuration is selected as "
    1796              :                                   "ZoneAndOutdoorAir. Node name disregarded and simulation continues.");
    1797              :             }
    1798           20 :         } else if (hpwhAlphaBlank[27 + nAlphaOffset] && HPWH.InletAirConfiguration == WTTAmbientTemp::ZoneAndOA) {
    1799            0 :             ShowSevereError(state, format("{}=\"{}\":", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    1800            0 :             ShowContinueError(state, "Outlet air splitter node name required when Inlet Air Configuration is selected as ZoneAndOutdoorAir.");
    1801            0 :             ErrorsFound = true;
    1802              :         }
    1803              : 
    1804              :         // get node data for HPWH
    1805           23 :         if (HPWH.InletAirMixerNode != 0) {
    1806              :             // when mixer/splitter nodes are used the HPWH's inlet/outlet node are set up as DataLoopNode::ObjectIsNotParent
    1807              : 
    1808            3 :             HPWH.HeatPumpAirInletNode = NodeInputManager::GetOnlySingleNode(state,
    1809            3 :                                                                             hpwhAlpha[7 + nAlphaOffset],
    1810              :                                                                             ErrorsFound,
    1811              :                                                                             objType,
    1812            6 :                                                                             HPWH.Name + "-INLET AIR MIXER",
    1813              :                                                                             DataLoopNode::NodeFluidType::Air,
    1814              :                                                                             DataLoopNode::ConnectionType::Inlet,
    1815              :                                                                             NodeInputManager::CompFluidStream::Primary,
    1816              :                                                                             DataLoopNode::ObjectIsNotParent);
    1817              : 
    1818            3 :             HPWH.HeatPumpAirOutletNode = NodeInputManager::GetOnlySingleNode(state,
    1819            3 :                                                                              hpwhAlpha[8 + nAlphaOffset],
    1820              :                                                                              ErrorsFound,
    1821              :                                                                              objType,
    1822            6 :                                                                              HPWH.Name + "-OUTLET AIR SPLITTER",
    1823              :                                                                              DataLoopNode::NodeFluidType::Air,
    1824              :                                                                              DataLoopNode::ConnectionType::Outlet,
    1825              :                                                                              NodeInputManager::CompFluidStream::Primary,
    1826              :                                                                              DataLoopNode::ObjectIsNotParent);
    1827              : 
    1828            3 :             HPWH.OutsideAirNode = NodeInputManager::GetOnlySingleNode(state,
    1829            3 :                                                                       hpwhAlpha[9 + nAlphaOffset],
    1830              :                                                                       ErrorsFound,
    1831              :                                                                       objType,
    1832            3 :                                                                       HPWH.Name,
    1833              :                                                                       DataLoopNode::NodeFluidType::Air,
    1834              :                                                                       DataLoopNode::ConnectionType::OutsideAirReference,
    1835              :                                                                       NodeInputManager::CompFluidStream::Primary,
    1836              :                                                                       DataLoopNode::ObjectIsParent);
    1837            3 :             if (!hpwhAlpha[9 + nAlphaOffset].empty()) {
    1838              :                 bool Okay;
    1839            3 :                 OutAirNodeManager::CheckAndAddAirNodeNumber(state, HPWH.OutsideAirNode, Okay);
    1840            3 :                 if (!Okay) {
    1841            0 :                     ShowWarningError(state,
    1842            0 :                                      format("{}=\"{}\": Adding outdoor air node={}",
    1843            0 :                                             state.dataIPShortCut->cCurrentModuleObject,
    1844            0 :                                             HPWH.Name,
    1845            0 :                                             hpwhAlpha[9 + nAlphaOffset]));
    1846              :                 }
    1847              :             }
    1848              : 
    1849            3 :             HPWH.ExhaustAirNode = NodeInputManager::GetOnlySingleNode(state,
    1850            3 :                                                                       hpwhAlpha[10 + nAlphaOffset],
    1851              :                                                                       ErrorsFound,
    1852              :                                                                       objType,
    1853            3 :                                                                       HPWH.Name,
    1854              :                                                                       DataLoopNode::NodeFluidType::Air,
    1855              :                                                                       DataLoopNode::ConnectionType::ReliefAir,
    1856              :                                                                       NodeInputManager::CompFluidStream::Primary,
    1857              :                                                                       DataLoopNode::ObjectIsParent);
    1858              : 
    1859              :         } else {
    1860              :             // when mixer/splitter nodes are NOT used the HPWH's inlet/outlet nodes are set up as DataLoopNode::ObjectIsParent
    1861           20 :             if (HPWH.InletAirConfiguration == WTTAmbientTemp::Schedule) {
    1862              :                 // for scheduled HPWH's the inlet node is not on any branch or parent object, make it an outlet node
    1863              :                 // to avoid node connection errors
    1864            3 :                 HPWH.HeatPumpAirInletNode = NodeInputManager::GetOnlySingleNode(state,
    1865            3 :                                                                                 hpwhAlpha[7 + nAlphaOffset],
    1866              :                                                                                 ErrorsFound,
    1867              :                                                                                 objType,
    1868            3 :                                                                                 HPWH.Name,
    1869              :                                                                                 DataLoopNode::NodeFluidType::Air,
    1870              :                                                                                 DataLoopNode::ConnectionType::Outlet,
    1871              :                                                                                 NodeInputManager::CompFluidStream::Primary,
    1872              :                                                                                 DataLoopNode::ObjectIsParent);
    1873              : 
    1874            3 :                 HPWH.HeatPumpAirOutletNode = NodeInputManager::GetOnlySingleNode(state,
    1875            3 :                                                                                  hpwhAlpha[8 + nAlphaOffset],
    1876              :                                                                                  ErrorsFound,
    1877              :                                                                                  objType,
    1878            3 :                                                                                  HPWH.Name,
    1879              :                                                                                  DataLoopNode::NodeFluidType::Air,
    1880              :                                                                                  DataLoopNode::ConnectionType::Outlet,
    1881              :                                                                                  NodeInputManager::CompFluidStream::Primary,
    1882              :                                                                                  DataLoopNode::ObjectIsParent);
    1883              : 
    1884              :             } else { // HPWH is connected to a zone with no mixer/splitter nodes
    1885           17 :                 if (HPWH.InletAirConfiguration == WTTAmbientTemp::TempZone) {
    1886            7 :                     HPWH.HeatPumpAirInletNode = NodeInputManager::GetOnlySingleNode(state,
    1887            7 :                                                                                     hpwhAlpha[7 + nAlphaOffset],
    1888              :                                                                                     ErrorsFound,
    1889              :                                                                                     objType,
    1890            7 :                                                                                     HPWH.Name,
    1891              :                                                                                     DataLoopNode::NodeFluidType::Air,
    1892              :                                                                                     DataLoopNode::ConnectionType::Inlet,
    1893              :                                                                                     NodeInputManager::CompFluidStream::Primary,
    1894              :                                                                                     DataLoopNode::ObjectIsParent);
    1895              : 
    1896            7 :                     HPWH.HeatPumpAirOutletNode = NodeInputManager::GetOnlySingleNode(state,
    1897            7 :                                                                                      hpwhAlpha[8 + nAlphaOffset],
    1898              :                                                                                      ErrorsFound,
    1899              :                                                                                      objType,
    1900            7 :                                                                                      HPWH.Name,
    1901              :                                                                                      DataLoopNode::NodeFluidType::Air,
    1902              :                                                                                      DataLoopNode::ConnectionType::Outlet,
    1903              :                                                                                      NodeInputManager::CompFluidStream::Primary,
    1904              :                                                                                      DataLoopNode::ObjectIsParent);
    1905              :                 } else { // HPWH is located outdoors
    1906           10 :                     HPWH.OutsideAirNode = NodeInputManager::GetOnlySingleNode(state,
    1907           10 :                                                                               hpwhAlpha[9 + nAlphaOffset],
    1908              :                                                                               ErrorsFound,
    1909              :                                                                               objType,
    1910           10 :                                                                               HPWH.Name,
    1911              :                                                                               DataLoopNode::NodeFluidType::Air,
    1912              :                                                                               DataLoopNode::ConnectionType::OutsideAirReference,
    1913              :                                                                               NodeInputManager::CompFluidStream::Primary,
    1914              :                                                                               DataLoopNode::ObjectIsParent);
    1915           10 :                     if (!hpwhAlphaBlank[9 + nAlphaOffset]) {
    1916              :                         bool Okay;
    1917           10 :                         OutAirNodeManager::CheckAndAddAirNodeNumber(state, HPWH.OutsideAirNode, Okay);
    1918           10 :                         if (!Okay) {
    1919            0 :                             ShowWarningError(state,
    1920            0 :                                              format("{}=\"{}\": Adding outdoor air node ={}",
    1921            0 :                                                     state.dataIPShortCut->cCurrentModuleObject,
    1922            0 :                                                     HPWH.Name,
    1923            0 :                                                     hpwhAlpha[9 + nAlphaOffset]));
    1924              :                         }
    1925              :                     }
    1926              : 
    1927           10 :                     HPWH.ExhaustAirNode = NodeInputManager::GetOnlySingleNode(state,
    1928           10 :                                                                               hpwhAlpha[10 + nAlphaOffset],
    1929              :                                                                               ErrorsFound,
    1930              :                                                                               objType,
    1931           10 :                                                                               HPWH.Name,
    1932              :                                                                               DataLoopNode::NodeFluidType::Air,
    1933              :                                                                               DataLoopNode::ConnectionType::ReliefAir,
    1934              :                                                                               NodeInputManager::CompFluidStream::Primary,
    1935              :                                                                               DataLoopNode::ObjectIsParent);
    1936              :                 }
    1937              :             }
    1938              :         }
    1939              :         // check that required node names are present
    1940           23 :         if (HPWH.InletAirConfiguration == WTTAmbientTemp::Schedule || HPWH.InletAirConfiguration == WTTAmbientTemp::TempZone) {
    1941           10 :             if (HPWH.HeatPumpAirInletNode == 0 || HPWH.HeatPumpAirOutletNode == 0) {
    1942            0 :                 ShowSevereError(state, format("{}=\"{}\":", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    1943            0 :                 ShowContinueError(state, format("When {}=\"{}\".", hpwhAlphaFieldNames[6 + nAlphaOffset], hpwhAlpha[6 + nAlphaOffset]));
    1944            0 :                 ShowContinueError(
    1945            0 :                     state, format("{} and {} must be specified.", hpwhAlphaFieldNames[7 + nAlphaOffset], hpwhAlphaFieldNames[8 + nAlphaOffset]));
    1946            0 :                 ErrorsFound = true;
    1947              :             }
    1948           13 :         } else if (HPWH.InletAirConfiguration == WTTAmbientTemp::OutsideAir) {
    1949           10 :             if (HPWH.OutsideAirNode == 0 || HPWH.ExhaustAirNode == 0) {
    1950            0 :                 ShowSevereError(state, format("{}=\"{}\":", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    1951            0 :                 ShowContinueError(state, format("When {}=\"{}\".", hpwhAlphaFieldNames[6 + nAlphaOffset], hpwhAlpha[6 + nAlphaOffset]));
    1952            0 :                 ShowContinueError(
    1953            0 :                     state, format("{} and {} must be specified.", hpwhAlphaFieldNames[9 + nAlphaOffset], hpwhAlphaFieldNames[10 + nAlphaOffset]));
    1954            0 :                 ErrorsFound = true;
    1955              :             }
    1956            3 :         } else if (HPWH.InletAirMixerNode > 0 && HPWH.OutletAirSplitterNode > 0 && HPWH.InletAirConfiguration == WTTAmbientTemp::ZoneAndOA) {
    1957            3 :             if (HPWH.HeatPumpAirInletNode == 0 || HPWH.HeatPumpAirOutletNode == 0 || HPWH.OutsideAirNode == 0 || HPWH.ExhaustAirNode == 0) {
    1958            0 :                 ShowSevereError(state, format("{}=\"{}\":", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    1959            0 :                 ShowContinueError(state, format("When {}=\"{}\".", hpwhAlphaFieldNames[6 + nAlphaOffset], hpwhAlpha[6 + nAlphaOffset]));
    1960            0 :                 if (HPWH.HeatPumpAirInletNode == 0 || HPWH.HeatPumpAirOutletNode == 0) {
    1961            0 :                     ShowContinueError(
    1962            0 :                         state, format("{} and {} must be specified.", hpwhAlphaFieldNames[7 + nAlphaOffset], hpwhAlphaFieldNames[8 + nAlphaOffset]));
    1963              :                 }
    1964            0 :                 if (HPWH.OutsideAirNode == 0 || HPWH.ExhaustAirNode == 0) {
    1965            0 :                     ShowContinueError(
    1966            0 :                         state, format("{} and {} must be specified.", hpwhAlphaFieldNames[9 + nAlphaOffset], hpwhAlphaFieldNames[10 + nAlphaOffset]));
    1967              :                 }
    1968            0 :                 ErrorsFound = true;
    1969              :             }
    1970              :         }
    1971              : 
    1972              :         // check that the HPWH inlet and outlet nodes are in the same zone (ZoneHVAC:EquipmentConnections) when
    1973              :         // Inlet Air Configuration is Zone Air Only or Zone and Outdoor Air
    1974           23 :         if ((HPWH.InletAirConfiguration == WTTAmbientTemp::TempZone || HPWH.InletAirConfiguration == WTTAmbientTemp::ZoneAndOA) &&
    1975           10 :             HPWH.AmbientTempZone > 0) {
    1976           10 :             if (allocated(state.dataZoneEquip->ZoneEquipConfig)) {
    1977           10 :                 bool FoundInletNode = false;
    1978           10 :                 bool FoundOutletNode = false;
    1979           10 :                 int ZoneNum = HPWH.AmbientTempZone;
    1980           10 :                 if (ZoneNum <= state.dataGlobal->NumOfZones) {
    1981           37 :                     for (int SupAirIn = 1; SupAirIn <= state.dataZoneEquip->ZoneEquipConfig(ZoneNum).NumInletNodes; ++SupAirIn) {
    1982           27 :                         if (HPWH.HeatPumpAirOutletNode != state.dataZoneEquip->ZoneEquipConfig(ZoneNum).InletNode(SupAirIn)) {
    1983           17 :                             continue;
    1984              :                         }
    1985           10 :                         FoundOutletNode = true;
    1986              :                     }
    1987           27 :                     for (int ExhAirOut = 1; ExhAirOut <= state.dataZoneEquip->ZoneEquipConfig(ZoneNum).NumExhaustNodes; ++ExhAirOut) {
    1988           17 :                         if (HPWH.HeatPumpAirInletNode != state.dataZoneEquip->ZoneEquipConfig(ZoneNum).ExhaustNode(ExhAirOut)) {
    1989            7 :                             continue;
    1990              :                         }
    1991           10 :                         FoundInletNode = true;
    1992              :                     }
    1993           10 :                     if (!FoundInletNode) {
    1994            0 :                         ShowSevereError(state, format("{}=\"{}\":", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    1995            0 :                         ShowContinueError(state,
    1996            0 :                                           format("The HPWH's air inlet node name = {} was not properly specified ", hpwhAlpha[7 + nAlphaOffset]));
    1997            0 :                         ShowContinueError(
    1998              :                             state,
    1999            0 :                             format("as an exhaust air node for zone = {} in a ZoneHVAC:EquipmentConnections object.", hpwhAlpha[13 + nAlphaOffset]));
    2000            0 :                         ErrorsFound = true;
    2001              :                     }
    2002           10 :                     if (!FoundOutletNode) {
    2003            0 :                         ShowSevereError(state, format("{}=\"{}\":", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    2004            0 :                         ShowContinueError(state,
    2005            0 :                                           format("The HPWH's air outlet node name = {} was not properly specified ", hpwhAlpha[8 + nAlphaOffset]));
    2006            0 :                         ShowContinueError(
    2007              :                             state,
    2008            0 :                             format("as an inlet air node for zone = {} in a ZoneHVAC:EquipmentConnections object.", hpwhAlpha[13 + nAlphaOffset]));
    2009            0 :                         ErrorsFound = true;
    2010              :                     }
    2011              :                 }
    2012              :             } else {
    2013            0 :                 ShowSevereError(state, format("{}=\"{}\":", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    2014            0 :                 ShowContinueError(state,
    2015              :                                   "Heat pump water heater air inlet node name and air outlet node name must be listed in a "
    2016              :                                   "ZoneHVAC:EquipmentConnections object when Inlet Air Configuration is equal to ZoneAirOnly or "
    2017              :                                   "ZoneAndOutdoorAir.");
    2018            0 :                 ErrorsFound = true;
    2019              :             }
    2020              :         }
    2021              : 
    2022              :         // only get the inlet air mixer schedule if the inlet air configuration is zone and outdoor air
    2023           23 :         if (HPWH.InletAirConfiguration == WTTAmbientTemp::ZoneAndOA) {
    2024            3 :             if (hpwhAlphaBlank[28 + nAlphaOffset]) {
    2025            0 :                 ShowSevereEmptyField(state, eoh, hpwhAlphaFieldNames[28 + nAlphaOffset]);
    2026            0 :                 ErrorsFound = true;
    2027              :                 //           set outlet air splitter schedule index equal to inlet air mixer schedule index
    2028              :                 //           (place holder for when zone pressurization/depressurization is allowed and different schedules can be used)
    2029            3 :             } else if ((HPWH.inletAirMixerSched = HPWH.outletAirSplitterSched = Sched::GetSchedule(state, hpwhAlpha[28 + nAlphaOffset])) == nullptr) {
    2030            0 :                 ShowSevereItemNotFound(state, eoh, hpwhAlphaFieldNames[28 + nAlphaOffset], hpwhAlpha[28 + nAlphaOffset]);
    2031            0 :                 ErrorsFound = true;
    2032            3 :             } else if (!HPWH.inletAirMixerSched->checkMinMaxVals(state, Clusive::In, 0.0, Clusive::In, 1.0)) {
    2033            0 :                 Sched::ShowSevereBadMinMax(
    2034            0 :                     state, eoh, hpwhAlphaFieldNames[28 + nAlphaOffset], hpwhAlpha[28 + nAlphaOffset], Clusive::In, 0.0, Clusive::In, 1.0);
    2035            0 :                 ErrorsFound = true;
    2036              :             }
    2037              :         }
    2038              : 
    2039              :         // set fan outlet node variable for use in setting Node(FanOutletNode)%MassFlowRateMax for fan object
    2040           23 :         if (HPWH.fanPlace == HVAC::FanPlace::DrawThru) {
    2041           11 :             if (HPWH.OutletAirSplitterNode != 0) {
    2042            3 :                 HPWH.FanOutletNode = HPWH.OutletAirSplitterNode;
    2043            8 :             } else if (HPWH.InletAirConfiguration == WTTAmbientTemp::OutsideAir) {
    2044            1 :                 HPWH.FanOutletNode = HPWH.ExhaustAirNode;
    2045              :             } else {
    2046            7 :                 HPWH.FanOutletNode = HPWH.HeatPumpAirOutletNode;
    2047              :             }
    2048           12 :         } else if (HPWH.fanPlace == HVAC::FanPlace::BlowThru) {
    2049              :             // set fan outlet node variable for use in setting Node(FanOutletNode)%MassFlowRateMax for fan object
    2050           12 :             if (bIsVScoil) {
    2051            5 :                 if (HPWH.bIsIHP) {
    2052            1 :                     HPWH.FanOutletNode = IntegratedHeatPump::GetDWHCoilInletNodeIHP(state, HPWH.DXCoilType, HPWH.DXCoilName, DXCoilErrFlag);
    2053              :                 } else {
    2054            4 :                     HPWH.FanOutletNode = VariableSpeedCoils::GetCoilInletNodeVariableSpeed(state, HPWH.DXCoilType, HPWH.DXCoilName, DXCoilErrFlag);
    2055              :                 }
    2056              :             } else {
    2057            7 :                 HPWH.FanOutletNode = state.dataDXCoils->DXCoil(HPWH.DXCoilNum).AirInNode;
    2058              :             }
    2059              :         }
    2060              : 
    2061              :         // check that fan outlet node is indeed correct
    2062           23 :         int FanOutletNodeNum = state.dataFans->fans(HPWH.FanNum)->outletNodeNum;
    2063              : 
    2064           23 :         if (FanOutletNodeNum != HPWH.FanOutletNode) {
    2065            0 :             ShowSevereError(state, format("{}=\"{}\":", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    2066            0 :             ShowContinueError(state, "Heat pump water heater fan outlet node name does not match next connected component.");
    2067            0 :             if (FanOutletNodeNum != 0) {
    2068            0 :                 ShowContinueError(state, format("Fan outlet node name = {}", state.dataLoopNodes->NodeID(FanOutletNodeNum)));
    2069              :             }
    2070            0 :             if (HPWH.FanOutletNode != 0) {
    2071            0 :                 ShowContinueError(state, format("Expected fan outlet node name = {}", state.dataLoopNodes->NodeID(HPWH.FanOutletNode)));
    2072              :             }
    2073            0 :             ErrorsFound = true;
    2074              :         }
    2075           23 :         int FanInletNodeNum = state.dataFans->fans(HPWH.FanNum)->inletNodeNum;
    2076              : 
    2077           23 :         int HPWHFanInletNodeNum(0);
    2078           23 :         if (HPWH.InletAirMixerNode != 0) {
    2079            3 :             HPWHFanInletNodeNum = HPWH.InletAirMixerNode;
    2080              :         } else {
    2081           20 :             if (HPWH.InletAirConfiguration == WTTAmbientTemp::OutsideAir) {
    2082           10 :                 HPWHFanInletNodeNum = HPWH.OutsideAirNode;
    2083              :             } else {
    2084           10 :                 HPWHFanInletNodeNum = HPWH.HeatPumpAirInletNode;
    2085              :             }
    2086              :         }
    2087           23 :         if (HPWH.fanPlace == HVAC::FanPlace::BlowThru) {
    2088           12 :             if (FanInletNodeNum != HPWHFanInletNodeNum) {
    2089            0 :                 ShowSevereError(state, format("{}=\"{}\":", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    2090            0 :                 ShowContinueError(state, "Heat pump water heater fan inlet node name does not match previous connected component.");
    2091            0 :                 if (FanOutletNodeNum != 0) {
    2092            0 :                     ShowContinueError(state, format("Fan inlet node name = {}", state.dataLoopNodes->NodeID(FanInletNodeNum)));
    2093              :                 }
    2094            0 :                 if (HPWH.FanOutletNode != 0) {
    2095            0 :                     ShowContinueError(state, format("Expected fan inlet node name = {}", state.dataLoopNodes->NodeID(HPWHFanInletNodeNum)));
    2096              :                 }
    2097            0 :                 ErrorsFound = true;
    2098              :             }
    2099              :         }
    2100              : 
    2101           23 :         int DXCoilAirOutletNodeNum(0);
    2102           23 :         if ((HPWH.DXCoilNum > 0) && (bIsVScoil)) {
    2103            7 :             if (HPWH.bIsIHP) {
    2104            1 :                 DXCoilAirOutletNodeNum = IntegratedHeatPump::GetDWHCoilOutletNodeIHP(state, HPWH.DXCoilType, HPWH.DXCoilName, DXCoilErrFlag);
    2105              :             } else {
    2106            6 :                 DXCoilAirOutletNodeNum = VariableSpeedCoils::GetCoilOutletNodeVariableSpeed(state, HPWH.DXCoilType, HPWH.DXCoilName, DXCoilErrFlag);
    2107              :             }
    2108              : 
    2109           16 :         } else if (HPWH.DXCoilNum > 0) {
    2110           16 :             DXCoilAirOutletNodeNum = state.dataDXCoils->DXCoil(HPWH.DXCoilNum).AirOutNode;
    2111              :         }
    2112           23 :         if (HPWH.fanPlace == HVAC::FanPlace::DrawThru) {
    2113           11 :             if (FanInletNodeNum != DXCoilAirOutletNodeNum) {
    2114            0 :                 ShowSevereError(state, format("{}=\"{}\":", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    2115            0 :                 ShowContinueError(state, "Heat pump water heater fan inlet node name does not match previous connected component.");
    2116            0 :                 if (FanInletNodeNum != 0) {
    2117            0 :                     ShowContinueError(state, format("Fan inlet node name = {}", state.dataLoopNodes->NodeID(FanInletNodeNum)));
    2118              :                 }
    2119            0 :                 if (DXCoilAirOutletNodeNum != 0) {
    2120            0 :                     ShowContinueError(state, format("Expected fan inlet node name = {}", state.dataLoopNodes->NodeID(DXCoilAirOutletNodeNum)));
    2121              :                 }
    2122            0 :                 ErrorsFound = true;
    2123              :             }
    2124           12 :         } else if (HPWH.fanPlace == HVAC::FanPlace::BlowThru) {
    2125           12 :             int HPWHCoilOutletNodeNum(0);
    2126           12 :             if (HPWH.OutletAirSplitterNode != 0) {
    2127            0 :                 HPWHCoilOutletNodeNum = HPWH.OutletAirSplitterNode;
    2128              :             } else {
    2129           12 :                 if (HPWH.InletAirConfiguration == WTTAmbientTemp::OutsideAir) {
    2130            9 :                     HPWHCoilOutletNodeNum = HPWH.ExhaustAirNode;
    2131              :                 } else {
    2132            3 :                     HPWHCoilOutletNodeNum = HPWH.HeatPumpAirOutletNode;
    2133              :                 }
    2134              :             }
    2135           12 :             if (DXCoilAirOutletNodeNum != HPWHCoilOutletNodeNum) {
    2136            0 :                 ShowSevereError(state, format("{}=\"{}\":", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    2137            0 :                 ShowContinueError(state, "Heat pump water heater coil outlet node name does not match next connected component.");
    2138            0 :                 if (DXCoilAirOutletNodeNum != 0) {
    2139            0 :                     ShowContinueError(state, format("Coil outlet node name = {}", state.dataLoopNodes->NodeID(DXCoilAirOutletNodeNum)));
    2140              :                 }
    2141            0 :                 if (HPWHCoilOutletNodeNum != 0) {
    2142            0 :                     ShowContinueError(state, format("Expected coil outlet node name = {}", state.dataLoopNodes->NodeID(HPWHCoilOutletNodeNum)));
    2143              :                 }
    2144            0 :                 ErrorsFound = true;
    2145              :             }
    2146              :         }
    2147              : 
    2148              :         // set the max mass flow rate for outdoor fans
    2149           23 :         if (HPWH.FanOutletNode > 0) {
    2150           23 :             state.dataLoopNodes->Node(HPWH.FanOutletNode).MassFlowRateMax =
    2151           46 :                 HPWH.OperatingAirFlowRate * Psychrometrics::PsyRhoAirFnPbTdbW(state, state.dataEnvrn->OutBaroPress, 20.0, 0.0);
    2152              :         }
    2153              : 
    2154           23 :         if (HPWH.fanPlace == HVAC::FanPlace::BlowThru) {
    2155           12 :             if (HPWH.InletAirMixerNode > 0) {
    2156            0 :                 HPWH.FanInletNode_str = hpwhAlpha[26 + nAlphaOffset];
    2157            0 :                 HPWH.FanOutletNode_str = "UNDEFINED";
    2158              :             } else {
    2159           12 :                 if (HPWH.OutsideAirNode == 0) {
    2160            3 :                     HPWH.FanInletNode_str = hpwhAlpha[7 + nAlphaOffset];
    2161            3 :                     HPWH.FanOutletNode_str = "UNDEFINED";
    2162              :                 } else {
    2163            9 :                     HPWH.FanInletNode_str = hpwhAlpha[9 + nAlphaOffset];
    2164            9 :                     HPWH.FanOutletNode_str = "UNDEFINED";
    2165              :                 }
    2166              :             }
    2167           12 :             if (HPWH.OutletAirSplitterNode > 0) {
    2168            0 :                 HPWH.CoilInletNode_str = "UNDEFINED";
    2169            0 :                 HPWH.CoilOutletNode_str = hpwhAlpha[27 + nAlphaOffset];
    2170              :             } else {
    2171           12 :                 if (HPWH.OutsideAirNode == 0) {
    2172            3 :                     HPWH.CoilInletNode_str = "UNDEFINED";
    2173            3 :                     HPWH.CoilOutletNode_str = hpwhAlpha[8 + nAlphaOffset];
    2174              :                 } else {
    2175            9 :                     HPWH.CoilInletNode_str = "UNDEFINED";
    2176            9 :                     HPWH.CoilOutletNode_str = hpwhAlpha[10 + nAlphaOffset];
    2177              :                 }
    2178              :             }
    2179              :         } else {
    2180           11 :             if (HPWH.InletAirMixerNode > 0) {
    2181            3 :                 HPWH.CoilInletNode_str = hpwhAlpha[26 + nAlphaOffset];
    2182            3 :                 HPWH.CoilOutletNode_str = "UNDEFINED";
    2183              :             } else {
    2184            8 :                 if (HPWH.OutsideAirNode == 0) {
    2185            7 :                     HPWH.CoilInletNode_str = hpwhAlpha[7 + nAlphaOffset];
    2186            7 :                     HPWH.CoilOutletNode_str = "UNDEFINED";
    2187              :                 } else {
    2188            1 :                     HPWH.CoilInletNode_str = hpwhAlpha[9 + nAlphaOffset];
    2189            1 :                     HPWH.CoilOutletNode_str = "UNDEFINED";
    2190              :                 }
    2191              :             }
    2192           11 :             if (HPWH.OutletAirSplitterNode > 0) {
    2193            3 :                 HPWH.FanInletNode_str = "UNDEFINED";
    2194            3 :                 HPWH.FanOutletNode_str = hpwhAlpha[27 + nAlphaOffset];
    2195              :             } else {
    2196            8 :                 if (HPWH.OutsideAirNode == 0) {
    2197            7 :                     HPWH.FanInletNode_str = "UNDEFINED";
    2198            7 :                     HPWH.FanOutletNode_str = hpwhAlpha[8 + nAlphaOffset];
    2199              :                 } else {
    2200            1 :                     HPWH.FanInletNode_str = "UNDEFINED";
    2201            1 :                     HPWH.FanOutletNode_str = hpwhAlpha[10 + nAlphaOffset];
    2202              :                 }
    2203              :             }
    2204              :         }
    2205              : 
    2206              :         // set up comp set for air side nodes (can be blow thru or draw thru, may or may not have damper nodes)
    2207           23 :         if (HPWH.bIsIHP) {
    2208            2 :             BranchNodeConnections::SetUpCompSets(
    2209            2 :                 state, HPWH.Type, HPWH.Name, HPWH.DXCoilType, HPWH.DXCoilName + " Outdoor Coil", HPWH.CoilInletNode_str, HPWH.CoilOutletNode_str);
    2210              :         } else {
    2211           22 :             BranchNodeConnections::SetUpCompSets(
    2212              :                 state, HPWH.Type, HPWH.Name, HPWH.DXCoilType, HPWH.DXCoilName, HPWH.CoilInletNode_str, HPWH.CoilOutletNode_str);
    2213              :         }
    2214              : 
    2215           46 :         BranchNodeConnections::SetUpCompSets(
    2216           23 :             state, HPWH.Type, HPWH.Name, HVAC::fanTypeNames[(int)HPWH.fanType], HPWH.FanName, HPWH.FanInletNode_str, HPWH.FanOutletNode_str);
    2217              : 
    2218              :         // Control Logic Flag
    2219           43 :         std::string CtrlLogicFlag = hpwhAlphaBlank[29 + nAlphaOffset] ? "SIMULTANEOUS" : hpwhAlpha[29 + nAlphaOffset];
    2220           23 :         if (Util::SameString(CtrlLogicFlag, "SIMULTANEOUS")) {
    2221           20 :             HPWH.AllowHeatingElementAndHeatPumpToRunAtSameTime = true;
    2222            3 :         } else if (Util::SameString(CtrlLogicFlag, "MUTUALLYEXCLUSIVE")) {
    2223            3 :             HPWH.AllowHeatingElementAndHeatPumpToRunAtSameTime = false;
    2224              :         } else {
    2225            0 :             ShowSevereError(state, format("{}=\"{}\":", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    2226            0 :             ShowContinueError(state, format("{} is not a valid value for field Tank Element Control Logic.", CtrlLogicFlag));
    2227            0 :             ErrorsFound = true;
    2228              :         }
    2229              : 
    2230              :         // Control Sensor 1 Location In Stratified Tank
    2231           23 :         if (!hpwhNumericBlank[8 + nNumericOffset]) {
    2232           11 :             HPWH.ControlSensor1Height = hpwhNumeric[8 + nNumericOffset];
    2233              :         } else {
    2234              :             // use heater1 location, which we don't know right now
    2235           12 :             HPWH.ControlSensor1Height = -1.0;
    2236              :         }
    2237              : 
    2238              :         // Control Sensor 1 Weight
    2239           23 :         HPWH.ControlSensor1Weight = hpwhNumericBlank[9 + nNumericOffset] ? 1.0 : hpwhNumeric[9 + nNumericOffset];
    2240              : 
    2241              :         // Control Sensor 2 Location In Stratified Tank
    2242           23 :         if (!hpwhNumericBlank[10 + nNumericOffset]) {
    2243           23 :             HPWH.ControlSensor2Height = hpwhNumeric[10 + nNumericOffset];
    2244              :         } else {
    2245            0 :             HPWH.ControlSensor2Height = -1.0;
    2246              :         }
    2247              : 
    2248              :         // Control Sensor 2 Weight
    2249           23 :         HPWH.ControlSensor2Weight = 1.0 - HPWH.ControlSensor1Weight;
    2250           23 :     }
    2251              : 
    2252            9 :     return ErrorsFound;
    2253              : }
    2254              : 
    2255          127 : bool getWaterHeaterMixedInputs(EnergyPlusData &state)
    2256              : {
    2257          127 :     bool ErrorsFound = false;
    2258          127 :     state.dataIPShortCut->cCurrentModuleObject = cMixedWHModuleObj;
    2259              :     static constexpr std::string_view routineName = "getWaterHeaterMixedInputs";
    2260              : 
    2261          307 :     for (int WaterThermalTankNum = 1; WaterThermalTankNum <= state.dataWaterThermalTanks->numWaterHeaterMixed; ++WaterThermalTankNum) {
    2262              :         int NumAlphas;
    2263              :         int NumNums;
    2264              :         int IOStat;
    2265          360 :         state.dataInputProcessing->inputProcessor->getObjectItem(state,
    2266          180 :                                                                  state.dataIPShortCut->cCurrentModuleObject,
    2267              :                                                                  WaterThermalTankNum,
    2268          180 :                                                                  state.dataIPShortCut->cAlphaArgs,
    2269              :                                                                  NumAlphas,
    2270          180 :                                                                  state.dataIPShortCut->rNumericArgs,
    2271              :                                                                  NumNums,
    2272              :                                                                  IOStat,
    2273          180 :                                                                  state.dataIPShortCut->lNumericFieldBlanks,
    2274          180 :                                                                  state.dataIPShortCut->lAlphaFieldBlanks,
    2275          180 :                                                                  state.dataIPShortCut->cAlphaFieldNames,
    2276          180 :                                                                  state.dataIPShortCut->cNumericFieldNames);
    2277              : 
    2278          180 :         ErrorObjectHeader eoh{routineName, state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)};
    2279          180 :         GlobalNames::VerifyUniqueInterObjectName(state,
    2280          180 :                                                  state.dataWaterThermalTanks->UniqueWaterThermalTankNames,
    2281          180 :                                                  state.dataIPShortCut->cAlphaArgs(1),
    2282          180 :                                                  state.dataIPShortCut->cCurrentModuleObject,
    2283          180 :                                                  state.dataIPShortCut->cAlphaFieldNames(1),
    2284              :                                                  ErrorsFound);
    2285              : 
    2286          180 :         auto &Tank = state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum);
    2287              : 
    2288          180 :         Tank.Name = state.dataIPShortCut->cAlphaArgs(1);
    2289          180 :         Tank.Type = state.dataIPShortCut->cCurrentModuleObject;
    2290          180 :         Tank.WaterThermalTankType = DataPlant::PlantEquipmentType::WtrHeaterMixed;
    2291              : 
    2292          180 :         if ((Tank.water = Fluid::GetWater(state)) == nullptr) {
    2293            0 :             ShowSevereError(state, "Fluid properties for WATER not found");
    2294            0 :             ErrorsFound = true;
    2295              :         }
    2296              : 
    2297              :         // default to always on
    2298          180 :         Tank.sourceSideAvailSched = Sched::GetScheduleAlwaysOn(state);
    2299          180 :         Tank.useSideAvailSched = Sched::GetScheduleAlwaysOn(state);
    2300              : 
    2301              :         // A user field will be added in a later release
    2302          180 :         Tank.EndUseSubcategoryName = "Water Heater";
    2303              : 
    2304          180 :         Tank.Volume = state.dataIPShortCut->rNumericArgs(1);
    2305          180 :         if (Tank.Volume == DataSizing::AutoSize) {
    2306            2 :             Tank.VolumeWasAutoSized = true;
    2307              :         }
    2308          180 :         if (state.dataIPShortCut->rNumericArgs(1) == 0.0) {
    2309              :             // Set volume to a really small number to simulate a tankless/instantaneous water heater
    2310            0 :             Tank.Volume = 0.000001; // = 1 cm3
    2311              :         }
    2312              : 
    2313          180 :         if (state.dataIPShortCut->lAlphaFieldBlanks(2)) {
    2314            0 :             ShowSevereEmptyField(state, eoh, state.dataIPShortCut->cAlphaFieldNames(2));
    2315            0 :             ErrorsFound = true;
    2316          180 :         } else if ((Tank.setptTempSched = Sched::GetSchedule(state, state.dataIPShortCut->cAlphaArgs(2))) == nullptr) {
    2317            0 :             ShowSevereItemNotFound(state, eoh, state.dataIPShortCut->cAlphaFieldNames(2), state.dataIPShortCut->cAlphaArgs(2));
    2318            0 :             ErrorsFound = true;
    2319              :         }
    2320              : 
    2321          180 :         if (state.dataIPShortCut->rNumericArgs(2) > 0.0001) {
    2322          174 :             Tank.DeadBandDeltaTemp = state.dataIPShortCut->rNumericArgs(2);
    2323              :         } else {
    2324              :             // Default to very small number (however it can't be TINY or it will break the algorithm)
    2325            6 :             Tank.DeadBandDeltaTemp = 0.5;
    2326              :         }
    2327              : 
    2328          180 :         if (state.dataIPShortCut->rNumericArgs(3) > 0.0) {
    2329          180 :             Tank.TankTempLimit = state.dataIPShortCut->rNumericArgs(3);
    2330              :         } else {
    2331              :             // Default to very large number
    2332              :             // BG comment why a large number here why not boilng point of water?
    2333            0 :             Tank.TankTempLimit = 100.0; // 1.0E9
    2334              :         }
    2335              : 
    2336          180 :         Tank.MaxCapacity = state.dataIPShortCut->rNumericArgs(4);
    2337          180 :         if (Tank.MaxCapacity == DataSizing::AutoSize) {
    2338            1 :             Tank.MaxCapacityWasAutoSized = true;
    2339              :         }
    2340              : 
    2341          180 :         if ((state.dataIPShortCut->rNumericArgs(5) > Tank.MaxCapacity) && (!Tank.MaxCapacityWasAutoSized)) {
    2342            0 :             ShowSevereError(state,
    2343            0 :                             format("{} = {}:  Heater Minimum Capacity cannot be greater than Heater Maximum Capacity",
    2344            0 :                                    state.dataIPShortCut->cCurrentModuleObject,
    2345            0 :                                    state.dataIPShortCut->cAlphaArgs(1)));
    2346            0 :             ErrorsFound = true;
    2347              :         } else {
    2348          180 :             Tank.MinCapacity = state.dataIPShortCut->rNumericArgs(5);
    2349              :         }
    2350              : 
    2351              :         // Validate Heater Control Type
    2352          180 :         Tank.ControlType =
    2353          180 :             static_cast<HeaterControlMode>(getEnumValue(HeaterControlModeNamesUC, Util::makeUPPER(state.dataIPShortCut->cAlphaArgs(3))));
    2354          180 :         switch (Tank.ControlType) {
    2355          175 :         case HeaterControlMode::Cycle: {
    2356          175 :             Tank.MinCapacity = Tank.MaxCapacity;
    2357          175 :             break;
    2358              :         }
    2359            5 :         case HeaterControlMode::Modulate: {
    2360              : 
    2361              :             // CASE ('MODULATE WITH OVERHEAT')  ! Not yet implemented
    2362              : 
    2363              :             // CASE ('MODULATE WITH UNDERHEAT')  ! Not yet implemented
    2364              : 
    2365            5 :             break;
    2366              :         }
    2367            0 :         default: {
    2368            0 :             ShowSevereError(state,
    2369            0 :                             format("{} = {}:  Invalid Control Type entered={}",
    2370            0 :                                    state.dataIPShortCut->cCurrentModuleObject,
    2371            0 :                                    state.dataIPShortCut->cAlphaArgs(1),
    2372            0 :                                    state.dataIPShortCut->cAlphaArgs(3)));
    2373            0 :             ErrorsFound = true;
    2374            0 :             break;
    2375              :         }
    2376              :         }
    2377              : 
    2378          180 :         Tank.VolFlowRateMin = state.dataIPShortCut->rNumericArgs(6);
    2379          180 :         Tank.VolFlowRateMin = max(0.0, Tank.VolFlowRateMin);
    2380          180 :         Tank.IgnitionDelay = state.dataIPShortCut->rNumericArgs(7); // Not yet implemented
    2381              : 
    2382              :         // Validate Heater Fuel Type
    2383          180 :         Tank.FuelType = static_cast<Constant::eFuel>(getEnumValue(Constant::eFuelNamesUC, state.dataIPShortCut->cAlphaArgs(4)));
    2384          180 :         switch (Tank.FuelType) {
    2385            0 :         case Constant::eFuel::Invalid: {
    2386            0 :             ShowSevereError(state,
    2387            0 :                             format("{} = {}:  Invalid Heater Fuel Type entered={}",
    2388            0 :                                    state.dataIPShortCut->cCurrentModuleObject,
    2389            0 :                                    state.dataIPShortCut->cAlphaArgs(1),
    2390            0 :                                    state.dataIPShortCut->cAlphaArgs(4)));
    2391              :             // Set to Electric to avoid errors when setting up output variables
    2392            0 :             Tank.FuelType = Constant::eFuel::Electricity;
    2393            0 :             ErrorsFound = true;
    2394            0 :             break;
    2395              :         }
    2396          180 :         default:
    2397          180 :             break;
    2398              :         }
    2399              : 
    2400          180 :         if (state.dataIPShortCut->rNumericArgs(8) > 0.0) {
    2401          180 :             Tank.Efficiency = state.dataIPShortCut->rNumericArgs(8);
    2402          180 :             if (state.dataIPShortCut->rNumericArgs(8) > 1.0) {
    2403            0 :                 ShowWarningError(state,
    2404            0 :                                  fmt::format("{} = {}: {}={} should not typically be greater than 1.",
    2405            0 :                                              state.dataIPShortCut->cCurrentModuleObject,
    2406            0 :                                              state.dataIPShortCut->cAlphaArgs(1),
    2407            0 :                                              state.dataIPShortCut->cNumericFieldNames(8),
    2408            0 :                                              state.dataIPShortCut->rNumericArgs(8)));
    2409              :             }
    2410              :         } else {
    2411            0 :             ShowSevereError(state,
    2412            0 :                             format("{} = {}:  Heater Thermal Efficiency must be greater than zero",
    2413            0 :                                    state.dataIPShortCut->cCurrentModuleObject,
    2414            0 :                                    state.dataIPShortCut->cAlphaArgs(1)));
    2415            0 :             ErrorsFound = true;
    2416              :         }
    2417              : 
    2418          180 :         if (!state.dataIPShortCut->cAlphaArgs(5).empty()) {
    2419            0 :             Tank.PLFCurve = Curve::GetCurveIndex(state, state.dataIPShortCut->cAlphaArgs(5));
    2420            0 :             if (Tank.PLFCurve == 0) {
    2421            0 :                 ShowSevereError(state,
    2422            0 :                                 format("{} = {}:  Part Load Factor curve not found = {}",
    2423            0 :                                        state.dataIPShortCut->cCurrentModuleObject,
    2424            0 :                                        state.dataIPShortCut->cAlphaArgs(1),
    2425            0 :                                        state.dataIPShortCut->cAlphaArgs(5)));
    2426            0 :                 ErrorsFound = true;
    2427              :             } else {
    2428              :                 bool IsValid;
    2429            0 :                 EnergyPlus::WaterThermalTanks::WaterThermalTankData::ValidatePLFCurve(state, Tank.PLFCurve, IsValid);
    2430              : 
    2431            0 :                 if (!IsValid) {
    2432            0 :                     ShowSevereError(
    2433              :                         state,
    2434            0 :                         format("{} = {}:  Part Load Factor curve failed to evaluate to greater than zero for all numbers in the domain of 0 to 1",
    2435            0 :                                state.dataIPShortCut->cCurrentModuleObject,
    2436            0 :                                state.dataIPShortCut->cAlphaArgs(1)));
    2437            0 :                     ErrorsFound = true;
    2438              :                 }
    2439              : 
    2440            0 :                 ErrorsFound |= Curve::CheckCurveDims(state,
    2441              :                                                      Tank.PLFCurve,                              // Curve index
    2442              :                                                      {1},                                        // Valid dimensions
    2443              :                                                      routineName,                                // Routine name
    2444            0 :                                                      state.dataIPShortCut->cCurrentModuleObject, // Object Type
    2445              :                                                      Tank.Name,                                  // Object Name
    2446            0 :                                                      state.dataIPShortCut->cAlphaFieldNames(5)); // Field Name
    2447              :             }
    2448              :         }
    2449              : 
    2450          180 :         Tank.OffCycParaLoad = state.dataIPShortCut->rNumericArgs(9);
    2451              : 
    2452              :         // Validate Off-Cycle Parasitic Fuel Type
    2453          180 :         Tank.OffCycParaFuelType = static_cast<Constant::eFuel>(getEnumValue(Constant::eFuelNamesUC, state.dataIPShortCut->cAlphaArgs(6)));
    2454          180 :         switch (Tank.OffCycParaFuelType) {
    2455           16 :         case Constant::eFuel::Invalid:
    2456           16 :             if (state.dataIPShortCut->cAlphaArgs(6).empty()) { // If blank, default to Fuel Type for heater
    2457           16 :                 Tank.OffCycParaFuelType = Tank.FuelType;
    2458              :             } else { // could have been an unsupported value
    2459            0 :                 ShowSevereError(state,
    2460            0 :                                 format("{} = {}:  Invalid Off-Cycle Parasitic Fuel Type entered={}",
    2461            0 :                                        state.dataIPShortCut->cCurrentModuleObject,
    2462            0 :                                        state.dataIPShortCut->cAlphaArgs(1),
    2463            0 :                                        state.dataIPShortCut->cAlphaArgs(6)));
    2464              :                 // Set to Electric to avoid errors when setting up output variables
    2465            0 :                 Tank.OffCycParaFuelType = Constant::eFuel::Electricity;
    2466            0 :                 ErrorsFound = true;
    2467              :             }
    2468           16 :             break;
    2469          164 :         default:
    2470          164 :             break;
    2471              :         }
    2472              : 
    2473          180 :         Tank.OffCycParaFracToTank = state.dataIPShortCut->rNumericArgs(10);
    2474              : 
    2475          180 :         Tank.OnCycParaLoad = state.dataIPShortCut->rNumericArgs(11);
    2476              : 
    2477              :         // Validate On-Cycle Parasitic Fuel Type
    2478          180 :         Tank.OnCycParaFuelType = static_cast<Constant::eFuel>(getEnumValue(Constant::eFuelNamesUC, state.dataIPShortCut->cAlphaArgs(7)));
    2479          180 :         switch (Tank.OnCycParaFuelType) {
    2480           56 :         case Constant::eFuel::Invalid:
    2481           56 :             if (state.dataIPShortCut->cAlphaArgs(7).empty()) { // If blank, default to Fuel Type for heater
    2482           56 :                 Tank.OnCycParaFuelType = Tank.FuelType;
    2483              :             } else { // could have been an unsupported value
    2484            0 :                 ShowSevereError(state,
    2485            0 :                                 format("{} = {}:  Invalid On-Cycle Parasitic Fuel Type entered={}",
    2486            0 :                                        state.dataIPShortCut->cCurrentModuleObject,
    2487            0 :                                        state.dataIPShortCut->cAlphaArgs(1),
    2488            0 :                                        state.dataIPShortCut->cAlphaArgs(7)));
    2489              :                 // Set to Electric to avoid errors when setting up output variables
    2490            0 :                 Tank.OnCycParaFuelType = Constant::eFuel::Electricity;
    2491            0 :                 ErrorsFound = true;
    2492              :             }
    2493           56 :             break;
    2494          124 :         default:
    2495          124 :             break;
    2496              :         }
    2497              : 
    2498          180 :         Tank.OnCycParaFracToTank = state.dataIPShortCut->rNumericArgs(12);
    2499              : 
    2500          180 :         Tank.AmbientTempIndicator =
    2501          180 :             static_cast<WTTAmbientTemp>(getEnumValue(TankAmbientTempNamesUC, Util::makeUPPER(state.dataIPShortCut->cAlphaArgs(8))));
    2502          180 :         switch (Tank.AmbientTempIndicator) {
    2503              : 
    2504          101 :         case WTTAmbientTemp::Schedule: {
    2505          101 :             if (state.dataIPShortCut->lAlphaFieldBlanks(9)) {
    2506            0 :                 ShowSevereEmptyField(state, eoh, state.dataIPShortCut->cAlphaFieldNames(9));
    2507            0 :                 ErrorsFound = true;
    2508          101 :             } else if ((Tank.ambientTempSched = Sched::GetSchedule(state, state.dataIPShortCut->cAlphaArgs(9))) == nullptr) {
    2509            0 :                 ShowSevereItemNotFound(state, eoh, state.dataIPShortCut->cAlphaFieldNames(9), state.dataIPShortCut->cAlphaArgs(9));
    2510            0 :                 ErrorsFound = true;
    2511              :             }
    2512          101 :         } break;
    2513              : 
    2514           72 :         case WTTAmbientTemp::TempZone: {
    2515           72 :             Tank.AmbientTempZone = Util::FindItemInList(state.dataIPShortCut->cAlphaArgs(10), state.dataHeatBal->Zone);
    2516           72 :             if (Tank.AmbientTempZone == 0) {
    2517            0 :                 ShowSevereError(state,
    2518            0 :                                 format("{} = {}:  Ambient Temperature Zone not found = {}",
    2519            0 :                                        state.dataIPShortCut->cCurrentModuleObject,
    2520            0 :                                        state.dataIPShortCut->cAlphaArgs(1),
    2521            0 :                                        state.dataIPShortCut->cAlphaArgs(10)));
    2522            0 :                 ErrorsFound = true;
    2523              :             }
    2524           72 :         } break;
    2525              : 
    2526            7 :         case WTTAmbientTemp::OutsideAir: {
    2527            7 :             Tank.AmbientTempOutsideAirNode = NodeInputManager::GetOnlySingleNode(state,
    2528            7 :                                                                                  state.dataIPShortCut->cAlphaArgs(11),
    2529              :                                                                                  ErrorsFound,
    2530              :                                                                                  DataLoopNode::ConnectionObjectType::WaterHeaterMixed,
    2531            7 :                                                                                  state.dataIPShortCut->cAlphaArgs(1),
    2532              :                                                                                  DataLoopNode::NodeFluidType::Air,
    2533              :                                                                                  DataLoopNode::ConnectionType::OutsideAirReference,
    2534              :                                                                                  NodeInputManager::CompFluidStream::Primary,
    2535              :                                                                                  DataLoopNode::ObjectIsNotParent);
    2536            7 :             if (!state.dataIPShortCut->cAlphaArgs(11).empty()) {
    2537            7 :                 if (!OutAirNodeManager::CheckOutAirNodeNumber(state, Tank.AmbientTempOutsideAirNode)) {
    2538            0 :                     ShowSevereError(state,
    2539            0 :                                     format("{} = {}: Outdoor Air Node not on OutdoorAir:NodeList or OutdoorAir:Node",
    2540            0 :                                            state.dataIPShortCut->cCurrentModuleObject,
    2541            0 :                                            state.dataIPShortCut->cAlphaArgs(1)));
    2542            0 :                     ShowContinueError(state, format("...Referenced Node Name={}", state.dataIPShortCut->cAlphaArgs(11)));
    2543            0 :                     ErrorsFound = true;
    2544              :                 }
    2545              :             } else {
    2546            0 :                 ShowSevereError(state, format("{} = {}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
    2547            0 :                 ShowContinueError(state, "An Ambient Outdoor Air Node name must be used when the Ambient Temperature Indicator is Outdoors.");
    2548            0 :                 ErrorsFound = true;
    2549              :             }
    2550              : 
    2551            7 :             break;
    2552              :         }
    2553            0 :         default: {
    2554            0 :             ShowSevereError(state,
    2555            0 :                             format("{} = {}:  Invalid Ambient Temperature Indicator entered={}",
    2556            0 :                                    state.dataIPShortCut->cCurrentModuleObject,
    2557            0 :                                    state.dataIPShortCut->cAlphaArgs(1),
    2558            0 :                                    state.dataIPShortCut->cAlphaArgs(8)));
    2559            0 :             ShowContinueError(state, " Valid entries are SCHEDULE, ZONE, and OUTDOORS.");
    2560            0 :             ErrorsFound = true;
    2561            0 :             break;
    2562              :         }
    2563              :         }
    2564              : 
    2565          180 :         Tank.OffCycLossCoeff = state.dataIPShortCut->rNumericArgs(13);
    2566          180 :         Tank.OffCycLossFracToZone = state.dataIPShortCut->rNumericArgs(14);
    2567              : 
    2568          180 :         Tank.OnCycLossCoeff = state.dataIPShortCut->rNumericArgs(15);
    2569          180 :         Tank.OnCycLossFracToZone = state.dataIPShortCut->rNumericArgs(16);
    2570          180 :         Real64 rho = Tank.water->getDensity(state, Constant::InitConvTemp, routineName);
    2571              : 
    2572          180 :         Tank.MassFlowRateMax = state.dataIPShortCut->rNumericArgs(17) * rho;
    2573              : 
    2574          180 :         if ((state.dataIPShortCut->cAlphaArgs(14).empty()) && (state.dataIPShortCut->cAlphaArgs(15).empty())) {
    2575           61 :             if (state.dataIPShortCut->lAlphaFieldBlanks(12)) {
    2576           61 :             } else if ((Tank.flowRateSched = Sched::GetSchedule(state, state.dataIPShortCut->cAlphaArgs(12))) == nullptr) {
    2577            0 :                 ShowSevereItemNotFound(state, eoh, state.dataIPShortCut->cAlphaFieldNames(12), state.dataIPShortCut->cAlphaArgs(12));
    2578            0 :                 ErrorsFound = true;
    2579              :             }
    2580              :         }
    2581              : 
    2582          180 :         if (state.dataIPShortCut->lAlphaFieldBlanks(13)) {
    2583            9 :         } else if ((Tank.useInletTempSched = Sched::GetSchedule(state, state.dataIPShortCut->cAlphaArgs(13))) == nullptr) {
    2584            0 :             ShowSevereItemNotFound(state, eoh, state.dataIPShortCut->cAlphaFieldNames(13), state.dataIPShortCut->cAlphaArgs(13));
    2585            0 :             ErrorsFound = true;
    2586              :         }
    2587              : 
    2588          180 :         if (NumNums > 17) {
    2589          135 :             if ((state.dataIPShortCut->rNumericArgs(18) > 1) || (state.dataIPShortCut->rNumericArgs(18) < 0)) {
    2590            0 :                 ShowSevereError(state,
    2591            0 :                                 format("{} = {}:  Use Side Effectiveness is out of bounds (0 to 1)",
    2592            0 :                                        state.dataIPShortCut->cCurrentModuleObject,
    2593            0 :                                        state.dataIPShortCut->cAlphaArgs(1)));
    2594            0 :                 ErrorsFound = true;
    2595              :             }
    2596          135 :             Tank.UseEffectiveness = state.dataIPShortCut->rNumericArgs(18);
    2597              :         } else {
    2598           45 :             Tank.UseEffectiveness = 1.0; // Default for stand-alone mode
    2599              :         }
    2600              : 
    2601          180 :         if (NumNums > 18) {
    2602          135 :             if ((state.dataIPShortCut->rNumericArgs(19) > 1) || (state.dataIPShortCut->rNumericArgs(19) <= 0)) {
    2603            0 :                 ShowSevereError(state,
    2604            0 :                                 format("{} = {}:  Source Side Effectiveness is out of bounds (>0 to 1)",
    2605            0 :                                        state.dataIPShortCut->cCurrentModuleObject,
    2606            0 :                                        state.dataIPShortCut->cAlphaArgs(1)));
    2607            0 :                 ErrorsFound = true;
    2608              :             }
    2609          135 :             Tank.SourceEffectiveness = state.dataIPShortCut->rNumericArgs(19);
    2610              :         } else {
    2611           45 :             Tank.SourceEffectiveness = 1.0;
    2612              :         }
    2613              : 
    2614              :         // If no plant nodes are connected, simulate in stand-alone mode.
    2615          302 :         if (state.dataIPShortCut->cAlphaArgs(14).empty() && state.dataIPShortCut->cAlphaArgs(15).empty() &&
    2616          302 :             state.dataIPShortCut->cAlphaArgs(16).empty() && state.dataIPShortCut->cAlphaArgs(17).empty()) {
    2617           47 :             Tank.StandAlone = true;
    2618              :         }
    2619              : 
    2620          180 :         if (!state.dataIPShortCut->lNumericFieldBlanks(20)) {
    2621          119 :             Tank.UseDesignVolFlowRate = state.dataIPShortCut->rNumericArgs(20);
    2622          119 :             if (Tank.UseDesignVolFlowRate == DataSizing::AutoSize) {
    2623          113 :                 Tank.UseDesignVolFlowRateWasAutoSized = true;
    2624              :             }
    2625              :         } else {
    2626           61 :             Tank.UseDesignVolFlowRate = 0.0;
    2627              :         }
    2628          180 :         Tank.UseSidePlantLoc.loopSideNum = DataPlant::LoopSideLocation::Invalid;
    2629              : 
    2630          180 :         if (!state.dataIPShortCut->lNumericFieldBlanks(21)) {
    2631          111 :             Tank.SourceDesignVolFlowRate = state.dataIPShortCut->rNumericArgs(21);
    2632          111 :             if (Tank.SourceDesignVolFlowRate == DataSizing::AutoSize) {
    2633          101 :                 Tank.SourceDesignVolFlowRateWasAutoSized = true;
    2634              :             }
    2635              :         } else {
    2636           69 :             Tank.SourceDesignVolFlowRate = 0.0;
    2637              :         }
    2638          180 :         Tank.SrcSidePlantLoc.loopSideNum = DataPlant::LoopSideLocation::Invalid;
    2639              : 
    2640          180 :         if (!state.dataIPShortCut->lNumericFieldBlanks(22)) {
    2641           97 :             Tank.SizingRecoveryTime = state.dataIPShortCut->rNumericArgs(22);
    2642              :         } else {
    2643           83 :             Tank.SizingRecoveryTime = 1.5;
    2644              :         }
    2645              : 
    2646          180 :         if ((!state.dataIPShortCut->cAlphaArgs(14).empty()) || (!state.dataIPShortCut->cAlphaArgs(15).empty())) {
    2647          119 :             Tank.UseInletNode = NodeInputManager::GetOnlySingleNode(state,
    2648          119 :                                                                     state.dataIPShortCut->cAlphaArgs(14),
    2649              :                                                                     ErrorsFound,
    2650              :                                                                     DataLoopNode::ConnectionObjectType::WaterHeaterMixed,
    2651          119 :                                                                     state.dataIPShortCut->cAlphaArgs(1),
    2652              :                                                                     DataLoopNode::NodeFluidType::Water,
    2653              :                                                                     DataLoopNode::ConnectionType::Inlet,
    2654              :                                                                     NodeInputManager::CompFluidStream::Primary,
    2655              :                                                                     DataLoopNode::ObjectIsNotParent);
    2656          119 :             Tank.InletNodeName1 = state.dataIPShortCut->cAlphaArgs(14);
    2657          119 :             Tank.UseOutletNode = NodeInputManager::GetOnlySingleNode(state,
    2658          119 :                                                                      state.dataIPShortCut->cAlphaArgs(15),
    2659              :                                                                      ErrorsFound,
    2660              :                                                                      DataLoopNode::ConnectionObjectType::WaterHeaterMixed,
    2661          119 :                                                                      state.dataIPShortCut->cAlphaArgs(1),
    2662              :                                                                      DataLoopNode::NodeFluidType::Water,
    2663              :                                                                      DataLoopNode::ConnectionType::Outlet,
    2664              :                                                                      NodeInputManager::CompFluidStream::Primary,
    2665              :                                                                      DataLoopNode::ObjectIsNotParent);
    2666          119 :             Tank.OutletNodeName1 = state.dataIPShortCut->cAlphaArgs(15);
    2667              : 
    2668          119 :             if (state.dataIPShortCut->rNumericArgs(17) > 0) {
    2669            0 :                 ShowWarningError(state,
    2670            0 :                                  format("{} = {}:  Use side nodes are specified; Peak Volumetric Use Flow Rate will not be used",
    2671            0 :                                         state.dataIPShortCut->cCurrentModuleObject,
    2672            0 :                                         state.dataIPShortCut->cAlphaArgs(1)));
    2673              :             }
    2674              : 
    2675          119 :             if (Tank.flowRateSched != nullptr) {
    2676            0 :                 ShowWarningError(state,
    2677            0 :                                  format("{} = {}:  Use side nodes are specified; Use Flow Rate Fraction Schedule will not be used",
    2678            0 :                                         state.dataIPShortCut->cCurrentModuleObject,
    2679            0 :                                         state.dataIPShortCut->cAlphaArgs(1)));
    2680              :             }
    2681              : 
    2682          119 :             if (Tank.useInletTempSched != nullptr) {
    2683            0 :                 ShowWarningError(state,
    2684            0 :                                  format("{} = {}:  Use side nodes are specified; Cold Water Supply Temperature Schedule will not be used",
    2685            0 :                                         state.dataIPShortCut->cCurrentModuleObject,
    2686            0 :                                         state.dataIPShortCut->cAlphaArgs(1)));
    2687              :             }
    2688              :         }
    2689              : 
    2690          180 :         if ((!state.dataIPShortCut->cAlphaArgs(16).empty()) || (!state.dataIPShortCut->cAlphaArgs(17).empty())) {
    2691           33 :             Tank.SourceInletNode = NodeInputManager::GetOnlySingleNode(state,
    2692           33 :                                                                        state.dataIPShortCut->cAlphaArgs(16),
    2693              :                                                                        ErrorsFound,
    2694              :                                                                        DataLoopNode::ConnectionObjectType::WaterHeaterMixed,
    2695           33 :                                                                        state.dataIPShortCut->cAlphaArgs(1),
    2696              :                                                                        DataLoopNode::NodeFluidType::Water,
    2697              :                                                                        DataLoopNode::ConnectionType::Inlet,
    2698              :                                                                        NodeInputManager::CompFluidStream::Secondary,
    2699              :                                                                        DataLoopNode::ObjectIsNotParent);
    2700           33 :             Tank.InletNodeName2 = state.dataIPShortCut->cAlphaArgs(16);
    2701           33 :             Tank.SourceOutletNode = NodeInputManager::GetOnlySingleNode(state,
    2702           33 :                                                                         state.dataIPShortCut->cAlphaArgs(17),
    2703              :                                                                         ErrorsFound,
    2704              :                                                                         DataLoopNode::ConnectionObjectType::WaterHeaterMixed,
    2705           33 :                                                                         state.dataIPShortCut->cAlphaArgs(1),
    2706              :                                                                         DataLoopNode::NodeFluidType::Water,
    2707              :                                                                         DataLoopNode::ConnectionType::Outlet,
    2708              :                                                                         NodeInputManager::CompFluidStream::Secondary,
    2709              :                                                                         DataLoopNode::ObjectIsNotParent);
    2710           33 :             Tank.OutletNodeName2 = state.dataIPShortCut->cAlphaArgs(17);
    2711              :         }
    2712              : 
    2713          180 :         if (!state.dataIPShortCut->lAlphaFieldBlanks(18)) {
    2714            3 :             Tank.SourceSideControlMode =
    2715            3 :                 static_cast<SourceSideControl>(getEnumValue(SourceSideControlNamesUC, Util::makeUPPER(state.dataIPShortCut->cAlphaArgs(18))));
    2716            3 :             if (Tank.SourceSideControlMode == SourceSideControl::Invalid) {
    2717            0 :                 ShowSevereError(state,
    2718            0 :                                 format("{} = {}:  Invalid Control Mode entered={}",
    2719            0 :                                        state.dataIPShortCut->cCurrentModuleObject,
    2720            0 :                                        state.dataIPShortCut->cAlphaArgs(1),
    2721            0 :                                        state.dataIPShortCut->cAlphaArgs(18)));
    2722            0 :                 ErrorsFound = true;
    2723              :             }
    2724              :         } else {
    2725          177 :             Tank.SourceSideControlMode = SourceSideControl::IndirectHeatPrimarySetpoint;
    2726              :         }
    2727              : 
    2728          180 :         if (state.dataIPShortCut->lAlphaFieldBlanks(19)) {
    2729            0 :         } else if ((Tank.sourceSideAltSetpointSched = Sched::GetSchedule(state, state.dataIPShortCut->cAlphaArgs(19))) == nullptr) {
    2730            0 :             ShowSevereItemNotFound(state, eoh, state.dataIPShortCut->cAlphaFieldNames(19), state.dataIPShortCut->cAlphaArgs(19));
    2731            0 :             ErrorsFound = true;
    2732              :         }
    2733              : 
    2734          180 :         if (NumAlphas > 19) {
    2735            3 :             Tank.EndUseSubcategoryName = state.dataIPShortCut->cAlphaArgs(20);
    2736              :         }
    2737              : 
    2738              :     } // WaterThermalTankNum
    2739              : 
    2740          127 :     return ErrorsFound;
    2741              : }
    2742              : 
    2743           10 : bool getWaterHeaterStratifiedInput(EnergyPlusData &state)
    2744              : {
    2745           10 :     bool ErrorsFound = false;
    2746              :     static constexpr std::string_view routineName = "getWaterHeaterStratifiedInput";
    2747              : 
    2748           10 :     state.dataIPShortCut->cCurrentModuleObject = cStratifiedWHModuleObj; //'WaterHeater:Stratified'
    2749              : 
    2750           26 :     for (int WaterThermalTankNum = state.dataWaterThermalTanks->numWaterHeaterMixed + 1;
    2751           26 :          WaterThermalTankNum <= state.dataWaterThermalTanks->numWaterHeaterMixed + state.dataWaterThermalTanks->numWaterHeaterStratified;
    2752              :          ++WaterThermalTankNum) {
    2753              :         int NumAlphas;
    2754              :         int NumNums;
    2755              :         int IOStat;
    2756           32 :         state.dataInputProcessing->inputProcessor->getObjectItem(state,
    2757           16 :                                                                  state.dataIPShortCut->cCurrentModuleObject,
    2758           16 :                                                                  WaterThermalTankNum - state.dataWaterThermalTanks->numWaterHeaterMixed,
    2759           16 :                                                                  state.dataIPShortCut->cAlphaArgs,
    2760              :                                                                  NumAlphas,
    2761           16 :                                                                  state.dataIPShortCut->rNumericArgs,
    2762              :                                                                  NumNums,
    2763              :                                                                  IOStat,
    2764           16 :                                                                  state.dataIPShortCut->lNumericFieldBlanks,
    2765           16 :                                                                  state.dataIPShortCut->lAlphaFieldBlanks,
    2766           16 :                                                                  state.dataIPShortCut->cAlphaFieldNames,
    2767           16 :                                                                  state.dataIPShortCut->cNumericFieldNames);
    2768              : 
    2769           16 :         ErrorObjectHeader eoh{routineName, state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)};
    2770              : 
    2771           16 :         GlobalNames::VerifyUniqueInterObjectName(state,
    2772           16 :                                                  state.dataWaterThermalTanks->UniqueWaterThermalTankNames,
    2773           16 :                                                  state.dataIPShortCut->cAlphaArgs(1),
    2774           16 :                                                  state.dataIPShortCut->cCurrentModuleObject,
    2775           16 :                                                  state.dataIPShortCut->cAlphaFieldNames(1),
    2776              :                                                  ErrorsFound);
    2777              : 
    2778           16 :         auto &Tank = state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum);
    2779              : 
    2780           16 :         Tank.Name = state.dataIPShortCut->cAlphaArgs(1);
    2781           16 :         Tank.Type = state.dataIPShortCut->cCurrentModuleObject;
    2782           16 :         Tank.WaterThermalTankType = DataPlant::PlantEquipmentType::WtrHeaterStratified;
    2783              : 
    2784           16 :         if ((Tank.water = Fluid::GetWater(state)) == nullptr) {
    2785            0 :             ShowSevereError(state, "Fluid Properties for WATER not found.");
    2786            0 :             ErrorsFound = true;
    2787              :         }
    2788              : 
    2789              :         // default to always on
    2790           16 :         Tank.sourceSideAvailSched = Sched::GetScheduleAlwaysOn(state);
    2791           16 :         Tank.useSideAvailSched = Sched::GetScheduleAlwaysOn(state);
    2792              : 
    2793           16 :         Tank.EndUseSubcategoryName = state.dataIPShortCut->cAlphaArgs(2);
    2794              : 
    2795           16 :         Tank.Volume = state.dataIPShortCut->rNumericArgs(1);
    2796           16 :         if (Tank.Volume == DataSizing::AutoSize) {
    2797            0 :             Tank.VolumeWasAutoSized = true;
    2798              :         }
    2799           16 :         Real64 rho = Tank.water->getDensity(state, Constant::InitConvTemp, routineName);
    2800           16 :         Tank.Mass = Tank.Volume * rho;
    2801           16 :         Tank.Height = state.dataIPShortCut->rNumericArgs(2);
    2802           16 :         if (Tank.Height == DataSizing::AutoSize) {
    2803            0 :             Tank.HeightWasAutoSized = true;
    2804              :         }
    2805              : 
    2806           16 :         Tank.Shape = static_cast<TankShape>(getEnumValue(TankShapeNamesUC, Util::makeUPPER(state.dataIPShortCut->cAlphaArgs(3))));
    2807           16 :         switch (Tank.Shape) {
    2808           16 :         case TankShape::HorizCylinder:
    2809              :         case TankShape::VertCylinder: {
    2810           16 :             break;
    2811              :         }
    2812            0 :         case TankShape::Other: {
    2813            0 :             if (state.dataIPShortCut->rNumericArgs(3) > 0.0) {
    2814            0 :                 Tank.Perimeter = state.dataIPShortCut->rNumericArgs(3);
    2815              :             } else {
    2816            0 :                 ShowSevereError(state,
    2817            0 :                                 format("{} = {}:  Tank Perimeter must be greater than zero for Tank Shape=OTHER",
    2818            0 :                                        state.dataIPShortCut->cCurrentModuleObject,
    2819            0 :                                        state.dataIPShortCut->cAlphaArgs(1)));
    2820            0 :                 ErrorsFound = true;
    2821              :             }
    2822              : 
    2823            0 :             break;
    2824              :         }
    2825            0 :         default: {
    2826            0 :             ShowSevereError(state,
    2827            0 :                             format("{} = {}:  Invalid Tank Shape entered={}",
    2828            0 :                                    state.dataIPShortCut->cCurrentModuleObject,
    2829            0 :                                    state.dataIPShortCut->cAlphaArgs(1),
    2830            0 :                                    state.dataIPShortCut->cAlphaArgs(3)));
    2831            0 :             Tank.Shape = TankShape::VertCylinder;
    2832            0 :             ErrorsFound = true;
    2833            0 :             break;
    2834              :         }
    2835              :         }
    2836              : 
    2837           16 :         if (state.dataIPShortCut->rNumericArgs(4) > 0.0) {
    2838           16 :             Tank.TankTempLimit = state.dataIPShortCut->rNumericArgs(4);
    2839              :         } else {
    2840              :             // Default to very large number
    2841            0 :             Tank.TankTempLimit = 1.0e9;
    2842              :         }
    2843              : 
    2844              :         // Validate Heater Priority Control
    2845           16 :         Tank.StratifiedControlMode =
    2846           16 :             static_cast<PriorityControlMode>(getEnumValue(PriorityControlModeNamesUC, Util::makeUPPER(state.dataIPShortCut->cAlphaArgs(4))));
    2847           16 :         if (Tank.StratifiedControlMode == PriorityControlMode::Invalid) {
    2848            0 :             ShowSevereError(state,
    2849            0 :                             format("{} = {}:  Invalid Heater Priority Control entered={}",
    2850            0 :                                    state.dataIPShortCut->cCurrentModuleObject,
    2851            0 :                                    state.dataIPShortCut->cAlphaArgs(1),
    2852            0 :                                    state.dataIPShortCut->cAlphaArgs(4)));
    2853            0 :             ErrorsFound = true;
    2854              :         }
    2855              : 
    2856           16 :         if (state.dataIPShortCut->lAlphaFieldBlanks(5)) {
    2857            0 :             ShowSevereEmptyField(state, eoh, state.dataIPShortCut->cAlphaFieldNames(5));
    2858            0 :             ErrorsFound = true;
    2859           16 :         } else if ((Tank.setptTempSched = Sched::GetSchedule(state, state.dataIPShortCut->cAlphaArgs(5))) == nullptr) {
    2860            0 :             ShowSevereItemNotFound(state, eoh, state.dataIPShortCut->cAlphaFieldNames(5), state.dataIPShortCut->cAlphaArgs(5));
    2861            0 :             ErrorsFound = true;
    2862              :         }
    2863              : 
    2864           16 :         if (state.dataIPShortCut->rNumericArgs(5) > 0.0) {
    2865           16 :             Tank.DeadBandDeltaTemp = state.dataIPShortCut->rNumericArgs(5);
    2866              :         } else {
    2867              :             // Default to very small number (however it can't be TINY or it will break the algorithm)
    2868            0 :             Tank.DeadBandDeltaTemp = 0.0001;
    2869              :         }
    2870              : 
    2871           16 :         Tank.MaxCapacity = state.dataIPShortCut->rNumericArgs(6);
    2872           16 :         if (Tank.MaxCapacity == DataSizing::AutoSize) {
    2873            2 :             Tank.MaxCapacityWasAutoSized = true;
    2874              :         }
    2875              : 
    2876           16 :         Tank.HeaterHeight1 = state.dataIPShortCut->rNumericArgs(7);
    2877              : 
    2878              :         // adjust tank height used in these calculations for testing heater height
    2879              :         Real64 tankHeightForTesting;
    2880           16 :         if (Tank.Shape == TankShape::HorizCylinder) {
    2881            0 :             tankHeightForTesting = 2.0 * sqrt((Tank.Volume / Tank.Height) / Constant::Pi);
    2882              :         } else {
    2883           16 :             tankHeightForTesting = Tank.Height;
    2884              :         }
    2885              : 
    2886              :         // Test if Heater height is within range
    2887           16 :         if ((!Tank.HeightWasAutoSized) && (Tank.HeaterHeight1 > tankHeightForTesting)) {
    2888            0 :             ShowSevereError(state,
    2889            0 :                             format("{} = {}: Heater 1 is located higher than overall tank height.",
    2890            0 :                                    state.dataIPShortCut->cCurrentModuleObject,
    2891            0 :                                    state.dataIPShortCut->cAlphaArgs(1)));
    2892            0 :             ShowContinueError(state, format("{} = {:.4R}", state.dataIPShortCut->cNumericFieldNames(2), state.dataIPShortCut->rNumericArgs(2)));
    2893            0 :             ShowContinueError(state, format("{} = {:.4R}", state.dataIPShortCut->cNumericFieldNames(7), state.dataIPShortCut->rNumericArgs(7)));
    2894            0 :             ErrorsFound = true;
    2895              :         }
    2896              : 
    2897           16 :         if (state.dataIPShortCut->lAlphaFieldBlanks(6)) {
    2898            0 :             ShowSevereEmptyField(state, eoh, state.dataIPShortCut->cAlphaFieldNames(6));
    2899            0 :             ErrorsFound = true;
    2900           16 :         } else if ((Tank.setptTemp2Sched = Sched::GetSchedule(state, state.dataIPShortCut->cAlphaArgs(6))) == nullptr) {
    2901            0 :             ShowSevereItemNotFound(state, eoh, state.dataIPShortCut->cAlphaFieldNames(6), state.dataIPShortCut->cAlphaArgs(6));
    2902            0 :             ErrorsFound = true;
    2903              :         }
    2904              : 
    2905           16 :         if (state.dataIPShortCut->rNumericArgs(5) > 0.0) {
    2906           16 :             Tank.DeadBandDeltaTemp2 = state.dataIPShortCut->rNumericArgs(8);
    2907              :         } else {
    2908              :             // Default to very small number (however it can't be TINY or it will break the algorithm)
    2909            0 :             Tank.DeadBandDeltaTemp2 = 0.0001;
    2910              :         }
    2911              : 
    2912           16 :         Tank.MaxCapacity2 = state.dataIPShortCut->rNumericArgs(9);
    2913           16 :         Tank.HeaterHeight2 = state.dataIPShortCut->rNumericArgs(10);
    2914              : 
    2915              :         // Test if Heater height is within range
    2916           16 :         if ((!Tank.HeightWasAutoSized) && (Tank.HeaterHeight2 > tankHeightForTesting)) {
    2917            0 :             ShowSevereError(state,
    2918            0 :                             format("{} = {}: Heater 2 is located higher than overall tank height.",
    2919            0 :                                    state.dataIPShortCut->cCurrentModuleObject,
    2920            0 :                                    state.dataIPShortCut->cAlphaArgs(1)));
    2921            0 :             ShowContinueError(state, format("{} = {:.4R}", state.dataIPShortCut->cNumericFieldNames(2), state.dataIPShortCut->rNumericArgs(2)));
    2922            0 :             ShowContinueError(state, format("{} = {:.4R}", state.dataIPShortCut->cNumericFieldNames(10), state.dataIPShortCut->rNumericArgs(10)));
    2923            0 :             ErrorsFound = true;
    2924              :         }
    2925              : 
    2926              :         // Validate Heater Fuel Type
    2927           16 :         Tank.FuelType = static_cast<Constant::eFuel>(
    2928           16 :             getEnumValue(Constant::eFuelNamesUC,
    2929           16 :                          state.dataIPShortCut->cAlphaArgs(
    2930              :                              7))); // returns all kinds of fuels including district heat and cool + steam, returns unassigned if unsupported
    2931           16 :         if (Tank.FuelType == Constant::eFuel::Invalid) {
    2932            0 :             ShowSevereError(state,
    2933            0 :                             format("{} = {}:  Invalid Heater Fuel Type entered={}",
    2934            0 :                                    state.dataIPShortCut->cCurrentModuleObject,
    2935            0 :                                    state.dataIPShortCut->cAlphaArgs(1),
    2936            0 :                                    state.dataIPShortCut->cAlphaArgs(7)));
    2937              :             // Set to Electric to avoid errors when setting up output variables
    2938            0 :             Tank.FuelType = Constant::eFuel::Electricity;
    2939            0 :             ErrorsFound = true;
    2940              :         }
    2941              : 
    2942           16 :         if (state.dataIPShortCut->rNumericArgs(11) > 0.0) {
    2943           16 :             Tank.Efficiency = state.dataIPShortCut->rNumericArgs(11);
    2944           16 :             if (state.dataIPShortCut->rNumericArgs(11) > 1.0) {
    2945            0 :                 ShowWarningError(state,
    2946            0 :                                  fmt::format("{} = {}: {}={} should not typically be greater than 1.",
    2947            0 :                                              state.dataIPShortCut->cCurrentModuleObject,
    2948            0 :                                              state.dataIPShortCut->cAlphaArgs(1),
    2949            0 :                                              state.dataIPShortCut->cNumericFieldNames(11),
    2950            0 :                                              state.dataIPShortCut->rNumericArgs(11)));
    2951              :             }
    2952              :         } else {
    2953            0 :             ShowSevereError(state,
    2954            0 :                             format("{} = {}:  Heater Thermal Efficiency must be greater than zero",
    2955            0 :                                    state.dataIPShortCut->cCurrentModuleObject,
    2956            0 :                                    state.dataIPShortCut->cAlphaArgs(1)));
    2957            0 :             ErrorsFound = true;
    2958              :         }
    2959              : 
    2960           16 :         Tank.OffCycParaLoad = state.dataIPShortCut->rNumericArgs(12);
    2961              : 
    2962              :         // Validate Off-Cycle Parasitic Fuel Type
    2963           16 :         Tank.OffCycParaFuelType = static_cast<Constant::eFuel>(
    2964           16 :             getEnumValue(Constant::eFuelNamesUC,
    2965           16 :                          state.dataIPShortCut->cAlphaArgs(
    2966              :                              8))); // returns all kinds of fuels including district heat and cool + steam, returns unassigned if unsupported
    2967           16 :         if (Tank.OffCycParaFuelType == Constant::eFuel::Invalid) {
    2968            0 :             if (state.dataIPShortCut->cAlphaArgs(8).empty()) {
    2969            0 :                 Tank.OffCycParaFuelType = Tank.FuelType;
    2970              :             } else {
    2971            0 :                 ShowSevereError(state,
    2972            0 :                                 format("{} = {}:  Invalid Off-Cycle Parasitic Fuel Type entered={}",
    2973            0 :                                        state.dataIPShortCut->cCurrentModuleObject,
    2974            0 :                                        state.dataIPShortCut->cAlphaArgs(1),
    2975            0 :                                        state.dataIPShortCut->cAlphaArgs(8)));
    2976              :                 // Set to Electric to avoid errors when setting up output variables
    2977            0 :                 Tank.OffCycParaFuelType = Constant::eFuel::Electricity;
    2978            0 :                 ErrorsFound = true;
    2979              :             }
    2980              :         }
    2981              : 
    2982           16 :         Tank.OffCycParaFracToTank = state.dataIPShortCut->rNumericArgs(13);
    2983           16 :         Tank.OffCycParaHeight = state.dataIPShortCut->rNumericArgs(14);
    2984              : 
    2985           16 :         Tank.OnCycParaLoad = state.dataIPShortCut->rNumericArgs(15);
    2986              : 
    2987              :         // Validate On-Cycle Parasitic Fuel Type
    2988           16 :         Tank.OnCycParaFuelType = static_cast<Constant::eFuel>(
    2989           16 :             getEnumValue(Constant::eFuelNamesUC,
    2990           16 :                          state.dataIPShortCut->cAlphaArgs(
    2991              :                              9))); // returns all kinds of fuels including district heat and cool + steam, returns unassigned if unsupported/empty
    2992           16 :         if (Tank.OnCycParaFuelType == Constant::eFuel::Invalid) {
    2993            0 :             if (state.dataIPShortCut->cAlphaArgs(9).empty()) {
    2994            0 :                 Tank.OnCycParaFuelType = Tank.FuelType;
    2995              :             } else {
    2996            0 :                 ShowSevereError(state,
    2997            0 :                                 format("{} = {}:  Invalid On-Cycle Parasitic Fuel Type entered={}",
    2998            0 :                                        state.dataIPShortCut->cCurrentModuleObject,
    2999            0 :                                        state.dataIPShortCut->cAlphaArgs(1),
    3000            0 :                                        state.dataIPShortCut->cAlphaArgs(9)));
    3001              :                 // Set to Electric to avoid errors when setting up output variables
    3002            0 :                 Tank.OnCycParaFuelType = Constant::eFuel::Electricity;
    3003            0 :                 ErrorsFound = true;
    3004              :             }
    3005              :         }
    3006              : 
    3007           16 :         Tank.OnCycParaFracToTank = state.dataIPShortCut->rNumericArgs(16);
    3008           16 :         Tank.OnCycParaHeight = state.dataIPShortCut->rNumericArgs(17);
    3009              : 
    3010           16 :         Tank.AmbientTempIndicator =
    3011           16 :             static_cast<WTTAmbientTemp>(getEnumValue(TankAmbientTempNamesUC, Util::makeUPPER(state.dataIPShortCut->cAlphaArgs(10))));
    3012           16 :         switch (Tank.AmbientTempIndicator) {
    3013              : 
    3014            8 :         case WTTAmbientTemp::Schedule: {
    3015            8 :             if (state.dataIPShortCut->lAlphaFieldBlanks(11)) {
    3016            0 :                 ShowSevereEmptyField(state, eoh, state.dataIPShortCut->cAlphaFieldNames(11));
    3017            0 :                 ErrorsFound = true;
    3018            8 :             } else if ((Tank.ambientTempSched = Sched::GetSchedule(state, state.dataIPShortCut->cAlphaArgs(11))) == nullptr) {
    3019            0 :                 ShowSevereItemNotFound(state, eoh, state.dataIPShortCut->cAlphaFieldNames(11), state.dataIPShortCut->cAlphaArgs(11));
    3020            0 :                 ErrorsFound = true;
    3021              :             }
    3022            8 :         } break;
    3023              : 
    3024            6 :         case WTTAmbientTemp::TempZone: {
    3025            6 :             Tank.AmbientTempZone = Util::FindItemInList(state.dataIPShortCut->cAlphaArgs(12), state.dataHeatBal->Zone);
    3026            6 :             if (Tank.AmbientTempZone == 0) {
    3027            0 :                 ShowSevereError(state,
    3028            0 :                                 format("{} = {}:  Ambient Temperature Zone not found = {}",
    3029            0 :                                        state.dataIPShortCut->cCurrentModuleObject,
    3030            0 :                                        state.dataIPShortCut->cAlphaArgs(1),
    3031            0 :                                        state.dataIPShortCut->cAlphaArgs(12)));
    3032            0 :                 ErrorsFound = true;
    3033              :             }
    3034              : 
    3035            6 :             break;
    3036              :         }
    3037            2 :         case WTTAmbientTemp::OutsideAir: {
    3038            2 :             Tank.AmbientTempOutsideAirNode = NodeInputManager::GetOnlySingleNode(state,
    3039            2 :                                                                                  state.dataIPShortCut->cAlphaArgs(13),
    3040              :                                                                                  ErrorsFound,
    3041              :                                                                                  DataLoopNode::ConnectionObjectType::WaterHeaterStratified,
    3042            2 :                                                                                  state.dataIPShortCut->cAlphaArgs(1),
    3043              :                                                                                  DataLoopNode::NodeFluidType::Air,
    3044              :                                                                                  DataLoopNode::ConnectionType::Inlet,
    3045              :                                                                                  NodeInputManager::CompFluidStream::Primary,
    3046              :                                                                                  DataLoopNode::ObjectIsNotParent);
    3047            2 :             if (!state.dataIPShortCut->cAlphaArgs(13).empty()) {
    3048            2 :                 if (!OutAirNodeManager::CheckOutAirNodeNumber(state, Tank.AmbientTempOutsideAirNode)) {
    3049            0 :                     ShowSevereError(state,
    3050            0 :                                     format("{} = {}: Outdoor Air Node not on OutdoorAir:NodeList or OutdoorAir:Node",
    3051            0 :                                            state.dataIPShortCut->cCurrentModuleObject,
    3052            0 :                                            state.dataIPShortCut->cAlphaArgs(1)));
    3053            0 :                     ShowContinueError(state, format("...Referenced Node Name={}", state.dataIPShortCut->cAlphaArgs(13)));
    3054            0 :                     ErrorsFound = true;
    3055              :                 }
    3056              :             } else {
    3057            0 :                 ShowSevereError(state, format("{} = {}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
    3058            0 :                 ShowContinueError(state, "An Ambient Outdoor Air Node name must be used when the Ambient Temperature Indicator is Outdoors.");
    3059            0 :                 ErrorsFound = true;
    3060              :             }
    3061              : 
    3062            2 :             break;
    3063              :         }
    3064            0 :         default: {
    3065            0 :             ShowSevereError(state,
    3066            0 :                             format("{} = {}:  Invalid Ambient Temperature Indicator entered={}",
    3067            0 :                                    state.dataIPShortCut->cCurrentModuleObject,
    3068            0 :                                    state.dataIPShortCut->cAlphaArgs(1),
    3069            0 :                                    state.dataIPShortCut->cAlphaArgs(10)));
    3070            0 :             ShowContinueError(state, " Valid entries are Schedule, Zone, and Outdoors.");
    3071            0 :             ErrorsFound = true;
    3072            0 :             break;
    3073              :         }
    3074              :         }
    3075              : 
    3076           16 :         Tank.SkinLossCoeff = state.dataIPShortCut->rNumericArgs(18);
    3077           16 :         Tank.SkinLossFracToZone = state.dataIPShortCut->rNumericArgs(19);
    3078           16 :         Tank.OffCycFlueLossCoeff = state.dataIPShortCut->rNumericArgs(20);
    3079           16 :         Tank.OffCycFlueLossFracToZone = state.dataIPShortCut->rNumericArgs(21);
    3080              : 
    3081              :         // this is temporary until we know fluid type
    3082           16 :         rho = Tank.water->getDensity(state, Constant::InitConvTemp, routineName);
    3083              : 
    3084           16 :         Tank.MassFlowRateMax = state.dataIPShortCut->rNumericArgs(22) * rho;
    3085              : 
    3086           16 :         if ((state.dataIPShortCut->cAlphaArgs(16).empty()) && (state.dataIPShortCut->cAlphaArgs(17).empty())) {
    3087            7 :             if (state.dataIPShortCut->lAlphaFieldBlanks(14)) {
    3088            7 :             } else if ((Tank.flowRateSched = Sched::GetSchedule(state, state.dataIPShortCut->cAlphaArgs(14))) == nullptr) {
    3089            0 :                 ShowSevereItemNotFound(state, eoh, state.dataIPShortCut->cAlphaFieldNames(14), state.dataIPShortCut->cAlphaArgs(14));
    3090            0 :                 ErrorsFound = true;
    3091              :             }
    3092              :         }
    3093              : 
    3094           16 :         if (state.dataIPShortCut->lAlphaFieldBlanks(15)) {
    3095            0 :         } else if ((Tank.useInletTempSched = Sched::GetSchedule(state, state.dataIPShortCut->cAlphaArgs(15))) == nullptr) {
    3096            0 :             ShowSevereItemNotFound(state, eoh, state.dataIPShortCut->cAlphaFieldNames(15), state.dataIPShortCut->cAlphaArgs(15));
    3097            0 :             ErrorsFound = true;
    3098              :         }
    3099              : 
    3100           16 :         if (NumNums > 22) {
    3101           16 :             Tank.UseEffectiveness = state.dataIPShortCut->rNumericArgs(23);
    3102              :         } else {
    3103            0 :             Tank.UseEffectiveness = 1.0; // Default for stand-alone mode
    3104              :         }
    3105              : 
    3106           16 :         if (NumNums > 23) {
    3107           16 :             Tank.UseInletHeight = state.dataIPShortCut->rNumericArgs(24);
    3108              :         } else {
    3109              :             // Defaults to bottom of tank
    3110            0 :             Tank.UseInletHeight = 0.0;
    3111              :         }
    3112           16 :         if ((!Tank.HeightWasAutoSized) && (Tank.UseInletHeight > Tank.Height)) {
    3113            0 :             ShowSevereError(state,
    3114            0 :                             format("{} = {}: Use inlet is located higher than overall tank height.",
    3115            0 :                                    state.dataIPShortCut->cCurrentModuleObject,
    3116            0 :                                    state.dataIPShortCut->cAlphaArgs(1)));
    3117            0 :             ShowContinueError(state, format("{} = {:.4R}", state.dataIPShortCut->cNumericFieldNames(2), state.dataIPShortCut->rNumericArgs(2)));
    3118            0 :             ShowContinueError(state, format("{} = {:.4R}", state.dataIPShortCut->cNumericFieldNames(24), state.dataIPShortCut->rNumericArgs(24)));
    3119            0 :             ErrorsFound = true;
    3120              :         }
    3121              : 
    3122           16 :         if ((NumNums > 24) && (state.dataIPShortCut->rNumericArgs(25) != Constant::AutoCalculate)) {
    3123            1 :             Tank.UseOutletHeight = state.dataIPShortCut->rNumericArgs(25);
    3124              :         } else {
    3125              :             // Defaults to top of tank
    3126           15 :             Tank.UseOutletHeight = Tank.Height;
    3127              :         }
    3128           16 :         if (Tank.UseOutletHeight == DataSizing::AutoSize) {
    3129            0 :             Tank.UseOutletHeightWasAutoSized = true;
    3130              :         }
    3131           16 :         if ((!Tank.HeightWasAutoSized) && (Tank.UseOutletHeight > Tank.Height)) {
    3132            0 :             ShowSevereError(state,
    3133            0 :                             format("{} = {}: Use outlet is located higher than overall tank height.",
    3134            0 :                                    state.dataIPShortCut->cCurrentModuleObject,
    3135            0 :                                    state.dataIPShortCut->cAlphaArgs(1)));
    3136            0 :             ShowContinueError(state, format("{} = {:.4R}", state.dataIPShortCut->cNumericFieldNames(2), state.dataIPShortCut->rNumericArgs(2)));
    3137            0 :             ShowContinueError(state, format("{} = {:.4R}", state.dataIPShortCut->cNumericFieldNames(25), state.dataIPShortCut->rNumericArgs(25)));
    3138            0 :             ErrorsFound = true;
    3139              :         }
    3140              : 
    3141           16 :         if (NumNums > 25) {
    3142           16 :             if ((state.dataIPShortCut->rNumericArgs(26) > 1) || (state.dataIPShortCut->rNumericArgs(26) <= 0)) {
    3143            0 :                 ShowSevereError(state,
    3144            0 :                                 format("{} = {}:  Source Side Effectiveness is out of bounds (>0 to 1)",
    3145            0 :                                        state.dataIPShortCut->cCurrentModuleObject,
    3146            0 :                                        state.dataIPShortCut->cAlphaArgs(1)));
    3147            0 :                 ErrorsFound = true;
    3148              :             }
    3149           16 :             Tank.SourceEffectiveness = state.dataIPShortCut->rNumericArgs(26);
    3150              :         } else {
    3151            0 :             Tank.SourceEffectiveness = 1.0;
    3152              :         }
    3153              : 
    3154           16 :         if ((NumNums > 26) && (state.dataIPShortCut->rNumericArgs(27) != Constant::AutoCalculate)) {
    3155           11 :             Tank.SourceInletHeight = state.dataIPShortCut->rNumericArgs(27);
    3156              :         } else {
    3157              :             // Defaults to top of tank
    3158            5 :             Tank.SourceInletHeight = Tank.Height;
    3159              :         }
    3160           16 :         if (Tank.SourceInletHeight == DataSizing::AutoSize) {
    3161            0 :             Tank.SourceInletHeightWasAutoSized = true;
    3162              :         }
    3163           16 :         if ((!Tank.HeightWasAutoSized) && (Tank.SourceInletHeight > Tank.Height)) {
    3164            0 :             ShowSevereError(state,
    3165            0 :                             format("{} = {}: Source inlet is located higher than overall tank height.",
    3166            0 :                                    state.dataIPShortCut->cCurrentModuleObject,
    3167            0 :                                    state.dataIPShortCut->cAlphaArgs(1)));
    3168            0 :             ShowContinueError(state, format("{} = {:.4R}", state.dataIPShortCut->cNumericFieldNames(2), state.dataIPShortCut->rNumericArgs(2)));
    3169            0 :             ShowContinueError(state, format("{} = {:.4R}", state.dataIPShortCut->cNumericFieldNames(27), state.dataIPShortCut->rNumericArgs(27)));
    3170            0 :             ErrorsFound = true;
    3171              :         }
    3172              : 
    3173           16 :         if ((NumNums > 27) && (state.dataIPShortCut->rNumericArgs(28) != Constant::AutoCalculate)) {
    3174           16 :             Tank.SourceOutletHeight = state.dataIPShortCut->rNumericArgs(28);
    3175              :         } else {
    3176              :             // Defaults to bottom of tank
    3177            0 :             Tank.SourceOutletHeight = 0.0;
    3178              :         }
    3179           16 :         if ((!Tank.HeightWasAutoSized) && (Tank.SourceOutletHeight > Tank.Height)) {
    3180            0 :             ShowSevereError(state,
    3181            0 :                             format("{} = {}: Source outlet is located higher than overall tank height.",
    3182            0 :                                    state.dataIPShortCut->cCurrentModuleObject,
    3183            0 :                                    state.dataIPShortCut->cAlphaArgs(1)));
    3184            0 :             ShowContinueError(state, format("{} = {:.4R}", state.dataIPShortCut->cNumericFieldNames(2), state.dataIPShortCut->rNumericArgs(2)));
    3185            0 :             ShowContinueError(state, format("{} = {:.4R}", state.dataIPShortCut->cNumericFieldNames(28), state.dataIPShortCut->rNumericArgs(28)));
    3186            0 :             ErrorsFound = true;
    3187              :         }
    3188              : 
    3189              :         // If no plant nodes are connected, simulate in stand-alone mode.
    3190           30 :         if (state.dataIPShortCut->cAlphaArgs(16).empty() && state.dataIPShortCut->cAlphaArgs(17).empty() &&
    3191           30 :             state.dataIPShortCut->cAlphaArgs(18).empty() && state.dataIPShortCut->cAlphaArgs(19).empty()) {
    3192            2 :             Tank.StandAlone = true;
    3193              :         }
    3194              : 
    3195           16 :         if (!state.dataIPShortCut->lNumericFieldBlanks(29)) {
    3196            9 :             Tank.UseDesignVolFlowRate = state.dataIPShortCut->rNumericArgs(29);
    3197            9 :             if (Tank.UseDesignVolFlowRate == DataSizing::AutoSize) {
    3198            9 :                 Tank.UseDesignVolFlowRateWasAutoSized = true;
    3199              :             }
    3200              :         } else {
    3201            7 :             Tank.UseDesignVolFlowRate = 0.0;
    3202              :         }
    3203              : 
    3204           16 :         Tank.UseSidePlantLoc.loopSideNum = DataPlant::LoopSideLocation::Invalid;
    3205              : 
    3206           16 :         if (!state.dataIPShortCut->lNumericFieldBlanks(30)) {
    3207            6 :             Tank.SourceDesignVolFlowRate = state.dataIPShortCut->rNumericArgs(30);
    3208            6 :             if (Tank.SourceDesignVolFlowRate == DataSizing::AutoSize) {
    3209            4 :                 Tank.SourceDesignVolFlowRateWasAutoSized = true;
    3210              :             }
    3211              :         } else {
    3212           10 :             Tank.SourceDesignVolFlowRate = 0.0;
    3213              :         }
    3214              : 
    3215           16 :         if (NumNums > 30) {
    3216           16 :             Tank.SizingRecoveryTime = state.dataIPShortCut->rNumericArgs(31);
    3217              :         } else {
    3218            0 :             Tank.SizingRecoveryTime = 1.5;
    3219              :         }
    3220              : 
    3221           16 :         Tank.SrcSidePlantLoc.loopSideNum = DataPlant::LoopSideLocation::Invalid;
    3222              : 
    3223           16 :         if ((!state.dataIPShortCut->cAlphaArgs(16).empty()) || (!state.dataIPShortCut->cAlphaArgs(17).empty())) {
    3224            9 :             Tank.UseInletNode = NodeInputManager::GetOnlySingleNode(state,
    3225            9 :                                                                     state.dataIPShortCut->cAlphaArgs(16),
    3226              :                                                                     ErrorsFound,
    3227              :                                                                     DataLoopNode::ConnectionObjectType::WaterHeaterStratified,
    3228            9 :                                                                     state.dataIPShortCut->cAlphaArgs(1),
    3229              :                                                                     DataLoopNode::NodeFluidType::Water,
    3230              :                                                                     DataLoopNode::ConnectionType::Inlet,
    3231              :                                                                     NodeInputManager::CompFluidStream::Primary,
    3232              :                                                                     DataLoopNode::ObjectIsNotParent);
    3233            9 :             Tank.InletNodeName1 = state.dataIPShortCut->cAlphaArgs(16);
    3234            9 :             Tank.UseOutletNode = NodeInputManager::GetOnlySingleNode(state,
    3235            9 :                                                                      state.dataIPShortCut->cAlphaArgs(17),
    3236              :                                                                      ErrorsFound,
    3237              :                                                                      DataLoopNode::ConnectionObjectType::WaterHeaterStratified,
    3238            9 :                                                                      state.dataIPShortCut->cAlphaArgs(1),
    3239              :                                                                      DataLoopNode::NodeFluidType::Water,
    3240              :                                                                      DataLoopNode::ConnectionType::Outlet,
    3241              :                                                                      NodeInputManager::CompFluidStream::Primary,
    3242              :                                                                      DataLoopNode::ObjectIsNotParent);
    3243            9 :             Tank.OutletNodeName1 = state.dataIPShortCut->cAlphaArgs(17);
    3244              : 
    3245            9 :             if (state.dataIPShortCut->rNumericArgs(22) > 0) {
    3246            0 :                 ShowWarningError(state,
    3247            0 :                                  format("{} = {}:  Use side nodes are specified; Peak Volumetric Use Flow Rate will not be used",
    3248            0 :                                         state.dataIPShortCut->cCurrentModuleObject,
    3249            0 :                                         state.dataIPShortCut->cAlphaArgs(1)));
    3250              :             }
    3251              : 
    3252            9 :             if (Tank.flowRateSched != nullptr) {
    3253            0 :                 ShowWarningError(state,
    3254            0 :                                  format("{} = {}:  Use side nodes are specified; Use Flow Rate Fraction Schedule will not be used",
    3255            0 :                                         state.dataIPShortCut->cCurrentModuleObject,
    3256            0 :                                         state.dataIPShortCut->cAlphaArgs(1)));
    3257              :             }
    3258              : 
    3259            9 :             if (Tank.useInletTempSched != nullptr) {
    3260            0 :                 ShowWarningError(state,
    3261            0 :                                  format("{} = {}:  Use side nodes are specified; Cold Water Supply Temperature Schedule will not be used",
    3262            0 :                                         state.dataIPShortCut->cCurrentModuleObject,
    3263            0 :                                         state.dataIPShortCut->cAlphaArgs(1)));
    3264              :             }
    3265              :         }
    3266              : 
    3267           16 :         if ((!state.dataIPShortCut->cAlphaArgs(18).empty()) || (!state.dataIPShortCut->cAlphaArgs(19).empty())) {
    3268           10 :             Tank.SourceInletNode = NodeInputManager::GetOnlySingleNode(state,
    3269           10 :                                                                        state.dataIPShortCut->cAlphaArgs(18),
    3270              :                                                                        ErrorsFound,
    3271              :                                                                        DataLoopNode::ConnectionObjectType::WaterHeaterStratified,
    3272           10 :                                                                        state.dataIPShortCut->cAlphaArgs(1),
    3273              :                                                                        DataLoopNode::NodeFluidType::Water,
    3274              :                                                                        DataLoopNode::ConnectionType::Inlet,
    3275              :                                                                        NodeInputManager::CompFluidStream::Secondary,
    3276              :                                                                        DataLoopNode::ObjectIsNotParent);
    3277           10 :             Tank.InletNodeName2 = state.dataIPShortCut->cAlphaArgs(18);
    3278           10 :             Tank.SourceOutletNode = NodeInputManager::GetOnlySingleNode(state,
    3279           10 :                                                                         state.dataIPShortCut->cAlphaArgs(19),
    3280              :                                                                         ErrorsFound,
    3281              :                                                                         DataLoopNode::ConnectionObjectType::WaterHeaterStratified,
    3282           10 :                                                                         state.dataIPShortCut->cAlphaArgs(1),
    3283              :                                                                         DataLoopNode::NodeFluidType::Water,
    3284              :                                                                         DataLoopNode::ConnectionType::Outlet,
    3285              :                                                                         NodeInputManager::CompFluidStream::Secondary,
    3286              :                                                                         DataLoopNode::ObjectIsNotParent);
    3287           10 :             Tank.OutletNodeName2 = state.dataIPShortCut->cAlphaArgs(19);
    3288              :         }
    3289              : 
    3290              :         // Validate inlet mode
    3291           16 :         Tank.InletMode =
    3292           16 :             static_cast<InletPositionMode>(getEnumValue(InletPositionModeNamesUC, Util::makeUPPER(state.dataIPShortCut->cAlphaArgs(20))));
    3293              : 
    3294           16 :         Tank.Nodes = state.dataIPShortCut->rNumericArgs(32);
    3295           16 :         int specifiedNodes = 0;
    3296           16 :         Tank.AdditionalCond = state.dataIPShortCut->rNumericArgs(33);
    3297              : 
    3298           16 :         Tank.AdditionalLossCoeff.allocate(Tank.Nodes);
    3299           16 :         Tank.AdditionalLossCoeff = 0.0;
    3300           44 :         for (int NodeNum = 1; NodeNum <= 12; ++NodeNum) {
    3301           44 :             int index = 33 + NodeNum;
    3302           44 :             if (NumNums >= index) {
    3303           28 :                 if (NodeNum <= Tank.Nodes) {
    3304           28 :                     ++specifiedNodes;
    3305           28 :                     Tank.AdditionalLossCoeff(NodeNum) = state.dataIPShortCut->rNumericArgs(index);
    3306            0 :                 } else if (!state.dataIPShortCut->lNumericFieldBlanks(index) && (state.dataIPShortCut->rNumericArgs(index) != 0)) {
    3307              :                     // If either blank, or zero (default), then do not warn
    3308            0 :                     ++specifiedNodes;
    3309              :                 }
    3310              :             } else {
    3311           16 :                 break;
    3312              :             }
    3313              :         }
    3314              : 
    3315           16 :         if (specifiedNodes > Tank.Nodes) {
    3316            0 :             ShowWarningError(
    3317              :                 state,
    3318            0 :                 format("{} = {}:  More Additional Loss Coefficients were entered than the number of nodes; extra coefficients will not be used",
    3319            0 :                        state.dataIPShortCut->cCurrentModuleObject,
    3320            0 :                        state.dataIPShortCut->cAlphaArgs(1)));
    3321              :         }
    3322              : 
    3323           16 :         Tank.SetupStratifiedNodes(state);
    3324              : 
    3325           16 :         if (!state.dataIPShortCut->lAlphaFieldBlanks(21)) {
    3326            0 :             Tank.SourceSideControlMode =
    3327            0 :                 static_cast<SourceSideControl>(getEnumValue(SourceSideControlNamesUC, Util::makeUPPER(state.dataIPShortCut->cAlphaArgs(21))));
    3328            0 :             if (Tank.SourceSideControlMode == SourceSideControl::Invalid) {
    3329            0 :                 ShowSevereError(state,
    3330            0 :                                 format("{} = {}:  Invalid Control Mode entered={}",
    3331            0 :                                        state.dataIPShortCut->cCurrentModuleObject,
    3332            0 :                                        state.dataIPShortCut->cAlphaArgs(1),
    3333            0 :                                        state.dataIPShortCut->cAlphaArgs(21)));
    3334            0 :                 ErrorsFound = true;
    3335              :             }
    3336              :         } else {
    3337           16 :             Tank.SourceSideControlMode = SourceSideControl::IndirectHeatPrimarySetpoint;
    3338              :         }
    3339              : 
    3340           16 :         if (state.dataIPShortCut->lAlphaFieldBlanks(22)) {
    3341            0 :         } else if ((Tank.sourceSideAltSetpointSched = Sched::GetSchedule(state, state.dataIPShortCut->cAlphaArgs(22))) == nullptr) {
    3342            0 :             ShowSevereItemNotFound(state, eoh, state.dataIPShortCut->cAlphaFieldNames(22), state.dataIPShortCut->cAlphaArgs(22));
    3343            0 :             ErrorsFound = true;
    3344              :         }
    3345              :     }
    3346              : 
    3347           10 :     return ErrorsFound;
    3348              : }
    3349              : 
    3350            4 : bool getWaterTankMixedInput(EnergyPlusData &state)
    3351              : {
    3352              :     static constexpr std::string_view routineName = "getWaterTankMixedInput";
    3353            4 :     bool ErrorsFound = false;
    3354              : 
    3355            4 :     state.dataIPShortCut->cCurrentModuleObject = cMixedCWTankModuleObj; // 'ThermalStorage:ChilledWater:Mixed'
    3356            8 :     for (int WaterThermalTankNum = state.dataWaterThermalTanks->numWaterHeaterMixed + state.dataWaterThermalTanks->numWaterHeaterStratified + 1;
    3357            8 :          WaterThermalTankNum <= state.dataWaterThermalTanks->numWaterHeaterMixed + state.dataWaterThermalTanks->numWaterHeaterStratified +
    3358            8 :                                     state.dataWaterThermalTanks->numChilledWaterMixed;
    3359              :          ++WaterThermalTankNum) {
    3360              :         int NumAlphas;
    3361              :         int NumNums;
    3362              :         int IOStat;
    3363            8 :         state.dataInputProcessing->inputProcessor->getObjectItem(
    3364              :             state,
    3365            4 :             state.dataIPShortCut->cCurrentModuleObject,
    3366            4 :             WaterThermalTankNum - (state.dataWaterThermalTanks->numWaterHeaterMixed + state.dataWaterThermalTanks->numWaterHeaterStratified),
    3367            4 :             state.dataIPShortCut->cAlphaArgs,
    3368              :             NumAlphas,
    3369            4 :             state.dataIPShortCut->rNumericArgs,
    3370              :             NumNums,
    3371              :             IOStat,
    3372            4 :             state.dataIPShortCut->lNumericFieldBlanks,
    3373            4 :             state.dataIPShortCut->lAlphaFieldBlanks,
    3374            4 :             state.dataIPShortCut->cAlphaFieldNames,
    3375            4 :             state.dataIPShortCut->cNumericFieldNames);
    3376              : 
    3377            4 :         ErrorObjectHeader eoh{routineName, state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)};
    3378              : 
    3379            4 :         GlobalNames::VerifyUniqueInterObjectName(state,
    3380            4 :                                                  state.dataWaterThermalTanks->UniqueWaterThermalTankNames,
    3381            4 :                                                  state.dataIPShortCut->cAlphaArgs(1),
    3382            4 :                                                  state.dataIPShortCut->cCurrentModuleObject,
    3383            4 :                                                  state.dataIPShortCut->cAlphaFieldNames(1),
    3384              :                                                  ErrorsFound);
    3385              : 
    3386            4 :         auto &Tank = state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum);
    3387              : 
    3388            4 :         Tank.Name = state.dataIPShortCut->cAlphaArgs(1);
    3389            4 :         Tank.Type = state.dataIPShortCut->cCurrentModuleObject;
    3390            4 :         Tank.WaterThermalTankType = DataPlant::PlantEquipmentType::ChilledWaterTankMixed;
    3391              : 
    3392            4 :         if ((Tank.water = Fluid::GetWater(state)) == nullptr) {
    3393            0 :             ShowSevereError(state, "Fluid Properties for WATER not found");
    3394            0 :             ErrorsFound = true;
    3395              :         }
    3396              : 
    3397            4 :         Tank.IsChilledWaterTank = true;
    3398            4 :         Tank.EndUseSubcategoryName = "Chilled Water Storage";
    3399              : 
    3400            4 :         Tank.Volume = state.dataIPShortCut->rNumericArgs(1);
    3401            4 :         if (Tank.Volume == DataSizing::AutoSize) {
    3402            0 :             Tank.VolumeWasAutoSized = true;
    3403              :         }
    3404              : 
    3405            4 :         if (state.dataIPShortCut->rNumericArgs(1) == 0.0) {
    3406              :             // Set volume to a really small number to continue simulation
    3407            0 :             Tank.Volume = 0.000001; // = 1 cm3
    3408              :         }
    3409              : 
    3410            4 :         if (state.dataIPShortCut->lAlphaFieldBlanks(2)) {
    3411            0 :             ShowSevereEmptyField(state, eoh, state.dataIPShortCut->cAlphaFieldNames(2));
    3412            4 :         } else if ((Tank.setptTempSched = Sched::GetSchedule(state, state.dataIPShortCut->cAlphaArgs(2))) == nullptr) {
    3413            0 :             ShowSevereItemNotFound(state, eoh, state.dataIPShortCut->cAlphaFieldNames(2), state.dataIPShortCut->cAlphaArgs(2));
    3414            0 :             ErrorsFound = true;
    3415              :         }
    3416              : 
    3417            4 :         if (state.dataIPShortCut->rNumericArgs(2) > 0.0001) {
    3418            4 :             Tank.DeadBandDeltaTemp = state.dataIPShortCut->rNumericArgs(2);
    3419              :         } else {
    3420              :             // Default to very small number (however it can't be TINY or it will break the algorithm)
    3421            0 :             Tank.DeadBandDeltaTemp = 0.5;
    3422              :         }
    3423              : 
    3424            4 :         if (state.dataIPShortCut->rNumericArgs(3) > 0.0) {
    3425            4 :             Tank.TankTempLimit = state.dataIPShortCut->rNumericArgs(3);
    3426              :         } else {
    3427              :             // default to just above freezing
    3428            0 :             Tank.TankTempLimit = 1.0;
    3429              :         }
    3430              : 
    3431            4 :         Tank.MaxCapacity = state.dataIPShortCut->rNumericArgs(4);
    3432            4 :         if (Tank.MaxCapacity == DataSizing::AutoSize) {
    3433            0 :             Tank.MaxCapacityWasAutoSized = true;
    3434              :         }
    3435              : 
    3436            4 :         Tank.MinCapacity = 0.0;
    3437            4 :         Tank.ControlType = HeaterControlMode::Cycle;
    3438              : 
    3439            4 :         Tank.MassFlowRateMin = 0.0;
    3440            4 :         Tank.IgnitionDelay = 0.0;
    3441            4 :         Tank.FuelType = Constant::eFuel::Electricity;
    3442            4 :         Tank.Efficiency = 1.0;
    3443            4 :         Tank.PLFCurve = 0;
    3444            4 :         Tank.OffCycParaLoad = 0.0;
    3445            4 :         Tank.OffCycParaFuelType = Constant::eFuel::Electricity;
    3446            4 :         Tank.OffCycParaFracToTank = 0.0;
    3447            4 :         Tank.OnCycParaLoad = 0.0;
    3448            4 :         Tank.OnCycParaFuelType = Constant::eFuel::Electricity;
    3449            4 :         Tank.OnCycParaFracToTank = 0.0;
    3450              : 
    3451            4 :         Tank.AmbientTempIndicator =
    3452            4 :             static_cast<WTTAmbientTemp>(getEnumValue(TankAmbientTempNamesUC, Util::makeUPPER(state.dataIPShortCut->cAlphaArgs(3))));
    3453            4 :         switch (Tank.AmbientTempIndicator) {
    3454              : 
    3455            0 :         case WTTAmbientTemp::Schedule: {
    3456            0 :             if (state.dataIPShortCut->lAlphaFieldBlanks(4)) {
    3457            0 :                 ShowSevereEmptyField(state, eoh, state.dataIPShortCut->cAlphaFieldNames(4));
    3458            0 :             } else if ((Tank.ambientTempSched = Sched::GetSchedule(state, state.dataIPShortCut->cAlphaArgs(4))) == nullptr) {
    3459            0 :                 ShowSevereItemNotFound(state, eoh, state.dataIPShortCut->cAlphaFieldNames(4), state.dataIPShortCut->cAlphaArgs(4));
    3460            0 :                 ErrorsFound = true;
    3461              :             }
    3462            0 :         } break;
    3463              : 
    3464            3 :         case WTTAmbientTemp::TempZone: {
    3465            3 :             Tank.AmbientTempZone = Util::FindItemInList(state.dataIPShortCut->cAlphaArgs(5), state.dataHeatBal->Zone);
    3466            3 :             if (Tank.AmbientTempZone == 0) {
    3467            0 :                 ShowSevereError(state, format("Invalid, {} = {}", state.dataIPShortCut->cAlphaFieldNames(5), state.dataIPShortCut->cAlphaArgs(5)));
    3468            0 :                 ShowContinueError(state,
    3469            0 :                                   format("Entered in {} = {}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
    3470            0 :                 ShowContinueError(state, "Zone was not found.");
    3471            0 :                 ErrorsFound = true;
    3472              :             }
    3473              : 
    3474            3 :             break;
    3475              :         }
    3476            1 :         case WTTAmbientTemp::OutsideAir: {
    3477            1 :             Tank.AmbientTempOutsideAirNode = NodeInputManager::GetOnlySingleNode(state,
    3478            1 :                                                                                  state.dataIPShortCut->cAlphaArgs(6),
    3479              :                                                                                  ErrorsFound,
    3480              :                                                                                  DataLoopNode::ConnectionObjectType::ThermalStorageChilledWaterMixed,
    3481            1 :                                                                                  state.dataIPShortCut->cAlphaArgs(1),
    3482              :                                                                                  DataLoopNode::NodeFluidType::Air,
    3483              :                                                                                  DataLoopNode::ConnectionType::OutsideAirReference,
    3484              :                                                                                  NodeInputManager::CompFluidStream::Primary,
    3485              :                                                                                  DataLoopNode::ObjectIsNotParent);
    3486            1 :             if (!state.dataIPShortCut->lAlphaFieldBlanks(6)) {
    3487            1 :                 if (!OutAirNodeManager::CheckOutAirNodeNumber(state, Tank.AmbientTempOutsideAirNode)) {
    3488            0 :                     ShowSevereError(state,
    3489            0 :                                     format("Invalid, {} = {}", state.dataIPShortCut->cAlphaFieldNames(6), state.dataIPShortCut->cAlphaArgs(6)));
    3490            0 :                     ShowContinueError(state,
    3491            0 :                                       format("Entered in {} = {}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
    3492            0 :                     ShowContinueError(state, "Outdoor Air Node not on OutdoorAir:NodeList or OutdoorAir:Node");
    3493            0 :                     ErrorsFound = true;
    3494              :                 }
    3495              :             } else {
    3496            0 :                 ShowSevereError(state, format("{} = {}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
    3497            0 :                 ShowContinueError(state, "An Ambient Outdoor Air Node name must be used when the Ambient Temperature Indicator is Outdoors.");
    3498            0 :                 ErrorsFound = true;
    3499              :             }
    3500              : 
    3501            1 :             break;
    3502              :         }
    3503            0 :         default: {
    3504            0 :             ShowSevereError(state,
    3505            0 :                             format("{} = {}:  Invalid Ambient Temperature Indicator entered={}",
    3506            0 :                                    state.dataIPShortCut->cCurrentModuleObject,
    3507            0 :                                    state.dataIPShortCut->cAlphaArgs(1),
    3508            0 :                                    state.dataIPShortCut->cAlphaArgs(3)));
    3509            0 :             ShowContinueError(state, " Valid entries are Schedule, Zone, and Outdoors.");
    3510            0 :             ErrorsFound = true;
    3511            0 :             break;
    3512              :         }
    3513              :         }
    3514              : 
    3515            4 :         Tank.OffCycLossCoeff = state.dataIPShortCut->rNumericArgs(5);
    3516            4 :         Tank.OffCycLossFracToZone = 1.0;
    3517              : 
    3518            4 :         Tank.OnCycLossCoeff = state.dataIPShortCut->rNumericArgs(5);
    3519            4 :         Tank.OnCycLossFracToZone = 1.0;
    3520              : 
    3521            4 :         Tank.MassFlowRateMax = 0.0;
    3522            4 :         Tank.flowRateSched = nullptr;
    3523            4 :         Tank.useInletTempSched = nullptr;
    3524              : 
    3525              :         // default to always on
    3526            4 :         Tank.sourceSideAvailSched = Sched::GetScheduleAlwaysOn(state);
    3527            4 :         Tank.useSideAvailSched = Sched::GetScheduleAlwaysOn(state);
    3528              : 
    3529            4 :         if ((state.dataIPShortCut->rNumericArgs(6) > 1) || (state.dataIPShortCut->rNumericArgs(6) < 0)) {
    3530            0 :             ShowSevereError(state,
    3531            0 :                             format("{} = {}:  Use Side Effectiveness is out of bounds (0 to 1)",
    3532            0 :                                    state.dataIPShortCut->cCurrentModuleObject,
    3533            0 :                                    state.dataIPShortCut->cAlphaArgs(1)));
    3534            0 :             ErrorsFound = true;
    3535              :         }
    3536            4 :         Tank.UseEffectiveness = state.dataIPShortCut->rNumericArgs(6);
    3537              : 
    3538            4 :         if ((state.dataIPShortCut->rNumericArgs(8) > 1) || (state.dataIPShortCut->rNumericArgs(8) <= 0)) {
    3539            0 :             ShowSevereError(state,
    3540            0 :                             format("{} = {}:  Source Side Effectiveness is out of bounds (>0 to 1)",
    3541            0 :                                    state.dataIPShortCut->cCurrentModuleObject,
    3542            0 :                                    state.dataIPShortCut->cAlphaArgs(1)));
    3543            0 :             ErrorsFound = true;
    3544              :         }
    3545            4 :         Tank.SourceEffectiveness = state.dataIPShortCut->rNumericArgs(8);
    3546              : 
    3547            4 :         if (state.dataIPShortCut->lNumericFieldBlanks(7)) {
    3548            0 :             Tank.UseDesignVolFlowRate = 0.0;
    3549              :         } else {
    3550            4 :             Tank.UseDesignVolFlowRate = state.dataIPShortCut->rNumericArgs(7);
    3551            4 :             if (Tank.UseDesignVolFlowRate) {
    3552            4 :                 Tank.UseDesignVolFlowRateWasAutoSized = true;
    3553              :             }
    3554              :         }
    3555              : 
    3556            4 :         Tank.UseSidePlantLoc.loopSideNum = DataPlant::LoopSideLocation::Invalid;
    3557              : 
    3558            4 :         if (state.dataIPShortCut->lAlphaFieldBlanks(9)) {
    3559            0 :             Tank.useSideAvailSched = Sched::GetScheduleAlwaysOn(state);
    3560            4 :         } else if ((Tank.useSideAvailSched = Sched::GetSchedule(state, state.dataIPShortCut->cAlphaArgs(9))) == nullptr) {
    3561            0 :             ShowSevereItemNotFound(state, eoh, state.dataIPShortCut->cAlphaFieldNames(9), state.dataIPShortCut->cAlphaArgs(9));
    3562            0 :             ErrorsFound = true;
    3563              :         }
    3564              : 
    3565            4 :         Tank.SrcSidePlantLoc.loopSideNum = DataPlant::LoopSideLocation::Invalid;
    3566              : 
    3567            4 :         if (state.dataIPShortCut->lNumericFieldBlanks(9)) {
    3568            1 :             Tank.SourceDesignVolFlowRate = 0.0;
    3569              :         } else {
    3570            3 :             Tank.SourceDesignVolFlowRate = state.dataIPShortCut->rNumericArgs(9);
    3571            3 :             if (Tank.SourceDesignVolFlowRate == DataSizing::AutoSize) {
    3572            3 :                 Tank.SourceDesignVolFlowRateWasAutoSized = true;
    3573              :             }
    3574              :         }
    3575              : 
    3576            4 :         if (state.dataIPShortCut->lAlphaFieldBlanks(12)) {
    3577            1 :             Tank.sourceSideAvailSched = Sched::GetScheduleAlwaysOn(state);
    3578            3 :         } else if ((Tank.sourceSideAvailSched = Sched::GetSchedule(state, state.dataIPShortCut->cAlphaArgs(12))) == nullptr) {
    3579            0 :             ShowSevereItemNotFound(state, eoh, state.dataIPShortCut->cAlphaFieldNames(12), state.dataIPShortCut->cAlphaArgs(12));
    3580            0 :             ErrorsFound = true;
    3581              :         }
    3582              : 
    3583            4 :         if (state.dataIPShortCut->lNumericFieldBlanks(10)) {
    3584            1 :             Tank.SizingRecoveryTime = 4.0;
    3585              :         } else {
    3586            3 :             Tank.SizingRecoveryTime = state.dataIPShortCut->rNumericArgs(10);
    3587              :         }
    3588              : 
    3589            4 :         if ((!state.dataIPShortCut->lAlphaFieldBlanks(7)) || (!state.dataIPShortCut->lAlphaFieldBlanks(8))) {
    3590            4 :             Tank.UseInletNode = NodeInputManager::GetOnlySingleNode(state,
    3591            4 :                                                                     state.dataIPShortCut->cAlphaArgs(7),
    3592              :                                                                     ErrorsFound,
    3593              :                                                                     DataLoopNode::ConnectionObjectType::ThermalStorageChilledWaterMixed,
    3594            4 :                                                                     state.dataIPShortCut->cAlphaArgs(1),
    3595              :                                                                     DataLoopNode::NodeFluidType::Water,
    3596              :                                                                     DataLoopNode::ConnectionType::Inlet,
    3597              :                                                                     NodeInputManager::CompFluidStream::Primary,
    3598              :                                                                     DataLoopNode::ObjectIsNotParent);
    3599            4 :             Tank.InletNodeName1 = state.dataIPShortCut->cAlphaArgs(7);
    3600            4 :             Tank.UseOutletNode = NodeInputManager::GetOnlySingleNode(state,
    3601            4 :                                                                      state.dataIPShortCut->cAlphaArgs(8),
    3602              :                                                                      ErrorsFound,
    3603              :                                                                      DataLoopNode::ConnectionObjectType::ThermalStorageChilledWaterMixed,
    3604            4 :                                                                      state.dataIPShortCut->cAlphaArgs(1),
    3605              :                                                                      DataLoopNode::NodeFluidType::Water,
    3606              :                                                                      DataLoopNode::ConnectionType::Outlet,
    3607              :                                                                      NodeInputManager::CompFluidStream::Primary,
    3608              :                                                                      DataLoopNode::ObjectIsNotParent);
    3609            4 :             Tank.OutletNodeName1 = state.dataIPShortCut->cAlphaArgs(8);
    3610              :         }
    3611              : 
    3612            4 :         if ((!state.dataIPShortCut->lAlphaFieldBlanks(10)) || (!state.dataIPShortCut->lAlphaFieldBlanks(11))) {
    3613            3 :             Tank.SourceInletNode = NodeInputManager::GetOnlySingleNode(state,
    3614            3 :                                                                        state.dataIPShortCut->cAlphaArgs(10),
    3615              :                                                                        ErrorsFound,
    3616              :                                                                        DataLoopNode::ConnectionObjectType::ThermalStorageChilledWaterMixed,
    3617            3 :                                                                        state.dataIPShortCut->cAlphaArgs(1),
    3618              :                                                                        DataLoopNode::NodeFluidType::Water,
    3619              :                                                                        DataLoopNode::ConnectionType::Inlet,
    3620              :                                                                        NodeInputManager::CompFluidStream::Secondary,
    3621              :                                                                        DataLoopNode::ObjectIsNotParent);
    3622            3 :             Tank.InletNodeName2 = state.dataIPShortCut->cAlphaArgs(10);
    3623            3 :             Tank.SourceOutletNode = NodeInputManager::GetOnlySingleNode(state,
    3624            3 :                                                                         state.dataIPShortCut->cAlphaArgs(11),
    3625              :                                                                         ErrorsFound,
    3626              :                                                                         DataLoopNode::ConnectionObjectType::ThermalStorageChilledWaterMixed,
    3627            3 :                                                                         state.dataIPShortCut->cAlphaArgs(1),
    3628              :                                                                         DataLoopNode::NodeFluidType::Water,
    3629              :                                                                         DataLoopNode::ConnectionType::Outlet,
    3630              :                                                                         NodeInputManager::CompFluidStream::Secondary,
    3631              :                                                                         DataLoopNode::ObjectIsNotParent);
    3632            3 :             Tank.OutletNodeName2 = state.dataIPShortCut->cAlphaArgs(11);
    3633              :         }
    3634              : 
    3635            4 :         if (Tank.UseSidePlantLoc.loopSideNum == DataPlant::LoopSideLocation::Demand && Tank.SourceInletNode != 0) {
    3636            0 :             PlantUtilities::RegisterPlantCompDesignFlow(state, Tank.SourceInletNode, Tank.SourceDesignVolFlowRate);
    3637              :         }
    3638              : 
    3639              :     } // WaterThermalTankNum
    3640              : 
    3641            4 :     return ErrorsFound;
    3642              : }
    3643              : 
    3644            2 : bool getWaterTankStratifiedInput(EnergyPlusData &state)
    3645              : {
    3646            2 :     bool ErrorsFound = false;
    3647              :     static constexpr std::string_view routineName = "getWaterTankStratifiedInput";
    3648              : 
    3649            2 :     state.dataIPShortCut->cCurrentModuleObject = cStratifiedCWTankModuleObj; // 'ThermalStorage:ChilledWater:Stratified'
    3650              : 
    3651            4 :     for (int WaterThermalTankNum = state.dataWaterThermalTanks->numWaterHeaterMixed + state.dataWaterThermalTanks->numWaterHeaterStratified +
    3652            2 :                                    state.dataWaterThermalTanks->numChilledWaterMixed + 1;
    3653            4 :          WaterThermalTankNum <= state.dataWaterThermalTanks->numWaterHeaterMixed + state.dataWaterThermalTanks->numWaterHeaterStratified +
    3654            4 :                                     state.dataWaterThermalTanks->numChilledWaterMixed + state.dataWaterThermalTanks->numChilledWaterStratified;
    3655              :          ++WaterThermalTankNum) {
    3656              :         int NumNums;
    3657              :         int NumAlphas;
    3658              :         int IOStat;
    3659            4 :         state.dataInputProcessing->inputProcessor->getObjectItem(state,
    3660            2 :                                                                  state.dataIPShortCut->cCurrentModuleObject,
    3661            2 :                                                                  WaterThermalTankNum - (state.dataWaterThermalTanks->numWaterHeaterMixed +
    3662            2 :                                                                                         state.dataWaterThermalTanks->numWaterHeaterStratified +
    3663            2 :                                                                                         state.dataWaterThermalTanks->numChilledWaterMixed),
    3664            2 :                                                                  state.dataIPShortCut->cAlphaArgs,
    3665              :                                                                  NumAlphas,
    3666            2 :                                                                  state.dataIPShortCut->rNumericArgs,
    3667              :                                                                  NumNums,
    3668              :                                                                  IOStat,
    3669            2 :                                                                  state.dataIPShortCut->lNumericFieldBlanks,
    3670            2 :                                                                  state.dataIPShortCut->lAlphaFieldBlanks,
    3671            2 :                                                                  state.dataIPShortCut->cAlphaFieldNames,
    3672            2 :                                                                  state.dataIPShortCut->cNumericFieldNames);
    3673              : 
    3674            2 :         ErrorObjectHeader eoh{routineName, state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)};
    3675              : 
    3676            2 :         GlobalNames::VerifyUniqueInterObjectName(state,
    3677            2 :                                                  state.dataWaterThermalTanks->UniqueWaterThermalTankNames,
    3678            2 :                                                  state.dataIPShortCut->cAlphaArgs(1),
    3679            2 :                                                  state.dataIPShortCut->cCurrentModuleObject,
    3680            2 :                                                  state.dataIPShortCut->cAlphaFieldNames(1),
    3681              :                                                  ErrorsFound);
    3682              : 
    3683            2 :         auto &Tank = state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum);
    3684              : 
    3685            2 :         Tank.Name = state.dataIPShortCut->cAlphaArgs(1);
    3686            2 :         Tank.Type = state.dataIPShortCut->cCurrentModuleObject;
    3687            2 :         Tank.WaterThermalTankType = DataPlant::PlantEquipmentType::ChilledWaterTankStratified;
    3688              : 
    3689            2 :         if ((Tank.water = Fluid::GetWater(state)) == nullptr) {
    3690            0 :             ShowSevereError(state, "Fluid properties for WATER not found");
    3691            0 :             ErrorsFound = true;
    3692              :         }
    3693              : 
    3694            2 :         Tank.IsChilledWaterTank = true;
    3695            2 :         Tank.EndUseSubcategoryName = "Chilled Water Storage";
    3696              : 
    3697            2 :         Tank.Volume = state.dataIPShortCut->rNumericArgs(1);
    3698            2 :         if (Tank.Volume == DataSizing::AutoSize) {
    3699            0 :             Tank.VolumeWasAutoSized = true;
    3700              :         }
    3701              : 
    3702            2 :         Real64 rho = Tank.water->getDensity(state, Constant::InitConvTemp, routineName);
    3703              : 
    3704            2 :         Tank.Mass = Tank.Volume * rho;
    3705            2 :         Tank.Height = state.dataIPShortCut->rNumericArgs(2);
    3706            2 :         if (Tank.Height == DataSizing::AutoSize) {
    3707            0 :             Tank.HeightWasAutoSized = true;
    3708              :         }
    3709              : 
    3710            2 :         Tank.Shape = static_cast<TankShape>(getEnumValue(TankShapeNamesUC, Util::makeUPPER(state.dataIPShortCut->cAlphaArgs(2))));
    3711            2 :         switch (Tank.Shape) {
    3712            2 :         case TankShape::HorizCylinder:
    3713              :         case TankShape::VertCylinder: {
    3714            2 :             break;
    3715              :         }
    3716            0 :         case TankShape::Other: {
    3717            0 :             if (state.dataIPShortCut->rNumericArgs(3) > 0.0) {
    3718            0 :                 Tank.Perimeter = state.dataIPShortCut->rNumericArgs(3);
    3719              :             } else {
    3720            0 :                 ShowSevereError(state,
    3721            0 :                                 format("{} = {}:  Tank Perimeter must be greater than zero for Tank Shape=OTHER",
    3722            0 :                                        state.dataIPShortCut->cCurrentModuleObject,
    3723            0 :                                        state.dataIPShortCut->cAlphaArgs(1)));
    3724            0 :                 ErrorsFound = true;
    3725              :             }
    3726            0 :             break;
    3727              :         }
    3728            0 :         default: {
    3729            0 :             ShowSevereError(state,
    3730            0 :                             format("{} = {}:  Invalid Tank Shape entered={}",
    3731            0 :                                    state.dataIPShortCut->cCurrentModuleObject,
    3732            0 :                                    state.dataIPShortCut->cAlphaArgs(1),
    3733            0 :                                    state.dataIPShortCut->cAlphaArgs(2)));
    3734            0 :             Tank.Shape = TankShape::VertCylinder;
    3735            0 :             ErrorsFound = true;
    3736            0 :             break;
    3737              :         }
    3738              :         }
    3739              : 
    3740            2 :         if (state.dataIPShortCut->rNumericArgs(6) > 0.0) {
    3741            2 :             Tank.TankTempLimit = state.dataIPShortCut->rNumericArgs(6);
    3742              :         } else {
    3743              :             // default to just above freezing
    3744            0 :             Tank.TankTempLimit = 1.0;
    3745              :         }
    3746              : 
    3747            2 :         if (state.dataIPShortCut->lAlphaFieldBlanks(3)) {
    3748            0 :             ShowSevereEmptyField(state, eoh, state.dataIPShortCut->cAlphaFieldNames(3));
    3749            0 :             ErrorsFound = true;
    3750            2 :         } else if ((Tank.setptTempSched = Sched::GetSchedule(state, state.dataIPShortCut->cAlphaArgs(3))) == nullptr) {
    3751            0 :             ShowSevereItemNotFound(state, eoh, state.dataIPShortCut->cAlphaFieldNames(3), state.dataIPShortCut->cAlphaArgs(3));
    3752            0 :             ErrorsFound = true;
    3753              :         }
    3754              : 
    3755            2 :         if (state.dataIPShortCut->rNumericArgs(4) > 0.0) {
    3756            2 :             Tank.DeadBandDeltaTemp = state.dataIPShortCut->rNumericArgs(4);
    3757              :         } else {
    3758              :             // Default to very small number (however it can't be TINY or it will break the algorithm)
    3759            0 :             Tank.DeadBandDeltaTemp = 0.0001;
    3760              :         }
    3761              : 
    3762            2 :         Tank.HeaterHeight1 = state.dataIPShortCut->rNumericArgs(5);
    3763            2 :         Tank.MaxCapacity = state.dataIPShortCut->rNumericArgs(7);
    3764            2 :         if (Tank.MaxCapacity == DataSizing::AutoSize) {
    3765            0 :             Tank.MaxCapacityWasAutoSized = true;
    3766              :         }
    3767              : 
    3768            2 :         Tank.Efficiency = 1.0;
    3769            2 :         Tank.setptTemp2Sched = nullptr;
    3770            2 :         Tank.MaxCapacity2 = 0.0;
    3771            2 :         Tank.HeaterHeight2 = 0.0;
    3772            2 :         Tank.FuelType = Constant::eFuel::Electricity;
    3773              : 
    3774            2 :         Tank.OffCycParaLoad = 0.0;
    3775            2 :         Tank.OffCycParaFuelType = Constant::eFuel::Electricity;
    3776            2 :         Tank.OffCycParaFracToTank = 0.0;
    3777            2 :         Tank.OffCycParaHeight = 0.0;
    3778            2 :         Tank.OnCycParaLoad = 0.0;
    3779            2 :         Tank.OnCycParaFuelType = Constant::eFuel::Electricity;
    3780            2 :         Tank.OnCycParaFracToTank = 0.0;
    3781            2 :         Tank.OnCycParaHeight = 0.0;
    3782              : 
    3783            2 :         Tank.AmbientTempIndicator =
    3784            2 :             static_cast<WTTAmbientTemp>(getEnumValue(TankAmbientTempNamesUC, Util::makeUPPER(state.dataIPShortCut->cAlphaArgs(4))));
    3785            2 :         switch (Tank.AmbientTempIndicator) {
    3786              : 
    3787            0 :         case WTTAmbientTemp::Schedule: {
    3788            0 :             if (state.dataIPShortCut->lAlphaFieldBlanks(5)) {
    3789            0 :                 ShowSevereEmptyField(state, eoh, state.dataIPShortCut->cAlphaFieldNames(5));
    3790            0 :                 ErrorsFound = true;
    3791            0 :             } else if ((Tank.ambientTempSched = Sched::GetSchedule(state, state.dataIPShortCut->cAlphaArgs(5))) == nullptr) {
    3792            0 :                 ShowSevereItemNotFound(state, eoh, state.dataIPShortCut->cAlphaFieldNames(5), state.dataIPShortCut->cAlphaArgs(5));
    3793            0 :                 ErrorsFound = true;
    3794              :             }
    3795            0 :         } break;
    3796              : 
    3797            2 :         case WTTAmbientTemp::TempZone: {
    3798            2 :             Tank.AmbientTempZone = Util::FindItemInList(state.dataIPShortCut->cAlphaArgs(6), state.dataHeatBal->Zone);
    3799            2 :             if (Tank.AmbientTempZone == 0) {
    3800            0 :                 ShowSevereError(state, format("Invalid, {} = {}", state.dataIPShortCut->cAlphaFieldNames(6), state.dataIPShortCut->cAlphaArgs(6)));
    3801            0 :                 ShowContinueError(state,
    3802            0 :                                   format("Entered in {} = {}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
    3803            0 :                 ShowContinueError(state, "Zone was not found.");
    3804            0 :                 ErrorsFound = true;
    3805              :             }
    3806            2 :             Tank.OffCycLossFracToZone = 1.0;
    3807              : 
    3808            2 :             break;
    3809              :         }
    3810            0 :         case WTTAmbientTemp::OutsideAir: {
    3811            0 :             Tank.AmbientTempOutsideAirNode =
    3812            0 :                 NodeInputManager::GetOnlySingleNode(state,
    3813            0 :                                                     state.dataIPShortCut->cAlphaArgs(7),
    3814              :                                                     ErrorsFound,
    3815              :                                                     DataLoopNode::ConnectionObjectType::ThermalStorageChilledWaterStratified,
    3816            0 :                                                     state.dataIPShortCut->cAlphaArgs(1),
    3817              :                                                     DataLoopNode::NodeFluidType::Air,
    3818              :                                                     DataLoopNode::ConnectionType::Inlet,
    3819              :                                                     NodeInputManager::CompFluidStream::Primary,
    3820              :                                                     DataLoopNode::ObjectIsNotParent);
    3821            0 :             if (!state.dataIPShortCut->lAlphaFieldBlanks(7)) {
    3822            0 :                 if (!OutAirNodeManager::CheckOutAirNodeNumber(state, Tank.AmbientTempOutsideAirNode)) {
    3823            0 :                     ShowSevereError(state,
    3824            0 :                                     format("Invalid, {} = {}", state.dataIPShortCut->cAlphaFieldNames(7), state.dataIPShortCut->cAlphaArgs(7)));
    3825            0 :                     ShowContinueError(state,
    3826            0 :                                       format("Entered in {} = {}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
    3827            0 :                     ShowContinueError(state, "Outdoor Air Node not on OutdoorAir:NodeList or OutdoorAir:Node");
    3828            0 :                     ErrorsFound = true;
    3829              :                 }
    3830              :             } else {
    3831            0 :                 ShowSevereError(state, format("{} = {}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
    3832            0 :                 ShowContinueError(state, "An Ambient Outdoor Air Node name must be used when the Ambient Temperature Indicator is Outdoors.");
    3833            0 :                 ErrorsFound = true;
    3834              :             }
    3835              : 
    3836            0 :             break;
    3837              :         }
    3838            0 :         default: {
    3839            0 :             ShowSevereError(state,
    3840            0 :                             format("{} = {}:  Invalid Ambient Temperature Indicator entered={}",
    3841            0 :                                    state.dataIPShortCut->cCurrentModuleObject,
    3842            0 :                                    state.dataIPShortCut->cAlphaArgs(1),
    3843            0 :                                    state.dataIPShortCut->cAlphaArgs(4)));
    3844            0 :             ShowContinueError(state, "  Valid entries are Schedule, Zone, and Outdoors.");
    3845            0 :             ErrorsFound = true;
    3846            0 :             break;
    3847              :         }
    3848              :         }
    3849              : 
    3850            2 :         Tank.SkinLossCoeff = state.dataIPShortCut->rNumericArgs(8);
    3851            2 :         Tank.SkinLossFracToZone = 1.0;
    3852            2 :         Tank.OffCycFlueLossCoeff = 0.0;
    3853            2 :         Tank.OffCycFlueLossFracToZone = 0.0;
    3854              : 
    3855            2 :         Tank.MassFlowRateMax = 0.0;
    3856            2 :         Tank.flowRateSched = nullptr;
    3857            2 :         Tank.useInletTempSched = nullptr;
    3858            2 :         Tank.UseEffectiveness = state.dataIPShortCut->rNumericArgs(9);
    3859            2 :         Tank.UseInletHeight = state.dataIPShortCut->rNumericArgs(10);
    3860              : 
    3861              :         // default to always on
    3862            2 :         Tank.sourceSideAvailSched = Sched::GetScheduleAlwaysOn(state);
    3863            2 :         Tank.useSideAvailSched = Sched::GetScheduleAlwaysOn(state);
    3864              : 
    3865            2 :         if (state.dataIPShortCut->rNumericArgs(10) == Constant::AutoCalculate) {
    3866            0 :             Tank.UseInletHeight = Tank.Height; // top of tank
    3867              :         }
    3868            2 :         if (Tank.UseInletHeight > Tank.Height) {
    3869            0 :             ShowSevereError(state,
    3870            0 :                             format("{} = {}: Use inlet is located higher than overall tank height.",
    3871            0 :                                    state.dataIPShortCut->cCurrentModuleObject,
    3872            0 :                                    state.dataIPShortCut->cAlphaArgs(1)));
    3873            0 :             ShowContinueError(state, format("{} = {:.4R}", state.dataIPShortCut->cNumericFieldNames(2), state.dataIPShortCut->rNumericArgs(2)));
    3874            0 :             ShowContinueError(state, format("{} = {:.4R}", state.dataIPShortCut->cNumericFieldNames(10), state.dataIPShortCut->rNumericArgs(10)));
    3875            0 :             ErrorsFound = true;
    3876              :         }
    3877              : 
    3878            2 :         Tank.UseOutletHeight = state.dataIPShortCut->rNumericArgs(11);
    3879            2 :         if (Tank.UseOutletHeight > Tank.Height) {
    3880            0 :             ShowSevereError(state,
    3881            0 :                             format("{} = {}: Use outlet is located higher than overall tank height.",
    3882            0 :                                    state.dataIPShortCut->cCurrentModuleObject,
    3883            0 :                                    state.dataIPShortCut->cAlphaArgs(1)));
    3884            0 :             ShowContinueError(state, format("{} = {:.4R}", state.dataIPShortCut->cNumericFieldNames(2), state.dataIPShortCut->rNumericArgs(2)));
    3885            0 :             ShowContinueError(state, format("{} = {:.4R}", state.dataIPShortCut->cNumericFieldNames(11), state.dataIPShortCut->rNumericArgs(11)));
    3886            0 :             ErrorsFound = true;
    3887              :         }
    3888              : 
    3889            2 :         if ((state.dataIPShortCut->rNumericArgs(13) > 1) || (state.dataIPShortCut->rNumericArgs(13) <= 0)) {
    3890            0 :             ShowSevereError(state,
    3891            0 :                             format("{} = {}:  Source Side Effectiveness is out of bounds (>0 to 1)",
    3892            0 :                                    state.dataIPShortCut->cCurrentModuleObject,
    3893            0 :                                    state.dataIPShortCut->cAlphaArgs(1)));
    3894            0 :             ErrorsFound = true;
    3895              :         }
    3896            2 :         Tank.SourceEffectiveness = state.dataIPShortCut->rNumericArgs(13);
    3897              : 
    3898            2 :         Tank.SourceInletHeight = state.dataIPShortCut->rNumericArgs(14);
    3899            2 :         if (Tank.SourceInletHeight > Tank.Height) {
    3900            0 :             ShowSevereError(state,
    3901            0 :                             format("{} = {}: Source inlet is located higher than overall tank height.",
    3902            0 :                                    state.dataIPShortCut->cCurrentModuleObject,
    3903            0 :                                    state.dataIPShortCut->cAlphaArgs(1)));
    3904            0 :             ShowContinueError(state, format("{} = {:.4R}", state.dataIPShortCut->cNumericFieldNames(2), state.dataIPShortCut->rNumericArgs(2)));
    3905            0 :             ShowContinueError(state, format("{} = {:.4R}", state.dataIPShortCut->cNumericFieldNames(14), state.dataIPShortCut->rNumericArgs(14)));
    3906            0 :             ErrorsFound = true;
    3907              :         }
    3908              : 
    3909            2 :         Tank.SourceOutletHeight = state.dataIPShortCut->rNumericArgs(15);
    3910            2 :         if (state.dataIPShortCut->rNumericArgs(15) == Constant::AutoCalculate) {
    3911            0 :             Tank.SourceOutletHeight = Tank.Height; // top of tank
    3912              :         }
    3913            2 :         if (Tank.SourceOutletHeight > Tank.Height) {
    3914            0 :             ShowSevereError(state,
    3915            0 :                             format("{} = {}: Source outlet is located higher than overall tank height.",
    3916            0 :                                    state.dataIPShortCut->cCurrentModuleObject,
    3917            0 :                                    state.dataIPShortCut->cAlphaArgs(1)));
    3918            0 :             ShowContinueError(state, format("{} = {:.4R}", state.dataIPShortCut->cNumericFieldNames(2), state.dataIPShortCut->rNumericArgs(2)));
    3919            0 :             ShowContinueError(state, format("{} = {:.4R}", state.dataIPShortCut->cNumericFieldNames(15), state.dataIPShortCut->rNumericArgs(15)));
    3920            0 :             ErrorsFound = true;
    3921              :         }
    3922              : 
    3923            2 :         Tank.StandAlone = false;
    3924              : 
    3925            2 :         if (state.dataIPShortCut->lNumericFieldBlanks(12)) {
    3926            0 :             Tank.UseDesignVolFlowRate = 0.0;
    3927              :         } else {
    3928            2 :             Tank.UseDesignVolFlowRate = state.dataIPShortCut->rNumericArgs(12);
    3929            2 :             if (Tank.UseDesignVolFlowRate == DataSizing::AutoSize) {
    3930            2 :                 Tank.UseDesignVolFlowRateWasAutoSized = true;
    3931              :             }
    3932              :         }
    3933              : 
    3934            2 :         Tank.UseSidePlantLoc.loopSideNum = DataPlant::LoopSideLocation::Invalid;
    3935              : 
    3936            2 :         if (state.dataIPShortCut->lNumericFieldBlanks(16)) {
    3937            0 :             Tank.SourceDesignVolFlowRate = 0.0;
    3938              :         } else {
    3939            2 :             Tank.SourceDesignVolFlowRate = state.dataIPShortCut->rNumericArgs(16);
    3940            2 :             if (Tank.SourceDesignVolFlowRate == DataSizing::AutoSize) {
    3941            0 :                 Tank.SourceDesignVolFlowRateWasAutoSized = true;
    3942              :             }
    3943              :         }
    3944              : 
    3945            2 :         Tank.SizingRecoveryTime = state.dataIPShortCut->rNumericArgs(17);
    3946              : 
    3947            2 :         Tank.SrcSidePlantLoc.loopSideNum = DataPlant::LoopSideLocation::Invalid;
    3948              : 
    3949            2 :         if ((!state.dataIPShortCut->lAlphaFieldBlanks(8)) || (!state.dataIPShortCut->lAlphaFieldBlanks(9))) {
    3950            2 :             Tank.UseInletNode = NodeInputManager::GetOnlySingleNode(state,
    3951            2 :                                                                     state.dataIPShortCut->cAlphaArgs(8),
    3952              :                                                                     ErrorsFound,
    3953              :                                                                     DataLoopNode::ConnectionObjectType::ThermalStorageChilledWaterStratified,
    3954            2 :                                                                     state.dataIPShortCut->cAlphaArgs(1),
    3955              :                                                                     DataLoopNode::NodeFluidType::Water,
    3956              :                                                                     DataLoopNode::ConnectionType::Inlet,
    3957              :                                                                     NodeInputManager::CompFluidStream::Primary,
    3958              :                                                                     DataLoopNode::ObjectIsNotParent);
    3959            2 :             Tank.InletNodeName1 = state.dataIPShortCut->cAlphaArgs(8);
    3960            2 :             Tank.UseOutletNode = NodeInputManager::GetOnlySingleNode(state,
    3961            2 :                                                                      state.dataIPShortCut->cAlphaArgs(9),
    3962              :                                                                      ErrorsFound,
    3963              :                                                                      DataLoopNode::ConnectionObjectType::ThermalStorageChilledWaterStratified,
    3964            2 :                                                                      state.dataIPShortCut->cAlphaArgs(1),
    3965              :                                                                      DataLoopNode::NodeFluidType::Water,
    3966              :                                                                      DataLoopNode::ConnectionType::Outlet,
    3967              :                                                                      NodeInputManager::CompFluidStream::Primary,
    3968              :                                                                      DataLoopNode::ObjectIsNotParent);
    3969            2 :             Tank.OutletNodeName1 = state.dataIPShortCut->cAlphaArgs(9);
    3970              :         }
    3971              : 
    3972            2 :         if ((!state.dataIPShortCut->lAlphaFieldBlanks(11)) || (!state.dataIPShortCut->lAlphaFieldBlanks(12))) {
    3973            1 :             Tank.SourceInletNode = NodeInputManager::GetOnlySingleNode(state,
    3974            1 :                                                                        state.dataIPShortCut->cAlphaArgs(11),
    3975              :                                                                        ErrorsFound,
    3976              :                                                                        DataLoopNode::ConnectionObjectType::ThermalStorageChilledWaterStratified,
    3977            1 :                                                                        state.dataIPShortCut->cAlphaArgs(1),
    3978              :                                                                        DataLoopNode::NodeFluidType::Water,
    3979              :                                                                        DataLoopNode::ConnectionType::Inlet,
    3980              :                                                                        NodeInputManager::CompFluidStream::Secondary,
    3981              :                                                                        DataLoopNode::ObjectIsNotParent);
    3982            1 :             Tank.InletNodeName2 = state.dataIPShortCut->cAlphaArgs(11);
    3983            1 :             Tank.SourceOutletNode = NodeInputManager::GetOnlySingleNode(state,
    3984            1 :                                                                         state.dataIPShortCut->cAlphaArgs(12),
    3985              :                                                                         ErrorsFound,
    3986              :                                                                         DataLoopNode::ConnectionObjectType::ThermalStorageChilledWaterStratified,
    3987            1 :                                                                         state.dataIPShortCut->cAlphaArgs(1),
    3988              :                                                                         DataLoopNode::NodeFluidType::Water,
    3989              :                                                                         DataLoopNode::ConnectionType::Outlet,
    3990              :                                                                         NodeInputManager::CompFluidStream::Secondary,
    3991              :                                                                         DataLoopNode::ObjectIsNotParent);
    3992            1 :             Tank.OutletNodeName2 = state.dataIPShortCut->cAlphaArgs(12);
    3993              :         }
    3994              : 
    3995            2 :         if (state.dataIPShortCut->lAlphaFieldBlanks(10)) {
    3996            0 :             Tank.useSideAvailSched = Sched::GetScheduleAlwaysOn(state);
    3997            2 :         } else if ((Tank.useSideAvailSched = Sched::GetSchedule(state, state.dataIPShortCut->cAlphaArgs(10))) == nullptr) {
    3998            0 :             ShowSevereItemNotFound(state, eoh, state.dataIPShortCut->cAlphaFieldNames(10), state.dataIPShortCut->cAlphaArgs(10));
    3999            0 :             ErrorsFound = true;
    4000              :         }
    4001              : 
    4002            2 :         if (Tank.UseSidePlantLoc.loopSideNum == DataPlant::LoopSideLocation::Demand && Tank.SourceInletNode != 0) {
    4003            0 :             PlantUtilities::RegisterPlantCompDesignFlow(state, Tank.SourceInletNode, Tank.SourceDesignVolFlowRate);
    4004              :         }
    4005              : 
    4006            2 :         if (state.dataIPShortCut->lAlphaFieldBlanks(13)) {
    4007            0 :             Tank.sourceSideAvailSched = Sched::GetScheduleAlwaysOn(state);
    4008            2 :         } else if ((Tank.sourceSideAvailSched = Sched::GetSchedule(state, state.dataIPShortCut->cAlphaArgs(13))) == nullptr) {
    4009            0 :             ShowSevereItemNotFound(state, eoh, state.dataIPShortCut->cAlphaFieldNames(13), state.dataIPShortCut->cAlphaArgs(13));
    4010            0 :             ErrorsFound = true;
    4011              :         }
    4012              : 
    4013              :         // Validate inlet mode
    4014            2 :         Tank.InletMode =
    4015            2 :             static_cast<InletPositionMode>(getEnumValue(InletPositionModeNamesUC, Util::makeUPPER(state.dataIPShortCut->cAlphaArgs(14))));
    4016              : 
    4017            2 :         Tank.Nodes = state.dataIPShortCut->rNumericArgs(18);
    4018            2 :         Tank.AdditionalCond = state.dataIPShortCut->rNumericArgs(19);
    4019              : 
    4020            2 :         Tank.AdditionalLossCoeff.allocate(Tank.Nodes);
    4021            2 :         Tank.AdditionalLossCoeff = 0.0;
    4022            2 :         for (int NodeNum = 1; NodeNum <= Tank.Nodes; ++NodeNum) {
    4023            2 :             if (NumNums > 19 + NodeNum) {
    4024            0 :                 Tank.AdditionalLossCoeff(NodeNum) = state.dataIPShortCut->rNumericArgs(19 + NodeNum);
    4025              :             } else {
    4026            2 :                 break;
    4027              :             }
    4028              :         }
    4029              : 
    4030            2 :         if (NumNums > 19 + Tank.Nodes) {
    4031            0 :             ShowWarningError(
    4032              :                 state,
    4033            0 :                 format("{} = {}:  More Additional Loss Coefficients were entered than the number of nodes; extra coefficients will not be used",
    4034            0 :                        state.dataIPShortCut->cCurrentModuleObject,
    4035            0 :                        state.dataIPShortCut->cAlphaArgs(1)));
    4036              :         }
    4037              : 
    4038            2 :         Tank.SetupStratifiedNodes(state);
    4039              :     }
    4040              : 
    4041            2 :     return ErrorsFound;
    4042              : }
    4043              : 
    4044          450 : bool GetWaterThermalTankInput(EnergyPlusData &state)
    4045              : {
    4046              : 
    4047              :     // SUBROUTINE INFORMATION:
    4048              :     //       AUTHOR         Dan Fisher and Brandon Anderson
    4049              :     //       DATE WRITTEN   May 2000
    4050              :     //       MODIFIED       R. Raustad, June 2005, added HPWH and desuperheater water heating coils
    4051              :     //                      B. Griffith, Oct. 2007 extensions for indirect water heaters
    4052              :     //                      B. Griffith, Feb. 2008 extensions for autosizing water heaters
    4053              :     //                      BG Mar 2009.  Trap for bad heater height input for stratified water heater CR7718
    4054              :     //                      B. Shen 12/2014, add air-source variable-speed heat pump water heating
    4055              : 
    4056              :     // PURPOSE OF THIS SUBROUTINE:
    4057              :     // Gets the water heater, HPWH, and/or desuperheater heating coil input from the input file.
    4058              : 
    4059          450 :     bool ErrorsFound = false;
    4060              : 
    4061              :     // Make sure refrigeration input is gotten before this input
    4062          450 :     RefrigeratedCase::CheckRefrigerationInput(state);
    4063              : 
    4064          450 :     if (state.dataWaterThermalTanks->getWaterThermalTankInputFlag) {
    4065          450 :         state.dataWaterThermalTanks->numWaterHeaterMixed = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cMixedWHModuleObj);
    4066          900 :         state.dataWaterThermalTanks->numWaterHeaterStratified =
    4067          450 :             state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cStratifiedWHModuleObj);
    4068          900 :         state.dataWaterThermalTanks->numChilledWaterMixed =
    4069          450 :             state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cMixedCWTankModuleObj);
    4070          900 :         state.dataWaterThermalTanks->numChilledWaterStratified =
    4071          450 :             state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cStratifiedCWTankModuleObj);
    4072          900 :         state.dataWaterThermalTanks->numWaterThermalTank =
    4073          450 :             state.dataWaterThermalTanks->numWaterHeaterMixed + state.dataWaterThermalTanks->numWaterHeaterStratified +
    4074          450 :             state.dataWaterThermalTanks->numChilledWaterMixed + state.dataWaterThermalTanks->numChilledWaterStratified;
    4075          900 :         state.dataWaterThermalTanks->numHeatPumpWaterHeater =
    4076          450 :             state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cHPWHPumpedCondenser) +
    4077          450 :             state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cHPWHWrappedCondenser);
    4078          900 :         state.dataWaterThermalTanks->numWaterHeaterDesuperheater =
    4079          450 :             state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCoilDesuperheater);
    4080              : 
    4081          450 :         if (state.dataWaterThermalTanks->numWaterThermalTank > 0) {
    4082              :             static constexpr std::string_view Format_720(
    4083              :                 "! <Water Heater Information>,Type,Name,Volume {{m3}},Maximum Capacity {{W}},Standard Rated Recovery Efficiency, "
    4084              :                 "Standard Rated Energy Factor\n");
    4085              :             static constexpr std::string_view Format_721(
    4086              :                 "! <Heat Pump Water Heater Information>,Type,Name,Volume {{m3}},Maximum Capacity {{W}},Standard Rated Recovery "
    4087              :                 "Efficiency,Standard Rated Energy Factor,DX Coil Total Cooling Rate {{W}}\n");
    4088              :             static constexpr std::string_view Format_722(
    4089              :                 "! <Water Heater Stratified Node Information>,Node Number,Height {{m}},Volume {{m3}},Maximum Capacity "
    4090              :                 "{{W}},Off-Cycle UA {{W/K}},On-Cycle UA {{W/K}},Number Of Inlets,Number Of Outlets\n");
    4091              :             static constexpr std::string_view Format_725(
    4092              :                 "! <Chilled Water Tank Information>,Type,Name,Volume {{m3}},Use Side Design Flow Rate {{m3/s}}, "
    4093              :                 "Source Side Design Flow Rate {{m3/s}}\n");
    4094              :             static constexpr std::string_view Format_726(
    4095              :                 "! <Chilled Water Tank Stratified Node Information>,Node Number,Height {{m}},Volume {{m3}},UA {{W/K}},Number Of "
    4096              :                 "Inlets,Number Of Outlets\n");
    4097              : 
    4098              :             // Write water heater header for EIO
    4099          136 :             if ((state.dataWaterThermalTanks->numWaterHeaterMixed > 0) || (state.dataWaterThermalTanks->numWaterHeaterStratified > 0)) {
    4100          136 :                 print(state.files.eio, Format_720);
    4101              :             }
    4102          136 :             if (state.dataWaterThermalTanks->numHeatPumpWaterHeater > 0) {
    4103            9 :                 print(state.files.eio, Format_721);
    4104              :             }
    4105          136 :             if (state.dataWaterThermalTanks->numWaterHeaterStratified > 0) {
    4106           10 :                 print(state.files.eio, Format_722);
    4107              :             }
    4108          136 :             if (state.dataWaterThermalTanks->numChilledWaterMixed > 0) {
    4109            4 :                 print(state.files.eio, Format_725);
    4110              :             }
    4111          136 :             if (state.dataWaterThermalTanks->numChilledWaterStratified > 0) {
    4112            2 :                 print(state.files.eio, Format_726);
    4113              :             }
    4114              :         }
    4115              : 
    4116          450 :         if (state.dataWaterThermalTanks->numWaterThermalTank > 0) {
    4117          136 :             state.dataWaterThermalTanks->WaterThermalTank.allocate(state.dataWaterThermalTanks->numWaterThermalTank);
    4118          136 :             state.dataWaterThermalTanks->UniqueWaterThermalTankNames.reserve(static_cast<unsigned>(state.dataWaterThermalTanks->numWaterThermalTank));
    4119              :         }
    4120          450 :         if (state.dataWaterThermalTanks->numHeatPumpWaterHeater > 0) {
    4121            9 :             state.dataWaterThermalTanks->HPWaterHeater.allocate(state.dataWaterThermalTanks->numHeatPumpWaterHeater);
    4122              :         }
    4123              : 
    4124          450 :         if (state.dataWaterThermalTanks->numWaterHeaterDesuperheater > 0) {
    4125            6 :             state.dataWaterThermalTanks->WaterHeaterDesuperheater.allocate(state.dataWaterThermalTanks->numWaterHeaterDesuperheater);
    4126              :         }
    4127              : 
    4128              :         // =======   Get Coil:WaterHeating:Desuperheater ======================================================================
    4129          450 :         if (state.dataWaterThermalTanks->numWaterHeaterDesuperheater > 0) {
    4130            6 :             ErrorsFound |= getDesuperHtrInput(state);
    4131              :         }
    4132              : 
    4133              :         //  =======   Get HEAT PUMP:WATER HEATER ===============================================================================
    4134          450 :         if (state.dataWaterThermalTanks->numHeatPumpWaterHeater > 0) {
    4135            9 :             ErrorsFound |= getHPWaterHeaterInput(state);
    4136              :         }
    4137              : 
    4138              :         //  =======   Get WATER HEATER:MIXED ===================================================================================
    4139          450 :         if (state.dataWaterThermalTanks->numWaterHeaterMixed > 0) {
    4140          127 :             ErrorsFound |= getWaterHeaterMixedInputs(state);
    4141              :         }
    4142              : 
    4143              :         //  =======   Get WATER HEATER:STRATIFIED ==============================================================================
    4144          450 :         if (state.dataWaterThermalTanks->numWaterHeaterStratified > 0) {
    4145           10 :             ErrorsFound |= getWaterHeaterStratifiedInput(state);
    4146              :         }
    4147              : 
    4148              :         //  =======   Get Chilled Water :MIXED ===================================================================================
    4149          450 :         if (state.dataWaterThermalTanks->numChilledWaterMixed > 0) {
    4150            4 :             ErrorsFound |= getWaterTankMixedInput(state);
    4151              :         }
    4152              : 
    4153              :         //  =======   Get 'ThermalStorage:ChilledWater:Stratified' =======================================================
    4154          450 :         if (state.dataWaterThermalTanks->numChilledWaterStratified > 0) {
    4155            2 :             ErrorsFound |= getWaterTankStratifiedInput(state);
    4156              :         }
    4157              : 
    4158              :         //   Loop through all desuperheating coils and then search all water heaters for the tank connected to the desuperheating coil
    4159          450 :         if (state.dataWaterThermalTanks->numWaterHeaterDesuperheater > 0) {
    4160            6 :             state.dataIPShortCut->cCurrentModuleObject = cCoilDesuperheater;
    4161           12 :             for (int DesuperheaterNum = 1; DesuperheaterNum <= state.dataWaterThermalTanks->numWaterHeaterDesuperheater; ++DesuperheaterNum) {
    4162            6 :                 auto &DesuperHtr = state.dataWaterThermalTanks->WaterHeaterDesuperheater(DesuperheaterNum);
    4163           12 :                 for (int WtrHtrNum = 1; WtrHtrNum <= state.dataWaterThermalTanks->numWaterThermalTank; ++WtrHtrNum) {
    4164            6 :                     auto &Tank = state.dataWaterThermalTanks->WaterThermalTank(WtrHtrNum);
    4165            6 :                     if (!Util::SameString(DesuperHtr.TankName, Tank.Name) || !Util::SameString(DesuperHtr.TankType, Tank.Type)) {
    4166            0 :                         continue;
    4167              :                     }
    4168            6 :                     Tank.DesuperheaterNum = DesuperheaterNum;
    4169            6 :                     DesuperHtr.WaterHeaterTankNum = WtrHtrNum;
    4170            6 :                     DesuperHtr.TankTypeNum = Tank.WaterThermalTankType;
    4171            6 :                     DesuperHtr.BackupElementCapacity = Tank.MaxCapacity;
    4172            6 :                     if (Tank.UseInletNode == 0 && Tank.UseOutletNode == 0) {
    4173            6 :                         DesuperHtr.StandAlone = true;
    4174              :                     }
    4175              : 
    4176              :                     //         verify Desuperheater/tank source node connections
    4177            6 :                     if (DesuperHtr.WaterInletNode != Tank.SourceOutletNode) {
    4178            0 :                         ShowSevereError(state, format("{} = {}:", state.dataIPShortCut->cCurrentModuleObject, DesuperHtr.Name));
    4179            0 :                         ShowContinueError(state, "Desuperheater inlet node name does not match thermal tank source outlet node name.");
    4180            0 :                         ShowContinueError(state,
    4181            0 :                                           format("Desuperheater water inlet and outlet node names = {} and {}",
    4182            0 :                                                  DesuperHtr.InletNodeName1,
    4183            0 :                                                  DesuperHtr.OutletNodeName1));
    4184            0 :                         ShowContinueError(state,
    4185            0 :                                           format("Thermal tank source side inlet and outlet node names      = {} and {}",
    4186            0 :                                                  Tank.InletNodeName2,
    4187            0 :                                                  Tank.OutletNodeName2));
    4188            0 :                         ErrorsFound = true;
    4189              :                     }
    4190              : 
    4191            6 :                     if (DesuperHtr.WaterOutletNode != Tank.SourceInletNode) {
    4192            0 :                         ShowSevereError(state, format("{} = {}:", state.dataIPShortCut->cCurrentModuleObject, DesuperHtr.Name));
    4193            0 :                         ShowContinueError(state, "Desuperheater water outlet node name does not match thermal tank source inlet node name.");
    4194            0 :                         ShowContinueError(state,
    4195            0 :                                           format("Desuperheater water inlet and outlet node names = {} and {}",
    4196            0 :                                                  DesuperHtr.InletNodeName1,
    4197            0 :                                                  DesuperHtr.OutletNodeName1));
    4198            0 :                         ShowContinueError(state,
    4199            0 :                                           format("Thermal tank source side inlet and outlet node names      = {} and {}",
    4200            0 :                                                  Tank.InletNodeName2,
    4201            0 :                                                  Tank.OutletNodeName2));
    4202            0 :                         ErrorsFound = true;
    4203              :                     }
    4204              :                 }
    4205              : 
    4206            6 :                 if (DesuperHtr.WaterHeaterTankNum == 0) {
    4207            0 :                     ShowSevereError(state, format("{} = {}:", state.dataIPShortCut->cCurrentModuleObject, DesuperHtr.Name));
    4208            0 :                     ShowContinueError(state, format(" Water heater tank = {} not found.", DesuperHtr.TankName));
    4209            0 :                     ErrorsFound = true;
    4210              :                 }
    4211              :             }
    4212              :         }
    4213              : 
    4214              :         // Loop through HPWH's and then search all water heaters for the tank connected to the HPWH
    4215          450 :         if (state.dataWaterThermalTanks->numHeatPumpWaterHeater > 0) {
    4216              : 
    4217            9 :             int const NumPumpedCondenser = state.dataInputProcessing->inputProcessor->getNumObjectsFound(
    4218              :                 state, cHPWHPumpedCondenser); // number of WaterHeater:HeatPump:PumpedCondenser objects
    4219           32 :             for (int HPWaterHeaterNum = 1; HPWaterHeaterNum <= state.dataWaterThermalTanks->numHeatPumpWaterHeater; ++HPWaterHeaterNum) {
    4220              : 
    4221              :                 // Create reference to current HPWH object in array.
    4222           23 :                 HeatPumpWaterHeaterData &HPWH = state.dataWaterThermalTanks->HPWaterHeater(HPWaterHeaterNum);
    4223           23 :                 if (HPWaterHeaterNum <= NumPumpedCondenser) {
    4224              :                     // Pumped Condenser
    4225           20 :                     state.dataIPShortCut->cCurrentModuleObject = cHPWHPumpedCondenser;
    4226              :                 } else {
    4227              :                     // Wrapped Condenser
    4228            3 :                     state.dataIPShortCut->cCurrentModuleObject = cHPWHWrappedCondenser;
    4229              :                 }
    4230              : 
    4231              :                 // find the tank associated with the heat pump water heater and change its %TYPE to HEAT PUMP:WATER HEATER
    4232          143 :                 for (int CheckWaterHeaterNum = 1; CheckWaterHeaterNum <= state.dataWaterThermalTanks->numWaterThermalTank; ++CheckWaterHeaterNum) {
    4233              : 
    4234          120 :                     auto &Tank = state.dataWaterThermalTanks->WaterThermalTank(CheckWaterHeaterNum);
    4235              : 
    4236          120 :                     if (!(Util::SameString(HPWH.TankName, Tank.Name) && Util::SameString(HPWH.TankType, Tank.Type))) {
    4237           97 :                         continue;
    4238              :                     }
    4239              : 
    4240              :                     // save backup element and on/off-cycle parasitic properties for use during standard rating procedure
    4241           23 :                     HPWH.BackupElementCapacity = Tank.MaxCapacity;
    4242           23 :                     HPWH.BackupElementEfficiency = Tank.Efficiency;
    4243           23 :                     HPWH.WHOnCycParaLoad = Tank.OnCycParaLoad;
    4244           23 :                     HPWH.WHOffCycParaLoad = Tank.OffCycParaLoad;
    4245           23 :                     HPWH.WHOnCycParaFracToTank = Tank.OnCycParaFracToTank;
    4246           23 :                     HPWH.WHOffCycParaFracToTank = Tank.OffCycParaFracToTank;
    4247           23 :                     HPWH.WHPLFCurve = Tank.PLFCurve;
    4248              : 
    4249           23 :                     if (((Tank.WaterThermalTankType == DataPlant::PlantEquipmentType::WtrHeaterMixed) &&
    4250           12 :                          (HPWH.HPWHType == DataPlant::PlantEquipmentType::HeatPumpWtrHeaterPumped)) ||
    4251           11 :                         (Tank.WaterThermalTankType == DataPlant::PlantEquipmentType::WtrHeaterStratified)) {
    4252           23 :                         HPWH.TankType = Tank.Type;
    4253           23 :                         HPWH.HPWHTankType = Tank.WaterThermalTankType;
    4254              :                     } else {
    4255            0 :                         ShowSevereError(state, format("{} = {}:", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    4256            0 :                         ShowContinueError(state, format("Invalid water heater tank type = {}", Tank.Type));
    4257            0 :                         ErrorsFound = true;
    4258              :                     }
    4259              : 
    4260              :                     // Set up comp set for condenser water side nodes (reverse inlet/outlet for water heater)
    4261           23 :                     if (HPWH.bIsIHP) {
    4262            2 :                         BranchNodeConnections::SetUpCompSets(state,
    4263              :                                                              HPWH.Type,
    4264              :                                                              HPWH.Name,
    4265              :                                                              HPWH.DXCoilType,
    4266            2 :                                                              HPWH.DXCoilName + " Water Coil",
    4267              :                                                              HPWH.InletNodeName1,
    4268              :                                                              HPWH.OutletNodeName1,
    4269              :                                                              "HPWH To Coil");
    4270              :                     } else {
    4271           22 :                         BranchNodeConnections::SetUpCompSets(
    4272              :                             state, HPWH.Type, HPWH.Name, HPWH.DXCoilType, HPWH.DXCoilName, HPWH.InletNodeName1, HPWH.OutletNodeName1, "HPWH To Coil");
    4273              :                     }
    4274           23 :                     BranchNodeConnections::SetUpCompSets(
    4275              :                         state, HPWH.Type, HPWH.Name, HPWH.TankType, HPWH.TankName, HPWH.OutletNodeName1, HPWH.InletNodeName1, "HPWH To Tank");
    4276              : 
    4277              :                     // If WaterHeaterMixed: do not allow modulating control for HPWH's (i.e. modulating control usually used for tankless WH's)
    4278           23 :                     if ((Tank.WaterThermalTankType == DataPlant::PlantEquipmentType::WtrHeaterMixed) &&
    4279           12 :                         (Tank.ControlType == HeaterControlMode::Modulate)) {
    4280            0 :                         ShowSevereError(state, format("{} = {}:", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    4281            0 :                         ShowContinueError(state, format("Heater Control Type for {} = {} must be CYCLE.", Tank.Type, Tank.Name));
    4282            0 :                         ErrorsFound = true;
    4283              :                     }
    4284              : 
    4285           23 :                     Tank.HeatPumpNum = HPWaterHeaterNum;
    4286           23 :                     HPWH.WaterHeaterTankNum = CheckWaterHeaterNum;
    4287           23 :                     HPWH.FoundTank = true;
    4288              : 
    4289           23 :                     if (Tank.DesuperheaterNum > 0) {
    4290            0 :                         ShowSevereError(
    4291              :                             state,
    4292            0 :                             format("{} = {}and Coil:WaterHeating:Desuperheater = {}:  cannot be connected to the same water heater tank = {}",
    4293            0 :                                    state.dataIPShortCut->cCurrentModuleObject,
    4294            0 :                                    HPWH.Name,
    4295            0 :                                    state.dataWaterThermalTanks->WaterHeaterDesuperheater(CheckWaterHeaterNum).Name,
    4296            0 :                                    Tank.Name));
    4297              :                     }
    4298              : 
    4299              :                     // check that water heater source side effectiveness is greater than 0
    4300           23 :                     if (Tank.SourceEffectiveness <= 0.0) {
    4301            0 :                         ShowSevereError(state,
    4302            0 :                                         format("{} = {}:  Invalid source side effectiveness for heat pump water heater = {:.3T}",
    4303            0 :                                                state.dataIPShortCut->cCurrentModuleObject,
    4304            0 :                                                HPWH.Name,
    4305            0 :                                                Tank.SourceEffectiveness));
    4306            0 :                         ShowContinueError(state, " water heater source effectiveness will default to 1.0 and simulation continues.");
    4307            0 :                         Tank.SourceEffectiveness = 1.0;
    4308              :                     }
    4309              : 
    4310              :                     // Set up the source side nodes for wrapped condensers
    4311           23 :                     if (HPWH.HPWHType == DataPlant::PlantEquipmentType::HeatPumpWtrHeaterWrapped) {
    4312            3 :                         if (Tank.SourceInletNode > 0 || Tank.SourceOutletNode > 0) {
    4313            0 :                             ShowSevereError(state, format("{} = {} has a source inlet or outlet node specified,", Tank.Type, Tank.Name));
    4314            0 :                             ShowContinueError(
    4315            0 :                                 state, format("but it is attached to {} = {}, which doesn't permit source side connections.", HPWH.Type, HPWH.Name));
    4316            0 :                             ShowContinueError(state, "Please leave the source side inlet and outlet fields blank.");
    4317            0 :                             ErrorsFound = true;
    4318              :                         } else {
    4319              : 
    4320              :                             DataLoopNode::ConnectionObjectType objType = static_cast<DataLoopNode::ConnectionObjectType>(
    4321            3 :                                 getEnumValue(BranchNodeConnections::ConnectionObjectTypeNamesUC, Util::makeUPPER(Tank.Type)));
    4322              : 
    4323            3 :                             Tank.SourceInletNode = NodeInputManager::GetOnlySingleNode(state,
    4324            3 :                                                                                        HPWH.OutletNodeName1,
    4325              :                                                                                        ErrorsFound,
    4326              :                                                                                        objType,
    4327            3 :                                                                                        Tank.Name,
    4328              :                                                                                        DataLoopNode::NodeFluidType::Water,
    4329              :                                                                                        DataLoopNode::ConnectionType::Inlet,
    4330              :                                                                                        NodeInputManager::CompFluidStream::Secondary,
    4331              :                                                                                        DataLoopNode::ObjectIsNotParent);
    4332            3 :                             Tank.InletNodeName2 = HPWH.OutletNodeName1;
    4333            3 :                             Tank.SourceOutletNode = NodeInputManager::GetOnlySingleNode(state,
    4334            3 :                                                                                         HPWH.InletNodeName1,
    4335              :                                                                                         ErrorsFound,
    4336              :                                                                                         objType,
    4337            3 :                                                                                         Tank.Name,
    4338              :                                                                                         DataLoopNode::NodeFluidType::Water,
    4339              :                                                                                         DataLoopNode::ConnectionType::Outlet,
    4340              :                                                                                         NodeInputManager::CompFluidStream::Secondary,
    4341              :                                                                                         DataLoopNode::ObjectIsNotParent);
    4342            3 :                             Tank.OutletNodeName2 = HPWH.InletNodeName1;
    4343              :                         }
    4344              : 
    4345              :                         // Mark the tank as not stand alone because it is connected now.
    4346            3 :                         Tank.StandAlone = false;
    4347              :                     }
    4348              : 
    4349              :                     // Set HPWH structure variable StandAlone to TRUE if use nodes are not connected
    4350           23 :                     if (Tank.UseInletNode == 0 && Tank.UseOutletNode == 0) {
    4351           13 :                         HPWH.StandAlone = true;
    4352              :                     }
    4353              : 
    4354           23 :                     if (HPWH.WHUseInletNode != Tank.UseInletNode || HPWH.WHUseOutletNode != Tank.UseOutletNode) {
    4355            0 :                         ShowSevereError(state, format("{} = {}:", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    4356            0 :                         ShowContinueError(state,
    4357            0 :                                           format("Heat pump water heater tank use side inlet and outlet node names must match the use side inlet and "
    4358              :                                                  "outlet node names for water heater tank = {}: {}",
    4359            0 :                                                  HPWH.TankType,
    4360            0 :                                                  HPWH.TankName));
    4361            0 :                         ShowContinueError(state,
    4362            0 :                                           format("Heat pump water heater use side inlet and outlet node names = {} and {}",
    4363            0 :                                                  HPWH.InletNodeName2,
    4364            0 :                                                  HPWH.OutletNodeName2));
    4365            0 :                         ShowContinueError(state,
    4366            0 :                                           format("Water heater tank use side inlet and outlet node names      = {} and {}",
    4367            0 :                                                  Tank.InletNodeName1,
    4368            0 :                                                  Tank.OutletNodeName1));
    4369            0 :                         ErrorsFound = true;
    4370              :                     } else {
    4371           23 :                         if (!HPWH.StandAlone) {
    4372           20 :                             BranchNodeConnections::TestCompSet(state, HPWH.Type, HPWH.Name, Tank.InletNodeName1, Tank.OutletNodeName1, "Water Nodes");
    4373              :                         }
    4374              :                     }
    4375              : 
    4376              :                     // verify HP/tank source node connections
    4377           23 :                     if (HPWH.CondWaterInletNode != Tank.SourceOutletNode) {
    4378            0 :                         ShowSevereError(state, format("{} = {}:", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    4379            0 :                         ShowContinueError(state,
    4380              :                                           "Heat Pump condenser water inlet node name does not match water heater tank source outlet node name.");
    4381            0 :                         ShowContinueError(
    4382              :                             state,
    4383            0 :                             format("Heat pump condenser water inlet and outlet node names = {} and {}", HPWH.InletNodeName1, HPWH.OutletNodeName1));
    4384            0 :                         ShowContinueError(state,
    4385            0 :                                           format("Water heater tank source side inlet and outlet node names      = {} and {}",
    4386            0 :                                                  Tank.InletNodeName2,
    4387            0 :                                                  Tank.OutletNodeName2));
    4388            0 :                         ErrorsFound = true;
    4389              :                     }
    4390              : 
    4391           23 :                     if (HPWH.CondWaterOutletNode != Tank.SourceInletNode) {
    4392            0 :                         ShowSevereError(state, format("{} = {}:", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    4393            0 :                         ShowContinueError(state,
    4394              :                                           "Heat Pump condenser water outlet node name does not match water heater tank source inlet node name.");
    4395            0 :                         ShowContinueError(
    4396              :                             state,
    4397            0 :                             format("Heat pump condenser water inlet and outlet node names = {} and {}", HPWH.InletNodeName1, HPWH.OutletNodeName1));
    4398            0 :                         ShowContinueError(state,
    4399            0 :                                           format("Water heater tank source side inlet and outlet node names      = {} and {}",
    4400            0 :                                                  Tank.InletNodeName2,
    4401            0 :                                                  Tank.OutletNodeName2));
    4402            0 :                         ErrorsFound = true;
    4403              :                     }
    4404              : 
    4405              :                     // verify wrapped condenser location
    4406           23 :                     if (HPWH.HPWHType == DataPlant::PlantEquipmentType::HeatPumpWtrHeaterWrapped) {
    4407              :                         // make sure the top of the condenser is not above the tank height.
    4408            3 :                         if (HPWH.WrappedCondenserTopLocation > Tank.Height) {
    4409            0 :                             ShowSevereError(state, format("{} = {}:", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    4410            0 :                             ShowContinueError(state, "The height of the top of the wrapped condenser is greater than the height of the tank.");
    4411            0 :                             ErrorsFound = true;
    4412              :                         }
    4413              :                     }
    4414              : 
    4415              :                     // Verify tank name is in a zone equipment list if HPWH Inlet Air Configuration is Zone Air Only or Zone and Outdoor Air
    4416           23 :                     if (HPWH.InletAirConfiguration == WTTAmbientTemp::TempZone || HPWH.InletAirConfiguration == WTTAmbientTemp::ZoneAndOA) {
    4417           10 :                         if (allocated(state.dataZoneEquip->ZoneEquipConfig) && allocated(state.dataZoneEquip->ZoneEquipList)) {
    4418           10 :                             bool FoundTankInList = false;
    4419           10 :                             bool TankNotLowestPriority = false;
    4420           10 :                             int ZoneEquipConfigNum = HPWH.AmbientTempZone;
    4421           10 :                             int ZoneEquipListNum = state.dataZoneEquip->ZoneEquipConfig(ZoneEquipConfigNum).EquipListIndex;
    4422           10 :                             int TankCoolingPriority = 0;
    4423           10 :                             int TankHeatingPriority = 0;
    4424           10 :                             auto const &zoneEquipList = state.dataZoneEquip->ZoneEquipList(ZoneEquipListNum);
    4425           19 :                             for (int EquipmentTypeNum = 1; EquipmentTypeNum <= zoneEquipList.NumOfEquipTypes; ++EquipmentTypeNum) {
    4426           19 :                                 if (zoneEquipList.EquipName(EquipmentTypeNum) != HPWH.Name) {
    4427            9 :                                     continue;
    4428              :                                 }
    4429           10 :                                 FoundTankInList = true;
    4430           10 :                                 TankCoolingPriority = zoneEquipList.CoolingPriority(EquipmentTypeNum);
    4431           10 :                                 TankHeatingPriority = zoneEquipList.HeatingPriority(EquipmentTypeNum);
    4432           10 :                                 break;
    4433              :                             } // EquipmentTypeNum
    4434           10 :                             if (!FoundTankInList) {
    4435            0 :                                 ShowSevereError(state, format("{} = {}:", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    4436            0 :                                 ShowContinueError(state,
    4437              :                                                   "Heat pump water heater type and name must be listed in the correct "
    4438              :                                                   "ZoneHVAC:EquipmentList object when Inlet Air Configuration is equal to "
    4439              :                                                   "ZoneAirOnly or ZoneAndOutdoorAir.");
    4440            0 :                                 ErrorsFound = true;
    4441              :                             }
    4442              :                             //                     check that tank has lower priority than all other non-HPWH objects in Zone
    4443              :                             //                     Equipment List
    4444           39 :                             for (int EquipmentTypeNum = 1; EquipmentTypeNum <= zoneEquipList.NumOfEquipTypes; ++EquipmentTypeNum) {
    4445           29 :                                 if (Util::SameString(zoneEquipList.EquipTypeName(EquipmentTypeNum), state.dataIPShortCut->cCurrentModuleObject)) {
    4446           14 :                                     continue;
    4447              :                                 }
    4448           30 :                                 if (TankCoolingPriority > zoneEquipList.CoolingPriority(EquipmentTypeNum) ||
    4449           15 :                                     TankHeatingPriority > zoneEquipList.HeatingPriority(EquipmentTypeNum)) {
    4450            0 :                                     TankNotLowestPriority = true;
    4451              :                                 }
    4452              :                             } // EquipmentTypeNum
    4453           10 :                             if (TankNotLowestPriority && FoundTankInList) {
    4454            0 :                                 ShowWarningError(state, format("{} = {}:", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    4455            0 :                                 ShowContinueError(state,
    4456              :                                                   "Heat pump water heaters should be simulated first, before other space "
    4457              :                                                   "conditioning equipment.");
    4458            0 :                                 ShowContinueError(state,
    4459              :                                                   "Poor temperature control may result if the Heating/Cooling sequence number is "
    4460              :                                                   "not 1 in the ZoneHVAC:EquipmentList.");
    4461              :                             }
    4462              :                         } else {
    4463            0 :                             ShowSevereError(state, format("{} = {}:", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    4464            0 :                             ShowContinueError(state,
    4465              :                                               "ZoneHVAC:EquipmentList and ZoneHVAC:EquipmentConnections objects are required when Inlet Air "
    4466              :                                               "Configuration is either ZoneAirOnly or ZoneAndOutdoorAir.");
    4467            0 :                             ErrorsFound = true;
    4468              :                         } // ALLOCATED
    4469              :                     } // InletAirConfiguration
    4470              : 
    4471           23 :                     if (Tank.WaterThermalTankType == DataPlant::PlantEquipmentType::WtrHeaterStratified) {
    4472              : 
    4473              :                         // Nodal heat distribution fraction for stratified tank wrapped condensers
    4474           11 :                         if (HPWH.HPWHType == DataPlant::PlantEquipmentType::HeatPumpWtrHeaterWrapped) {
    4475            3 :                             if (Tank.Shape == TankShape::HorizCylinder) {
    4476            0 :                                 ShowWarningError(state, format("{} = {}:", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    4477            0 :                                 ShowContinueError(state, "A wrapped condenser HPWH model should not be used with a horizontal stratified tank.");
    4478            0 :                                 ShowContinueError(
    4479              :                                     state, "Ignoring condenser location and distributing heat evenly throughout the tank. Simulation continues.");
    4480            0 :                                 Real64 const SameFrac = 1.0 / Tank.Nodes;
    4481            0 :                                 for (int NodeNum = 1; NodeNum <= Tank.Nodes; ++NodeNum) {
    4482            0 :                                     Tank.Node(NodeNum).HPWHWrappedCondenserHeatingFrac = SameFrac;
    4483              :                                 }
    4484              :                             } else {
    4485            3 :                                 Real64 H0 = Tank.Height; // height of top of node
    4486              :                                 Real64 H;                // height of bottom of node
    4487            3 :                                 Real64 SumFrac(0.0);
    4488              :                                 // Get the fraction of each stratified node that is wrapped by the condenser
    4489           17 :                                 for (int NodeNum = 1; NodeNum <= Tank.Nodes; ++NodeNum) {
    4490           14 :                                     StratifiedNodeData &CurNode = Tank.Node(NodeNum);
    4491           14 :                                     if (NodeNum == Tank.Nodes) {
    4492            3 :                                         H = 0.0;
    4493              :                                     } else {
    4494           11 :                                         H = H0 - CurNode.Height;
    4495              :                                     }
    4496           14 :                                     if (H < HPWH.WrappedCondenserBottomLocation && H0 > HPWH.WrappedCondenserBottomLocation) {
    4497              :                                         // The bottom of the condenser starts partway through this node.
    4498            3 :                                         CurNode.HPWHWrappedCondenserHeatingFrac = 1.0 - (HPWH.WrappedCondenserBottomLocation - H) / CurNode.Height;
    4499           11 :                                     } else if (H >= HPWH.WrappedCondenserBottomLocation && H <= HPWH.WrappedCondenserTopLocation) {
    4500            6 :                                         if (H0 > HPWH.WrappedCondenserTopLocation) {
    4501              :                                             // the top of the condenser ends partway through this node.
    4502            1 :                                             CurNode.HPWHWrappedCondenserHeatingFrac = (HPWH.WrappedCondenserTopLocation - H) / CurNode.Height;
    4503              :                                         } else {
    4504              :                                             // the entire node is wrapped by the condenser
    4505            5 :                                             CurNode.HPWHWrappedCondenserHeatingFrac = 1.0;
    4506              :                                         }
    4507              :                                     } else {
    4508            5 :                                         CurNode.HPWHWrappedCondenserHeatingFrac = 0.0;
    4509              :                                     }
    4510           14 :                                     SumFrac += CurNode.HPWHWrappedCondenserHeatingFrac;
    4511           14 :                                     H0 = H;
    4512              :                                 }
    4513              :                                 // Normalize the fractions so they sum to 1.
    4514           17 :                                 for (int NodeNum = 1; NodeNum <= Tank.Nodes; ++NodeNum) {
    4515           14 :                                     Tank.Node(NodeNum).HPWHWrappedCondenserHeatingFrac /= SumFrac;
    4516              :                                 }
    4517              :                             }
    4518              :                         }
    4519              : 
    4520              :                         // Stratified Tank HPWH control sensor node locations
    4521           11 :                         if (HPWH.ControlSensor1Height < 0.0) {
    4522              :                             // default to heater 1
    4523            0 :                             HPWH.ControlSensor1Height = Tank.HeaterHeight1;
    4524              :                         }
    4525           11 :                         if (HPWH.ControlSensor2Height < 0.0) {
    4526              :                             // default to heater 2
    4527            0 :                             HPWH.ControlSensor2Height = Tank.HeaterHeight2;
    4528              :                         }
    4529              : 
    4530              :                         // Get the vertical tank height depending on the type of tank
    4531              :                         Real64 TankHeight;
    4532           11 :                         if (Tank.Shape == TankShape::VertCylinder || Tank.Shape == TankShape::Other) {
    4533           11 :                             TankHeight = Tank.Height;
    4534              :                         } else {
    4535            0 :                             assert(Tank.Shape == TankShape::HorizCylinder);
    4536              :                             // For horizontal cylinders, the tank "height" is actually the length.
    4537              :                             // We need to calculate the height.
    4538            0 :                             Real64 EndArea = Tank.Volume / Tank.Height;
    4539            0 :                             Real64 Radius = std::sqrt(EndArea / Constant::Pi);
    4540            0 :                             TankHeight = 2.0 * Radius; // actual vertical height
    4541              :                         }
    4542              : 
    4543              :                         // Make sure the control sensor locations are in the tank
    4544           11 :                         if (HPWH.ControlSensor1Height < 0.0 || HPWH.ControlSensor1Height > TankHeight) {
    4545            0 :                             ShowSevereError(state, format("{} = {}:", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    4546            0 :                             ShowContinueError(state, "Control Sensor 1 is located outside the tank.");
    4547            0 :                             ErrorsFound = true;
    4548              :                         }
    4549           11 :                         if (HPWH.ControlSensor2Height < 0.0 || HPWH.ControlSensor2Height > TankHeight) {
    4550            0 :                             ShowSevereError(state, format("{} = {}:", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    4551            0 :                             ShowContinueError(state, "Control Sensor 2 is located outside the tank.");
    4552            0 :                             ErrorsFound = true;
    4553              :                         }
    4554              : 
    4555              :                         // Assign the control sensors to the appropriate nodes
    4556           11 :                         Real64 H0 = TankHeight;
    4557              :                         Real64 H;
    4558           97 :                         for (int NodeNum = 1; NodeNum <= Tank.Nodes; ++NodeNum) {
    4559           86 :                             StratifiedNodeData const &TankNode = Tank.Node(NodeNum);
    4560           86 :                             if (NodeNum == Tank.Nodes) {
    4561           11 :                                 H = -1.0; // Avoids rounding errors and ensures that anything at height 0.0 goes into the bottom node
    4562              :                             } else {
    4563           75 :                                 H = H0 - TankNode.Height;
    4564              :                             }
    4565              : 
    4566              :                             // Control Sensor 1 Node
    4567           86 :                             if (HPWH.ControlSensor1Height <= H0 && HPWH.ControlSensor1Height > H) {
    4568           11 :                                 HPWH.ControlSensor1Node = NodeNum;
    4569              :                             }
    4570              : 
    4571              :                             // Control Sensor 2 Node
    4572           86 :                             if (HPWH.ControlSensor2Height <= H0 && HPWH.ControlSensor2Height > H) {
    4573           11 :                                 HPWH.ControlSensor2Node = NodeNum;
    4574              :                             }
    4575              : 
    4576           86 :                             H0 = H;
    4577              :                         }
    4578              :                     }
    4579              : 
    4580              :                 } // DO CheckWaterHeaterNum = 1, NumWaterHeater
    4581              : 
    4582           23 :                 if (!HPWH.FoundTank) {
    4583            0 :                     ShowSevereError(state, format("{} = {}:", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    4584            0 :                     ShowContinueError(state, format("Water heater tank object not found = {}, {}", HPWH.TankType, HPWH.TankName));
    4585            0 :                     ErrorsFound = true;
    4586              :                 }
    4587              : 
    4588              :             } // DO HPWaterHeaterNum = 1, NumHeatPumpWaterHeater
    4589              :         }
    4590              : 
    4591              :         // Get water heater sizing input.
    4592          450 :         state.dataIPShortCut->cCurrentModuleObject = "WaterHeater:Sizing";
    4593          900 :         state.dataWaterThermalTanks->numWaterHeaterSizing =
    4594          450 :             state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, state.dataIPShortCut->cCurrentModuleObject);
    4595              : 
    4596          450 :         if (state.dataWaterThermalTanks->numWaterHeaterSizing > 0) {
    4597              : 
    4598           14 :             for (int WHsizingNum = 1; WHsizingNum <= state.dataWaterThermalTanks->numWaterHeaterSizing; ++WHsizingNum) {
    4599              :                 int NumAlphas;
    4600              :                 int NumNums;
    4601              :                 int IOStat;
    4602           14 :                 state.dataInputProcessing->inputProcessor->getObjectItem(state,
    4603            7 :                                                                          state.dataIPShortCut->cCurrentModuleObject,
    4604              :                                                                          WHsizingNum,
    4605            7 :                                                                          state.dataIPShortCut->cAlphaArgs,
    4606              :                                                                          NumAlphas,
    4607            7 :                                                                          state.dataIPShortCut->rNumericArgs,
    4608              :                                                                          NumNums,
    4609              :                                                                          IOStat);
    4610              : 
    4611              :                 // find which water heater this object is for
    4612            7 :                 int WaterThermalTankNum = Util::FindItemInList(state.dataIPShortCut->cAlphaArgs(1), state.dataWaterThermalTanks->WaterThermalTank);
    4613            7 :                 if (WaterThermalTankNum == 0) {
    4614              :                     // did not match name throw warning.
    4615            0 :                     ShowSevereError(state,
    4616            0 :                                     format("{} object name: {} does not match any of the water heaters defined in the file",
    4617            0 :                                            state.dataIPShortCut->cCurrentModuleObject,
    4618            0 :                                            state.dataIPShortCut->cAlphaArgs(1)));
    4619            0 :                     ErrorsFound = true;
    4620            0 :                     continue;
    4621              :                 } else { // we have a match
    4622              :                     // store the sizing data in "sizing" nested derived type for the correct water heater
    4623              : 
    4624            7 :                     if (Util::SameString(state.dataIPShortCut->cAlphaArgs(2), "PeakDraw")) {
    4625            4 :                         state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.DesignMode = SizingMode::PeakDraw;
    4626            3 :                     } else if (Util::SameString(state.dataIPShortCut->cAlphaArgs(2), "ResidentialHUD-FHAMinimum")) {
    4627            3 :                         state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.DesignMode = SizingMode::ResidentialMin;
    4628            0 :                     } else if (Util::SameString(state.dataIPShortCut->cAlphaArgs(2), "PerPerson")) {
    4629            0 :                         state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.DesignMode = SizingMode::PerPerson;
    4630            0 :                     } else if (Util::SameString(state.dataIPShortCut->cAlphaArgs(2), "PerFloorArea")) {
    4631            0 :                         state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.DesignMode = SizingMode::PerFloorArea;
    4632            0 :                     } else if (Util::SameString(state.dataIPShortCut->cAlphaArgs(2), "PerUnit")) {
    4633            0 :                         state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.DesignMode = SizingMode::PerUnit;
    4634            0 :                     } else if (Util::SameString(state.dataIPShortCut->cAlphaArgs(2), "PerSolarCollectorArea")) {
    4635            0 :                         state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.DesignMode = SizingMode::PerSolarColArea;
    4636              :                     } else {
    4637              :                         // wrong design mode entered, throw error
    4638            0 :                         ShowSevereError(state,
    4639            0 :                                         format("{} object named: {} contains an incorrect Design Mode of: {}",
    4640            0 :                                                state.dataIPShortCut->cCurrentModuleObject,
    4641            0 :                                                state.dataIPShortCut->cAlphaArgs(1),
    4642            0 :                                                state.dataIPShortCut->cAlphaArgs(2)));
    4643            0 :                         ErrorsFound = true;
    4644              :                     }
    4645              : 
    4646            7 :                     state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.TankDrawTime = state.dataIPShortCut->rNumericArgs(1);
    4647            7 :                     state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.RecoveryTime = state.dataIPShortCut->rNumericArgs(2);
    4648            7 :                     state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.NominalVolForSizingDemandSideFlow =
    4649            7 :                         state.dataIPShortCut->rNumericArgs(3);
    4650            7 :                     state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.NumberOfBedrooms =
    4651            7 :                         int(state.dataIPShortCut->rNumericArgs(4));
    4652            7 :                     state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.NumberOfBathrooms =
    4653            7 :                         int(state.dataIPShortCut->rNumericArgs(5));
    4654            7 :                     state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.TankCapacityPerPerson =
    4655            7 :                         state.dataIPShortCut->rNumericArgs(6);
    4656            7 :                     state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.RecoveryCapacityPerPerson =
    4657            7 :                         state.dataIPShortCut->rNumericArgs(7);
    4658            7 :                     state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.TankCapacityPerArea =
    4659            7 :                         state.dataIPShortCut->rNumericArgs(8);
    4660            7 :                     state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.RecoveryCapacityPerArea =
    4661            7 :                         state.dataIPShortCut->rNumericArgs(9);
    4662            7 :                     state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.NumberOfUnits = state.dataIPShortCut->rNumericArgs(10);
    4663            7 :                     state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.TankCapacityPerUnit =
    4664            7 :                         state.dataIPShortCut->rNumericArgs(11);
    4665            7 :                     state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.RecoveryCapacityPerUnit =
    4666            7 :                         state.dataIPShortCut->rNumericArgs(12);
    4667            7 :                     state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.TankCapacityPerCollectorArea =
    4668            7 :                         state.dataIPShortCut->rNumericArgs(13);
    4669            7 :                     state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.HeightAspectRatio =
    4670            7 :                         state.dataIPShortCut->rNumericArgs(14);
    4671              : 
    4672            7 :                     switch (state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.DesignMode) {
    4673              : 
    4674            0 :                     case SizingMode::Invalid: {
    4675              :                         // do nothing, error thrown if design mode not found
    4676            0 :                         break;
    4677              :                     }
    4678            4 :                     case SizingMode::PeakDraw: { // need to have entered a reasonable value for TankDrawTime
    4679            4 :                         if (state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.TankDrawTime <= 0.0) {
    4680            0 :                             ShowSevereError(state,
    4681            0 :                                             format("{}, named {}, design mode set to Peak Draw but needs a positive value for tank draw time",
    4682            0 :                                                    state.dataIPShortCut->cCurrentModuleObject,
    4683            0 :                                                    state.dataIPShortCut->cAlphaArgs(1)));
    4684            0 :                             ErrorsFound = true;
    4685              :                         }
    4686              :                         // constrain crazy sizes by limiting to 10 years or 8760*10
    4687            4 :                         if (state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.TankDrawTime > 87600.0) {
    4688            0 :                             ShowWarningError(state,
    4689            0 :                                              format("{}, named {},  has input with an unreasonably large Tank Draw Time, more than 10 years",
    4690            0 :                                                     state.dataIPShortCut->cCurrentModuleObject,
    4691            0 :                                                     state.dataIPShortCut->cAlphaArgs(1)));
    4692            0 :                             ErrorsFound = true;
    4693              :                         }
    4694              :                         // if both volume and demand side flow connections are autosized, must be a good NominalVolForSizingDemandSideFlow
    4695            4 :                         if ((state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).UseSidePlantLoc.loopSideNum ==
    4696            4 :                              DataPlant::LoopSideLocation::Demand) &&
    4697            0 :                             (state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).UseDesignVolFlowRateWasAutoSized)) {
    4698            0 :                             if (state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.NominalVolForSizingDemandSideFlow <= 0.0) {
    4699            0 :                                 ShowWarningError(state,
    4700            0 :                                                  format("{}, named {} needs a value for Nominal Tank Volume for Autosizing Plant Connections",
    4701            0 :                                                         state.dataIPShortCut->cCurrentModuleObject,
    4702            0 :                                                         state.dataIPShortCut->cAlphaArgs(1)));
    4703            0 :                                 ErrorsFound = true;
    4704              :                             }
    4705              :                         }
    4706            4 :                         if ((state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).SrcSidePlantLoc.loopSideNum ==
    4707            4 :                              DataPlant::LoopSideLocation::Demand) &&
    4708            0 :                             (state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).SourceDesignVolFlowRateWasAutoSized)) {
    4709            0 :                             if (state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.NominalVolForSizingDemandSideFlow <= 0.0) {
    4710            0 :                                 ShowWarningError(state,
    4711            0 :                                                  format("{}, named {} needs a value for Nominal Tank Volume for Autosizing Plant Connections",
    4712            0 :                                                         state.dataIPShortCut->cCurrentModuleObject,
    4713            0 :                                                         state.dataIPShortCut->cAlphaArgs(1)));
    4714            0 :                                 ErrorsFound = true;
    4715              :                             }
    4716              :                         }
    4717              : 
    4718            4 :                         break;
    4719              :                     }
    4720            3 :                     case SizingMode::ResidentialMin: {
    4721              :                         // it would have to have at least on bedroom and any more than 10 is crazy for this mode
    4722            3 :                         if (state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.NumberOfBedrooms < 1) {
    4723            0 :                             ShowSevereError(state,
    4724            0 :                                             format("{}, named {}, mode needs at least one bedroom",
    4725            0 :                                                    state.dataIPShortCut->cCurrentModuleObject,
    4726            0 :                                                    state.dataIPShortCut->cAlphaArgs(1)));
    4727            0 :                             ErrorsFound = true;
    4728              :                         }
    4729            3 :                         if (state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.NumberOfBedrooms > 10) {
    4730            0 :                             ShowWarningError(state,
    4731            0 :                                              format("{}, named {}, probably has too many bedrooms for the selected design mode",
    4732            0 :                                                     state.dataIPShortCut->cCurrentModuleObject,
    4733            0 :                                                     state.dataIPShortCut->cAlphaArgs(1)));
    4734              :                         }
    4735              : 
    4736            3 :                         break;
    4737              :                     }
    4738            0 :                     case SizingMode::PerPerson: {
    4739              : 
    4740            0 :                         if ((state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).VolumeWasAutoSized) &&
    4741            0 :                             (state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.TankCapacityPerPerson <= 0.0)) {
    4742            0 :                             ShowSevereError(state,
    4743            0 :                                             format("{}, named {}, PerPerson mode needs positive value input for storage capacity per person",
    4744            0 :                                                    state.dataIPShortCut->cCurrentModuleObject,
    4745            0 :                                                    state.dataIPShortCut->cAlphaArgs(1)));
    4746            0 :                             ErrorsFound = true;
    4747              :                         }
    4748              : 
    4749            0 :                         if ((state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).MaxCapacityWasAutoSized) &&
    4750            0 :                             (state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.RecoveryCapacityPerPerson <= 0.0)) {
    4751            0 :                             ShowSevereError(state,
    4752            0 :                                             format("{}, named {}, PerPerson mode needs positive value input for recovery capacity per person",
    4753            0 :                                                    state.dataIPShortCut->cCurrentModuleObject,
    4754            0 :                                                    state.dataIPShortCut->cAlphaArgs(1)));
    4755            0 :                             ErrorsFound = true;
    4756              :                         }
    4757              : 
    4758            0 :                         break;
    4759              :                     }
    4760            0 :                     case SizingMode::PerFloorArea: {
    4761            0 :                         if ((state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).VolumeWasAutoSized) &&
    4762            0 :                             (state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.TankCapacityPerArea <= 0.0)) {
    4763            0 :                             ShowSevereError(state,
    4764            0 :                                             format("{}, named {}, PerArea mode needs positive value input for storage capacity per floor area",
    4765            0 :                                                    state.dataIPShortCut->cCurrentModuleObject,
    4766            0 :                                                    state.dataIPShortCut->cAlphaArgs(1)));
    4767            0 :                             ErrorsFound = true;
    4768              :                         }
    4769            0 :                         if ((state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).MaxCapacityWasAutoSized) &&
    4770            0 :                             (state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.RecoveryCapacityPerArea <= 0.0)) {
    4771            0 :                             ShowSevereError(state,
    4772            0 :                                             format("{}, named {}, PerArea mode needs positive value input for recovery capacity per floor area",
    4773            0 :                                                    state.dataIPShortCut->cCurrentModuleObject,
    4774            0 :                                                    state.dataIPShortCut->cAlphaArgs(1)));
    4775            0 :                             ErrorsFound = true;
    4776              :                         }
    4777              : 
    4778            0 :                         break;
    4779              :                     }
    4780            0 :                     case SizingMode::PerUnit: {
    4781            0 :                         if ((state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).VolumeWasAutoSized) &&
    4782            0 :                             (state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.TankCapacityPerUnit <= 0.0)) {
    4783            0 :                             ShowSevereError(state,
    4784            0 :                                             format("{}, named {}, PerUnit mode needs positive value input for storage capacity per unit",
    4785            0 :                                                    state.dataIPShortCut->cCurrentModuleObject,
    4786            0 :                                                    state.dataIPShortCut->cAlphaArgs(1)));
    4787            0 :                             ErrorsFound = true;
    4788              :                         }
    4789            0 :                         if ((state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).VolumeWasAutoSized) &&
    4790            0 :                             (state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.NumberOfUnits <= 0.0)) {
    4791            0 :                             ShowSevereError(state,
    4792            0 :                                             format("{}, named {}, PerUnit mode needs positive value input for number of units",
    4793            0 :                                                    state.dataIPShortCut->cCurrentModuleObject,
    4794            0 :                                                    state.dataIPShortCut->cAlphaArgs(1)));
    4795            0 :                             ErrorsFound = true;
    4796              :                         }
    4797            0 :                         if ((state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).MaxCapacityWasAutoSized) &&
    4798            0 :                             (state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.RecoveryCapacityPerUnit <= 0.0)) {
    4799            0 :                             ShowSevereError(state,
    4800            0 :                                             format("{}, named {}, PerUnit mode needs positive value input for recovery capacity per unit",
    4801            0 :                                                    state.dataIPShortCut->cCurrentModuleObject,
    4802            0 :                                                    state.dataIPShortCut->cAlphaArgs(1)));
    4803            0 :                             ErrorsFound = true;
    4804              :                         }
    4805            0 :                         if ((state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).MaxCapacityWasAutoSized) &&
    4806            0 :                             (state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.NumberOfUnits <= 0.0)) {
    4807            0 :                             ShowSevereError(state,
    4808            0 :                                             format("{}, named {}, PerUnit mode needs positive value input for number of units",
    4809            0 :                                                    state.dataIPShortCut->cCurrentModuleObject,
    4810            0 :                                                    state.dataIPShortCut->cAlphaArgs(1)));
    4811            0 :                             ErrorsFound = true;
    4812              :                         }
    4813            0 :                         break;
    4814              :                     }
    4815            0 :                     case SizingMode::PerSolarColArea: {
    4816            0 :                         if ((state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).VolumeWasAutoSized) &&
    4817            0 :                             (state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.TankCapacityPerCollectorArea <= 0.0)) {
    4818            0 :                             ShowSevereError(
    4819              :                                 state,
    4820            0 :                                 format("{}, named {}, PerSolarCollectorArea mode needs positive value input for storage capacity per collector area",
    4821            0 :                                        state.dataIPShortCut->cCurrentModuleObject,
    4822            0 :                                        state.dataIPShortCut->cAlphaArgs(1)));
    4823            0 :                             ErrorsFound = true;
    4824              :                         }
    4825            0 :                         break;
    4826              :                     }
    4827            0 :                     default:
    4828            0 :                         break;
    4829              :                     }
    4830              : 
    4831              :                 } // found water heater num okay
    4832              :             } // loop over sizing objects
    4833              : 
    4834              :         } // any water heater sizing objects
    4835              : 
    4836              :         // now check that if water heater fields were autosized, that there was also a sizing object for that water heater
    4837          450 :         if (state.dataWaterThermalTanks->numWaterThermalTank > 0) {
    4838          338 :             for (int WaterThermalTankNum = 1; WaterThermalTankNum <= state.dataWaterThermalTanks->numWaterThermalTank; ++WaterThermalTankNum) {
    4839              : 
    4840          204 :                 if ((state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).VolumeWasAutoSized) &&
    4841            2 :                     (state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.DesignMode == SizingMode::Invalid)) {
    4842            0 :                     ShowWarningError(
    4843              :                         state,
    4844            0 :                         format("Water heater named {}has tank volume set to AUTOSIZE but it is missing associated WaterHeater:Sizing object",
    4845            0 :                                state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Name));
    4846            0 :                     ErrorsFound = true;
    4847              :                 }
    4848          205 :                 if ((state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).MaxCapacityWasAutoSized) &&
    4849            3 :                     (state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.DesignMode == SizingMode::Invalid)) {
    4850            0 :                     ShowWarningError(
    4851              :                         state,
    4852            0 :                         format("Water heater named {}has heater capacity set to AUTOSIZE but it is missing associated WaterHeater:Sizing object",
    4853            0 :                                state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Name));
    4854            0 :                     ErrorsFound = true;
    4855              :                 }
    4856          202 :                 if ((state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).HeightWasAutoSized) &&
    4857            0 :                     (state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.DesignMode == SizingMode::Invalid)) {
    4858            0 :                     ShowWarningError(
    4859              :                         state,
    4860            0 :                         format("Water heater named {}has tank height set to AUTOSIZE but it is missing associated WaterHeater:Sizing object",
    4861            0 :                                state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Name));
    4862            0 :                     ErrorsFound = true;
    4863              :                 }
    4864              :             }
    4865              :         }
    4866              : 
    4867              :         //    now do calls to TestCompSet for tanks, depending on nodes and heat pump water heater
    4868          450 :         if (state.dataWaterThermalTanks->numWaterThermalTank > 0) {
    4869          338 :             for (int WaterThermalTankNum = 1; WaterThermalTankNum <= state.dataWaterThermalTanks->numWaterThermalTank; ++WaterThermalTankNum) {
    4870          336 :                 if (state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).UseInletNode > 0 &&
    4871          134 :                     state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).UseOutletNode > 0) {
    4872          134 :                     if (state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).HeatPumpNum > 0) {
    4873              :                         // do nothing, Use nodes are tested for HeatPump:WaterHeater not tank
    4874              :                     } else {
    4875          372 :                         BranchNodeConnections::TestCompSet(state,
    4876          124 :                                                            state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Type,
    4877          124 :                                                            state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Name,
    4878          124 :                                                            state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).InletNodeName1,
    4879          124 :                                                            state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).OutletNodeName1,
    4880              :                                                            "Use Side Water Nodes");
    4881              :                     }
    4882              :                 }
    4883          252 :                 if (state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).SourceInletNode > 0 &&
    4884           50 :                     state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).SourceOutletNode > 0) {
    4885              : 
    4886          150 :                     BranchNodeConnections::TestCompSet(state,
    4887           50 :                                                        state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Type,
    4888           50 :                                                        state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Name,
    4889           50 :                                                        state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).InletNodeName2,
    4890           50 :                                                        state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).OutletNodeName2,
    4891              :                                                        "Source Side Water Nodes");
    4892              :                 }
    4893              :             }
    4894              :         }
    4895              : 
    4896          450 :         if (state.dataWaterThermalTanks->numWaterThermalTank > 0) {
    4897          338 :             for (int WaterThermalTankNum = 1; WaterThermalTankNum <= state.dataWaterThermalTanks->numWaterThermalTank; ++WaterThermalTankNum) {
    4898              : 
    4899          202 :                 state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).setupZoneInternalGains(state);
    4900              : 
    4901              :             } // WaterThermalTankNum
    4902              :         }
    4903              :     } // get input flag
    4904              : 
    4905          450 :     return ErrorsFound;
    4906              : }
    4907              : 
    4908          201 : void WaterThermalTankData::setupOutputVars(EnergyPlusData &state)
    4909              : {
    4910          201 :     if ((this->WaterThermalTankType == DataPlant::PlantEquipmentType::ChilledWaterTankMixed) ||
    4911          197 :         (this->WaterThermalTankType == DataPlant::PlantEquipmentType::ChilledWaterTankStratified)) {
    4912            6 :         this->setupChilledWaterTankOutputVars(state);
    4913              :     } else {
    4914              :         // moving setupWaterHeaterOutputVars to here causes big table diffs...
    4915          195 :         this->setupWaterHeaterOutputVars(state);
    4916              :     }
    4917              :     // moving setupZoneInternalGains to here causes math and table diffs...
    4918              :     // this->setupZoneInternalGains();
    4919          201 : }
    4920              : 
    4921            6 : void WaterThermalTankData::setupChilledWaterTankOutputVars(EnergyPlusData &state)
    4922              : {
    4923              : 
    4924              :     // CurrentModuleObject='ThermalStorage:ChilledWater:Mixed/ThermalStorage:ChilledWater:Stratified'
    4925           12 :     SetupOutputVariable(state,
    4926              :                         "Chilled Water Thermal Storage Tank Temperature",
    4927              :                         Constant::Units::C,
    4928            6 :                         this->TankTempAvg,
    4929              :                         OutputProcessor::TimeStepType::System,
    4930              :                         OutputProcessor::StoreType::Average,
    4931            6 :                         this->Name);
    4932              : 
    4933           12 :     SetupOutputVariable(state,
    4934              :                         "Chilled Water Thermal Storage Final Tank Temperature",
    4935              :                         Constant::Units::C,
    4936            6 :                         this->TankTemp,
    4937              :                         OutputProcessor::TimeStepType::System,
    4938              :                         OutputProcessor::StoreType::Average,
    4939            6 :                         this->Name);
    4940              : 
    4941           12 :     SetupOutputVariable(state,
    4942              :                         "Chilled Water Thermal Storage Tank Heat Gain Rate",
    4943              :                         Constant::Units::W,
    4944            6 :                         this->LossRate,
    4945              :                         OutputProcessor::TimeStepType::System,
    4946              :                         OutputProcessor::StoreType::Average,
    4947            6 :                         this->Name);
    4948           12 :     SetupOutputVariable(state,
    4949              :                         "Chilled Water Thermal Storage Tank Heat Gain Energy",
    4950              :                         Constant::Units::J,
    4951            6 :                         this->LossEnergy,
    4952              :                         OutputProcessor::TimeStepType::System,
    4953              :                         OutputProcessor::StoreType::Sum,
    4954            6 :                         this->Name);
    4955              : 
    4956           12 :     SetupOutputVariable(state,
    4957              :                         "Chilled Water Thermal Storage Use Side Mass Flow Rate",
    4958              :                         Constant::Units::kg_s,
    4959            6 :                         this->UseMassFlowRate,
    4960              :                         OutputProcessor::TimeStepType::System,
    4961              :                         OutputProcessor::StoreType::Average,
    4962            6 :                         this->Name);
    4963              : 
    4964           12 :     SetupOutputVariable(state,
    4965              :                         "Chilled Water Thermal Storage Use Side Inlet Temperature",
    4966              :                         Constant::Units::C,
    4967            6 :                         this->UseInletTemp,
    4968              :                         OutputProcessor::TimeStepType::System,
    4969              :                         OutputProcessor::StoreType::Average,
    4970            6 :                         this->Name);
    4971              : 
    4972           12 :     SetupOutputVariable(state,
    4973              :                         "Chilled Water Thermal Storage Use Side Outlet Temperature",
    4974              :                         Constant::Units::C,
    4975            6 :                         this->UseOutletTemp,
    4976              :                         OutputProcessor::TimeStepType::System,
    4977              :                         OutputProcessor::StoreType::Average,
    4978            6 :                         this->Name);
    4979              : 
    4980           12 :     SetupOutputVariable(state,
    4981              :                         "Chilled Water Thermal Storage Use Side Heat Transfer Rate",
    4982              :                         Constant::Units::W,
    4983            6 :                         this->UseRate,
    4984              :                         OutputProcessor::TimeStepType::System,
    4985              :                         OutputProcessor::StoreType::Average,
    4986            6 :                         this->Name);
    4987           12 :     SetupOutputVariable(state,
    4988              :                         "Chilled Water Thermal Storage Use Side Heat Transfer Energy",
    4989              :                         Constant::Units::J,
    4990            6 :                         this->UseEnergy,
    4991              :                         OutputProcessor::TimeStepType::System,
    4992              :                         OutputProcessor::StoreType::Sum,
    4993            6 :                         this->Name);
    4994              : 
    4995           12 :     SetupOutputVariable(state,
    4996              :                         "Chilled Water Thermal Storage Source Side Mass Flow Rate",
    4997              :                         Constant::Units::kg_s,
    4998            6 :                         this->SourceMassFlowRate,
    4999              :                         OutputProcessor::TimeStepType::System,
    5000              :                         OutputProcessor::StoreType::Average,
    5001            6 :                         this->Name);
    5002              : 
    5003           12 :     SetupOutputVariable(state,
    5004              :                         "Chilled Water Thermal Storage Source Side Inlet Temperature",
    5005              :                         Constant::Units::C,
    5006            6 :                         this->SourceInletTemp,
    5007              :                         OutputProcessor::TimeStepType::System,
    5008              :                         OutputProcessor::StoreType::Average,
    5009            6 :                         this->Name);
    5010              : 
    5011           12 :     SetupOutputVariable(state,
    5012              :                         "Chilled Water Thermal Storage Source Side Outlet Temperature",
    5013              :                         Constant::Units::C,
    5014            6 :                         this->SourceOutletTemp,
    5015              :                         OutputProcessor::TimeStepType::System,
    5016              :                         OutputProcessor::StoreType::Average,
    5017            6 :                         this->Name);
    5018              : 
    5019           12 :     SetupOutputVariable(state,
    5020              :                         "Chilled Water Thermal Storage Source Side Heat Transfer Rate",
    5021              :                         Constant::Units::W,
    5022            6 :                         this->SourceRate,
    5023              :                         OutputProcessor::TimeStepType::System,
    5024              :                         OutputProcessor::StoreType::Average,
    5025            6 :                         this->Name);
    5026           12 :     SetupOutputVariable(state,
    5027              :                         "Chilled Water Thermal Storage Source Side Heat Transfer Energy",
    5028              :                         Constant::Units::J,
    5029            6 :                         this->SourceEnergy,
    5030              :                         OutputProcessor::TimeStepType::System,
    5031              :                         OutputProcessor::StoreType::Sum,
    5032            6 :                         this->Name);
    5033              : 
    5034            6 :     if (this->WaterThermalTankType == DataPlant::PlantEquipmentType::ChilledWaterTankStratified) {
    5035              : 
    5036           14 :         for (int NodeNum = 1; NodeNum <= this->Nodes; ++NodeNum) {
    5037           36 :             SetupOutputVariable(state,
    5038           24 :                                 format("Chilled Water Thermal Storage Temperature Node {}", NodeNum),
    5039              :                                 Constant::Units::C,
    5040           12 :                                 this->Node(NodeNum).TempAvg,
    5041              :                                 OutputProcessor::TimeStepType::System,
    5042              :                                 OutputProcessor::StoreType::Average,
    5043           12 :                                 this->Name);
    5044              :         }
    5045              : 
    5046           14 :         for (int NodeNum = 1; NodeNum <= this->Nodes; ++NodeNum) {
    5047           36 :             SetupOutputVariable(state,
    5048           24 :                                 format("Chilled Water Thermal Storage Final Temperature Node {}", NodeNum),
    5049              :                                 Constant::Units::C,
    5050           12 :                                 this->Node(NodeNum).Temp,
    5051              :                                 OutputProcessor::TimeStepType::System,
    5052              :                                 OutputProcessor::StoreType::Average,
    5053           12 :                                 this->Name);
    5054              :         }
    5055              :     }
    5056              : 
    5057            6 :     if (this->WaterThermalTankType == DataPlant::PlantEquipmentType::ChilledWaterTankStratified) {
    5058              : 
    5059           14 :         for (int NodeNum = 1; NodeNum <= this->Nodes; ++NodeNum) {
    5060              :             static constexpr std::string_view Format_724("Chilled Water Tank Stratified Node Information,{},{:.4T},{:.4T},{:.4T},{},{}\n");
    5061              : 
    5062           12 :             print(state.files.eio,
    5063              :                   Format_724,
    5064              :                   NodeNum,
    5065           12 :                   this->Node(NodeNum).Height,
    5066           12 :                   this->Node(NodeNum).Volume,
    5067           12 :                   this->Node(NodeNum).OffCycLossCoeff,
    5068           12 :                   this->Node(NodeNum).Inlets,
    5069           12 :                   this->Node(NodeNum).Outlets);
    5070              :         }
    5071              :     }
    5072            6 : }
    5073              : 
    5074          202 : void WaterThermalTankData::setupZoneInternalGains(EnergyPlusData &state)
    5075              : {
    5076              :     // set up internal gains if tank is in a thermal zone
    5077          202 :     if (this->AmbientTempZone > 0) {
    5078           83 :         switch (this->WaterThermalTankType) {
    5079           72 :         case DataPlant::PlantEquipmentType::WtrHeaterMixed: {
    5080           72 :             SetupZoneInternalGain(state, this->AmbientTempZone, this->Name, DataHeatBalance::IntGainType::WaterHeaterMixed, &this->AmbientZoneGain);
    5081           72 :             break;
    5082              :         }
    5083            6 :         case DataPlant::PlantEquipmentType::WtrHeaterStratified: {
    5084            6 :             SetupZoneInternalGain(
    5085              :                 state, this->AmbientTempZone, this->Name, DataHeatBalance::IntGainType::WaterHeaterStratified, &this->AmbientZoneGain);
    5086            6 :             break;
    5087              :         }
    5088            3 :         case DataPlant::PlantEquipmentType::ChilledWaterTankMixed: {
    5089            3 :             SetupZoneInternalGain(
    5090              :                 state, this->AmbientTempZone, this->Name, DataHeatBalance::IntGainType::ThermalStorageChilledWaterMixed, &this->AmbientZoneGain);
    5091            3 :             break;
    5092              :         }
    5093            2 :         case DataPlant::PlantEquipmentType::ChilledWaterTankStratified: {
    5094            2 :             SetupZoneInternalGain(
    5095              :                 state, this->AmbientTempZone, this->Name, DataHeatBalance::IntGainType::ThermalStorageChilledWaterStratified, &this->AmbientZoneGain);
    5096            2 :             break;
    5097              :         }
    5098            0 :         default:
    5099            0 :             break;
    5100              :         }
    5101              :     }
    5102          202 : }
    5103              : 
    5104          195 : void WaterThermalTankData::setupWaterHeaterOutputVars(EnergyPlusData &state)
    5105              : {
    5106              : 
    5107              :     // Setup report variables for WaterHeater:Mixed
    5108              :     // CurrentModuleObject='WaterHeater:Mixed'
    5109          390 :     SetupOutputVariable(state,
    5110              :                         "Water Heater Tank Temperature",
    5111              :                         Constant::Units::C,
    5112          195 :                         this->TankTempAvg,
    5113              :                         OutputProcessor::TimeStepType::System,
    5114              :                         OutputProcessor::StoreType::Average,
    5115          195 :                         this->Name);
    5116              : 
    5117          390 :     SetupOutputVariable(state,
    5118              :                         "Water Heater Final Tank Temperature",
    5119              :                         Constant::Units::C,
    5120          195 :                         this->TankTemp,
    5121              :                         OutputProcessor::TimeStepType::System,
    5122              :                         OutputProcessor::StoreType::Average,
    5123          195 :                         this->Name);
    5124              : 
    5125          390 :     SetupOutputVariable(state,
    5126              :                         "Water Heater Heat Loss Rate",
    5127              :                         Constant::Units::W,
    5128          195 :                         this->LossRate,
    5129              :                         OutputProcessor::TimeStepType::System,
    5130              :                         OutputProcessor::StoreType::Average,
    5131          195 :                         this->Name);
    5132          390 :     SetupOutputVariable(state,
    5133              :                         "Water Heater Heat Loss Energy",
    5134              :                         Constant::Units::J,
    5135          195 :                         this->LossEnergy,
    5136              :                         OutputProcessor::TimeStepType::System,
    5137              :                         OutputProcessor::StoreType::Sum,
    5138          195 :                         this->Name);
    5139              : 
    5140          390 :     SetupOutputVariable(state,
    5141              :                         "Water Heater Use Side Mass Flow Rate",
    5142              :                         Constant::Units::kg_s,
    5143          195 :                         this->UseMassFlowRate,
    5144              :                         OutputProcessor::TimeStepType::System,
    5145              :                         OutputProcessor::StoreType::Average,
    5146          195 :                         this->Name);
    5147              : 
    5148          390 :     SetupOutputVariable(state,
    5149              :                         "Water Heater Use Side Inlet Temperature",
    5150              :                         Constant::Units::C,
    5151          195 :                         this->UseInletTemp,
    5152              :                         OutputProcessor::TimeStepType::System,
    5153              :                         OutputProcessor::StoreType::Average,
    5154          195 :                         this->Name);
    5155              : 
    5156          390 :     SetupOutputVariable(state,
    5157              :                         "Water Heater Use Side Outlet Temperature",
    5158              :                         Constant::Units::C,
    5159          195 :                         this->UseOutletTemp,
    5160              :                         OutputProcessor::TimeStepType::System,
    5161              :                         OutputProcessor::StoreType::Average,
    5162          195 :                         this->Name);
    5163              : 
    5164          390 :     SetupOutputVariable(state,
    5165              :                         "Water Heater Use Side Heat Transfer Rate",
    5166              :                         Constant::Units::W,
    5167          195 :                         this->UseRate,
    5168              :                         OutputProcessor::TimeStepType::System,
    5169              :                         OutputProcessor::StoreType::Average,
    5170          195 :                         this->Name);
    5171          390 :     SetupOutputVariable(state,
    5172              :                         "Water Heater Use Side Heat Transfer Energy",
    5173              :                         Constant::Units::J,
    5174          195 :                         this->UseEnergy,
    5175              :                         OutputProcessor::TimeStepType::System,
    5176              :                         OutputProcessor::StoreType::Sum,
    5177          195 :                         this->Name);
    5178              : 
    5179          390 :     SetupOutputVariable(state,
    5180              :                         "Water Heater Source Side Mass Flow Rate",
    5181              :                         Constant::Units::kg_s,
    5182          195 :                         this->SourceMassFlowRate,
    5183              :                         OutputProcessor::TimeStepType::System,
    5184              :                         OutputProcessor::StoreType::Average,
    5185          195 :                         this->Name);
    5186              : 
    5187          390 :     SetupOutputVariable(state,
    5188              :                         "Water Heater Source Side Inlet Temperature",
    5189              :                         Constant::Units::C,
    5190          195 :                         this->SourceInletTemp,
    5191              :                         OutputProcessor::TimeStepType::System,
    5192              :                         OutputProcessor::StoreType::Average,
    5193          195 :                         this->Name);
    5194              : 
    5195          390 :     SetupOutputVariable(state,
    5196              :                         "Water Heater Source Side Outlet Temperature",
    5197              :                         Constant::Units::C,
    5198          195 :                         this->SourceOutletTemp,
    5199              :                         OutputProcessor::TimeStepType::System,
    5200              :                         OutputProcessor::StoreType::Average,
    5201          195 :                         this->Name);
    5202              : 
    5203          390 :     SetupOutputVariable(state,
    5204              :                         "Water Heater Source Side Heat Transfer Rate",
    5205              :                         Constant::Units::W,
    5206          195 :                         this->SourceRate,
    5207              :                         OutputProcessor::TimeStepType::System,
    5208              :                         OutputProcessor::StoreType::Average,
    5209          195 :                         this->Name);
    5210          390 :     SetupOutputVariable(state,
    5211              :                         "Water Heater Source Side Heat Transfer Energy",
    5212              :                         Constant::Units::J,
    5213          195 :                         this->SourceEnergy,
    5214              :                         OutputProcessor::TimeStepType::System,
    5215              :                         OutputProcessor::StoreType::Sum,
    5216          195 :                         this->Name,
    5217              :                         Constant::eResource::PlantLoopHeatingDemand,
    5218              :                         OutputProcessor::Group::Plant,
    5219              :                         OutputProcessor::EndUseCat::WaterSystem, // DHW
    5220              :                         this->EndUseSubcategoryName);
    5221              : 
    5222          390 :     SetupOutputVariable(state,
    5223              :                         "Water Heater Off Cycle Parasitic Tank Heat Transfer Rate",
    5224              :                         Constant::Units::W,
    5225          195 :                         this->OffCycParaRateToTank,
    5226              :                         OutputProcessor::TimeStepType::System,
    5227              :                         OutputProcessor::StoreType::Average,
    5228          195 :                         this->Name);
    5229          390 :     SetupOutputVariable(state,
    5230              :                         "Water Heater Off Cycle Parasitic Tank Heat Transfer Energy",
    5231              :                         Constant::Units::J,
    5232          195 :                         this->OffCycParaEnergyToTank,
    5233              :                         OutputProcessor::TimeStepType::System,
    5234              :                         OutputProcessor::StoreType::Sum,
    5235          195 :                         this->Name);
    5236              : 
    5237          390 :     SetupOutputVariable(state,
    5238              :                         "Water Heater On Cycle Parasitic Tank Heat Transfer Rate",
    5239              :                         Constant::Units::W,
    5240          195 :                         this->OnCycParaRateToTank,
    5241              :                         OutputProcessor::TimeStepType::System,
    5242              :                         OutputProcessor::StoreType::Average,
    5243          195 :                         this->Name);
    5244          390 :     SetupOutputVariable(state,
    5245              :                         "Water Heater On Cycle Parasitic Tank Heat Transfer Energy",
    5246              :                         Constant::Units::J,
    5247          195 :                         this->OnCycParaEnergyToTank,
    5248              :                         OutputProcessor::TimeStepType::System,
    5249              :                         OutputProcessor::StoreType::Sum,
    5250          195 :                         this->Name);
    5251              : 
    5252          390 :     SetupOutputVariable(state,
    5253              :                         "Water Heater Total Demand Heat Transfer Rate",
    5254              :                         Constant::Units::W,
    5255          195 :                         this->TotalDemandRate,
    5256              :                         OutputProcessor::TimeStepType::System,
    5257              :                         OutputProcessor::StoreType::Average,
    5258          195 :                         this->Name);
    5259          390 :     SetupOutputVariable(state,
    5260              :                         "Water Heater Total Demand Heat Transfer Energy",
    5261              :                         Constant::Units::J,
    5262          195 :                         this->TotalDemandEnergy,
    5263              :                         OutputProcessor::TimeStepType::System,
    5264              :                         OutputProcessor::StoreType::Sum,
    5265          195 :                         this->Name);
    5266              : 
    5267          390 :     SetupOutputVariable(state,
    5268              :                         "Water Heater Heating Rate",
    5269              :                         Constant::Units::W,
    5270          195 :                         this->HeaterRate,
    5271              :                         OutputProcessor::TimeStepType::System,
    5272              :                         OutputProcessor::StoreType::Average,
    5273          195 :                         this->Name);
    5274          390 :     SetupOutputVariable(state,
    5275              :                         "Water Heater Heating Energy",
    5276              :                         Constant::Units::J,
    5277          195 :                         this->HeaterEnergy,
    5278              :                         OutputProcessor::TimeStepType::System,
    5279              :                         OutputProcessor::StoreType::Sum,
    5280          195 :                         this->Name);
    5281              : 
    5282          390 :     SetupOutputVariable(state,
    5283              :                         "Water Heater Unmet Demand Heat Transfer Rate",
    5284              :                         Constant::Units::W,
    5285          195 :                         this->UnmetRate,
    5286              :                         OutputProcessor::TimeStepType::System,
    5287              :                         OutputProcessor::StoreType::Average,
    5288          195 :                         this->Name);
    5289          390 :     SetupOutputVariable(state,
    5290              :                         "Water Heater Unmet Demand Heat Transfer Energy",
    5291              :                         Constant::Units::J,
    5292          195 :                         this->UnmetEnergy,
    5293              :                         OutputProcessor::TimeStepType::System,
    5294              :                         OutputProcessor::StoreType::Sum,
    5295          195 :                         this->Name);
    5296              : 
    5297          390 :     SetupOutputVariable(state,
    5298              :                         "Water Heater Venting Heat Transfer Rate",
    5299              :                         Constant::Units::W,
    5300          195 :                         this->VentRate,
    5301              :                         OutputProcessor::TimeStepType::System,
    5302              :                         OutputProcessor::StoreType::Average,
    5303          195 :                         this->Name);
    5304          390 :     SetupOutputVariable(state,
    5305              :                         "Water Heater Venting Heat Transfer Energy",
    5306              :                         Constant::Units::J,
    5307          195 :                         this->VentEnergy,
    5308              :                         OutputProcessor::TimeStepType::System,
    5309              :                         OutputProcessor::StoreType::Sum,
    5310          195 :                         this->Name);
    5311              : 
    5312          390 :     SetupOutputVariable(state,
    5313              :                         "Water Heater Net Heat Transfer Rate",
    5314              :                         Constant::Units::W,
    5315          195 :                         this->NetHeatTransferRate,
    5316              :                         OutputProcessor::TimeStepType::System,
    5317              :                         OutputProcessor::StoreType::Average,
    5318          195 :                         this->Name);
    5319          390 :     SetupOutputVariable(state,
    5320              :                         "Water Heater Net Heat Transfer Energy",
    5321              :                         Constant::Units::J,
    5322          195 :                         this->NetHeatTransferEnergy,
    5323              :                         OutputProcessor::TimeStepType::System,
    5324              :                         OutputProcessor::StoreType::Sum,
    5325          195 :                         this->Name);
    5326              : 
    5327          195 :     SetupOutputVariable(state,
    5328              :                         "Water Heater Cycle On Count",
    5329              :                         Constant::Units::None,
    5330          195 :                         this->CycleOnCount,
    5331              :                         OutputProcessor::TimeStepType::System,
    5332              :                         OutputProcessor::StoreType::Sum,
    5333          195 :                         this->Name);
    5334          390 :     SetupOutputVariable(state,
    5335              :                         "Water Heater Runtime Fraction",
    5336              :                         Constant::Units::None,
    5337          195 :                         this->RuntimeFraction,
    5338              :                         OutputProcessor::TimeStepType::System,
    5339              :                         OutputProcessor::StoreType::Average,
    5340          195 :                         this->Name);
    5341          390 :     SetupOutputVariable(state,
    5342              :                         "Water Heater Part Load Ratio",
    5343              :                         Constant::Units::None,
    5344          195 :                         this->PartLoadRatio,
    5345              :                         OutputProcessor::TimeStepType::System,
    5346              :                         OutputProcessor::StoreType::Average,
    5347          195 :                         this->Name);
    5348              : 
    5349          585 :     SetupOutputVariable(state,
    5350          390 :                         format("Water Heater {} Rate", Constant::eFuelNames[static_cast<int>(this->FuelType)]),
    5351              :                         Constant::Units::W,
    5352          195 :                         this->FuelRate,
    5353              :                         OutputProcessor::TimeStepType::System,
    5354              :                         OutputProcessor::StoreType::Average,
    5355          195 :                         this->Name);
    5356          585 :     SetupOutputVariable(state,
    5357          390 :                         format("Water Heater {} Energy", Constant::eFuelNames[static_cast<int>(this->FuelType)]),
    5358              :                         Constant::Units::J,
    5359          195 :                         this->FuelEnergy,
    5360              :                         OutputProcessor::TimeStepType::System,
    5361              :                         OutputProcessor::StoreType::Sum,
    5362          195 :                         this->Name,
    5363          195 :                         Constant::eFuel2eResource[(int)this->FuelType],
    5364              :                         OutputProcessor::Group::Plant,
    5365              :                         OutputProcessor::EndUseCat::WaterSystem, // DHW
    5366              :                         this->EndUseSubcategoryName);
    5367              : 
    5368          585 :     SetupOutputVariable(state,
    5369          390 :                         format("Water Heater Off Cycle Parasitic {} Rate", Constant::eFuelNames[static_cast<int>(this->OffCycParaFuelType)]),
    5370              :                         Constant::Units::W,
    5371          195 :                         this->OffCycParaFuelRate,
    5372              :                         OutputProcessor::TimeStepType::System,
    5373              :                         OutputProcessor::StoreType::Average,
    5374          195 :                         this->Name);
    5375          585 :     SetupOutputVariable(state,
    5376          390 :                         format("Water Heater Off Cycle Parasitic {} Energy", Constant::eFuelNames[static_cast<int>(this->OffCycParaFuelType)]),
    5377              :                         Constant::Units::J,
    5378          195 :                         this->OffCycParaFuelEnergy,
    5379              :                         OutputProcessor::TimeStepType::System,
    5380              :                         OutputProcessor::StoreType::Sum,
    5381          195 :                         this->Name,
    5382          195 :                         Constant::eFuel2eResource[(int)this->OffCycParaFuelType],
    5383              :                         OutputProcessor::Group::Plant,
    5384              :                         OutputProcessor::EndUseCat::WaterSystem, // DHW
    5385              :                         this->EndUseSubcategoryName);
    5386              : 
    5387          585 :     SetupOutputVariable(state,
    5388          390 :                         format("Water Heater On Cycle Parasitic {} Rate", Constant::eFuelNames[static_cast<int>(this->OnCycParaFuelType)]),
    5389              :                         Constant::Units::W,
    5390          195 :                         this->OnCycParaFuelRate,
    5391              :                         OutputProcessor::TimeStepType::System,
    5392              :                         OutputProcessor::StoreType::Average,
    5393          195 :                         this->Name);
    5394          585 :     SetupOutputVariable(state,
    5395          390 :                         format("Water Heater On Cycle Parasitic {} Energy", Constant::eFuelNames[static_cast<int>(this->OnCycParaFuelType)]),
    5396              :                         Constant::Units::J,
    5397          195 :                         this->OnCycParaFuelEnergy,
    5398              :                         OutputProcessor::TimeStepType::System,
    5399              :                         OutputProcessor::StoreType::Sum,
    5400          195 :                         this->Name,
    5401          195 :                         Constant::eFuel2eResource[(int)this->OnCycParaFuelType],
    5402              :                         OutputProcessor::Group::Plant,
    5403              :                         OutputProcessor::EndUseCat::WaterSystem, // DHW
    5404              :                         this->EndUseSubcategoryName);
    5405              : 
    5406          390 :     SetupOutputVariable(state,
    5407              :                         "Water Heater Water Volume Flow Rate",
    5408              :                         Constant::Units::m3_s,
    5409          195 :                         this->VolFlowRate,
    5410              :                         OutputProcessor::TimeStepType::System,
    5411              :                         OutputProcessor::StoreType::Average,
    5412          195 :                         this->Name);
    5413          390 :     SetupOutputVariable(state,
    5414              :                         "Water Heater Water Volume",
    5415              :                         Constant::Units::m3,
    5416          195 :                         this->VolumeConsumed,
    5417              :                         OutputProcessor::TimeStepType::System,
    5418              :                         OutputProcessor::StoreType::Sum,
    5419          195 :                         this->Name,
    5420              :                         Constant::eResource::Water,
    5421              :                         OutputProcessor::Group::Plant,
    5422              :                         OutputProcessor::EndUseCat::WaterSystem, // DHW
    5423              :                         this->EndUseSubcategoryName);
    5424          390 :     SetupOutputVariable(state,
    5425              :                         "Water Heater Mains Water Volume",
    5426              :                         Constant::Units::m3,
    5427          195 :                         this->VolumeConsumed,
    5428              :                         OutputProcessor::TimeStepType::System,
    5429              :                         OutputProcessor::StoreType::Sum,
    5430          195 :                         this->Name,
    5431              :                         Constant::eResource::MainsWater,
    5432              :                         OutputProcessor::Group::Plant,
    5433              :                         OutputProcessor::EndUseCat::WaterSystem, // DHW
    5434              :                         this->EndUseSubcategoryName);
    5435              : 
    5436          195 :     if (this->HeatPumpNum > 0) {
    5437              :         // CurrentModuleObject='WaterHeater:HeatPump:PumpedCondenser'
    5438           23 :         HeatPumpWaterHeaterData &HPWH = state.dataWaterThermalTanks->HPWaterHeater(this->HeatPumpNum);
    5439           46 :         SetupOutputVariable(state,
    5440              :                             "Water Heater Compressor Part Load Ratio",
    5441              :                             Constant::Units::None,
    5442           23 :                             HPWH.HeatingPLR,
    5443              :                             OutputProcessor::TimeStepType::System,
    5444              :                             OutputProcessor::StoreType::Average,
    5445           23 :                             HPWH.Name);
    5446           46 :         SetupOutputVariable(state,
    5447              :                             "Water Heater Off Cycle Ancillary Electricity Rate",
    5448              :                             Constant::Units::W,
    5449           23 :                             HPWH.OffCycParaFuelRate,
    5450              :                             OutputProcessor::TimeStepType::System,
    5451              :                             OutputProcessor::StoreType::Average,
    5452           23 :                             HPWH.Name);
    5453           46 :         SetupOutputVariable(state,
    5454              :                             "Water Heater Off Cycle Ancillary Electricity Energy",
    5455              :                             Constant::Units::J,
    5456           23 :                             HPWH.OffCycParaFuelEnergy,
    5457              :                             OutputProcessor::TimeStepType::System,
    5458              :                             OutputProcessor::StoreType::Sum,
    5459           23 :                             HPWH.Name,
    5460              :                             Constant::eResource::Electricity,
    5461              :                             OutputProcessor::Group::Plant,
    5462              :                             OutputProcessor::EndUseCat::WaterSystem, // DHW
    5463              :                             "Water Heater Parasitic");
    5464           46 :         SetupOutputVariable(state,
    5465              :                             "Water Heater On Cycle Ancillary Electricity Rate",
    5466              :                             Constant::Units::W,
    5467           23 :                             HPWH.OnCycParaFuelRate,
    5468              :                             OutputProcessor::TimeStepType::System,
    5469              :                             OutputProcessor::StoreType::Average,
    5470           23 :                             HPWH.Name);
    5471           46 :         SetupOutputVariable(state,
    5472              :                             "Water Heater On Cycle Ancillary Electricity Energy",
    5473              :                             Constant::Units::J,
    5474           23 :                             HPWH.OnCycParaFuelEnergy,
    5475              :                             OutputProcessor::TimeStepType::System,
    5476              :                             OutputProcessor::StoreType::Sum,
    5477           23 :                             HPWH.Name,
    5478              :                             Constant::eResource::Electricity,
    5479              :                             OutputProcessor::Group::Plant,
    5480              :                             OutputProcessor::EndUseCat::WaterSystem, // DHW
    5481              :                             "Water Heater Parasitic");
    5482           46 :         SetupOutputVariable(state,
    5483              :                             "Water Heater Heat Pump Control Tank Temperature",
    5484              :                             Constant::Units::C,
    5485           23 :                             HPWH.ControlTempAvg,
    5486              :                             OutputProcessor::TimeStepType::System,
    5487              :                             OutputProcessor::StoreType::Average,
    5488           23 :                             HPWH.Name);
    5489           46 :         SetupOutputVariable(state,
    5490              :                             "Water Heater Heat Pump Control Tank Final Temperature",
    5491              :                             Constant::Units::C,
    5492           23 :                             HPWH.ControlTempFinal,
    5493              :                             OutputProcessor::TimeStepType::System,
    5494              :                             OutputProcessor::StoreType::Average,
    5495           23 :                             HPWH.Name);
    5496              :     }
    5497              : 
    5498          195 :     if (this->DesuperheaterNum > 0) {
    5499              :         // CurrentModuleObject='Coil:WaterHeating:Desuperheater'
    5500           12 :         SetupOutputVariable(state,
    5501              :                             "Water Heater Part Load Ratio",
    5502              :                             Constant::Units::None,
    5503            6 :                             state.dataWaterThermalTanks->WaterHeaterDesuperheater(this->DesuperheaterNum).DesuperheaterPLR,
    5504              :                             OutputProcessor::TimeStepType::System,
    5505              :                             OutputProcessor::StoreType::Average,
    5506            6 :                             state.dataWaterThermalTanks->WaterHeaterDesuperheater(this->DesuperheaterNum).Name);
    5507           12 :         SetupOutputVariable(state,
    5508              :                             "Water Heater On Cycle Parasitic Electricity Rate",
    5509              :                             Constant::Units::W,
    5510            6 :                             state.dataWaterThermalTanks->WaterHeaterDesuperheater(this->DesuperheaterNum).OnCycParaFuelRate,
    5511              :                             OutputProcessor::TimeStepType::System,
    5512              :                             OutputProcessor::StoreType::Average,
    5513            6 :                             state.dataWaterThermalTanks->WaterHeaterDesuperheater(this->DesuperheaterNum).Name);
    5514           12 :         SetupOutputVariable(state,
    5515              :                             "Water Heater On Cycle Parasitic Electricity Energy",
    5516              :                             Constant::Units::J,
    5517            6 :                             state.dataWaterThermalTanks->WaterHeaterDesuperheater(this->DesuperheaterNum).OnCycParaFuelEnergy,
    5518              :                             OutputProcessor::TimeStepType::System,
    5519              :                             OutputProcessor::StoreType::Sum,
    5520            6 :                             state.dataWaterThermalTanks->WaterHeaterDesuperheater(this->DesuperheaterNum).Name,
    5521              :                             Constant::eResource::Electricity,
    5522              :                             OutputProcessor::Group::Plant,
    5523              :                             OutputProcessor::EndUseCat::WaterSystem, // DHW
    5524              :                             "Water Heater Parasitic");
    5525           12 :         SetupOutputVariable(state,
    5526              :                             "Water Heater Off Cycle Parasitic Electricity Rate",
    5527              :                             Constant::Units::W,
    5528            6 :                             state.dataWaterThermalTanks->WaterHeaterDesuperheater(this->DesuperheaterNum).OffCycParaFuelRate,
    5529              :                             OutputProcessor::TimeStepType::System,
    5530              :                             OutputProcessor::StoreType::Average,
    5531            6 :                             state.dataWaterThermalTanks->WaterHeaterDesuperheater(this->DesuperheaterNum).Name);
    5532           12 :         SetupOutputVariable(state,
    5533              :                             "Water Heater Off Cycle Parasitic Electricity Energy",
    5534              :                             Constant::Units::J,
    5535            6 :                             state.dataWaterThermalTanks->WaterHeaterDesuperheater(this->DesuperheaterNum).OffCycParaFuelEnergy,
    5536              :                             OutputProcessor::TimeStepType::System,
    5537              :                             OutputProcessor::StoreType::Sum,
    5538            6 :                             state.dataWaterThermalTanks->WaterHeaterDesuperheater(this->DesuperheaterNum).Name,
    5539              :                             Constant::eResource::Electricity,
    5540              :                             OutputProcessor::Group::Plant,
    5541              :                             OutputProcessor::EndUseCat::WaterSystem, // DHW
    5542              :                             "Water Heater Parasitic");
    5543           12 :         SetupOutputVariable(state,
    5544              :                             "Water Heater Heat Reclaim Efficiency Modifier Multiplier",
    5545              :                             Constant::Units::None,
    5546            6 :                             state.dataWaterThermalTanks->WaterHeaterDesuperheater(this->DesuperheaterNum).HEffFTempOutput,
    5547              :                             OutputProcessor::TimeStepType::System,
    5548              :                             OutputProcessor::StoreType::Average,
    5549            6 :                             state.dataWaterThermalTanks->WaterHeaterDesuperheater(this->DesuperheaterNum).Name);
    5550           12 :         SetupOutputVariable(state,
    5551              :                             "Water Heater Pump Electricity Rate",
    5552              :                             Constant::Units::W,
    5553            6 :                             state.dataWaterThermalTanks->WaterHeaterDesuperheater(this->DesuperheaterNum).PumpPower,
    5554              :                             OutputProcessor::TimeStepType::System,
    5555              :                             OutputProcessor::StoreType::Average,
    5556            6 :                             state.dataWaterThermalTanks->WaterHeaterDesuperheater(this->DesuperheaterNum).Name);
    5557           12 :         SetupOutputVariable(state,
    5558              :                             "Water Heater Pump Electricity Energy",
    5559              :                             Constant::Units::J,
    5560            6 :                             state.dataWaterThermalTanks->WaterHeaterDesuperheater(this->DesuperheaterNum).PumpEnergy,
    5561              :                             OutputProcessor::TimeStepType::System,
    5562              :                             OutputProcessor::StoreType::Sum,
    5563            6 :                             state.dataWaterThermalTanks->WaterHeaterDesuperheater(this->DesuperheaterNum).Name,
    5564              :                             Constant::eResource::Electricity,
    5565              :                             OutputProcessor::Group::Plant,
    5566              :                             OutputProcessor::EndUseCat::WaterSystem, // DHW
    5567              :                             "Desuperheater Pump");
    5568           12 :         SetupOutputVariable(state,
    5569              :                             "Water Heater Heating Rate",
    5570              :                             Constant::Units::W,
    5571            6 :                             state.dataWaterThermalTanks->WaterHeaterDesuperheater(this->DesuperheaterNum).HeaterRate,
    5572              :                             OutputProcessor::TimeStepType::System,
    5573              :                             OutputProcessor::StoreType::Average,
    5574            6 :                             state.dataWaterThermalTanks->WaterHeaterDesuperheater(this->DesuperheaterNum).Name);
    5575           12 :         SetupOutputVariable(state,
    5576              :                             "Water Heater Heating Energy",
    5577              :                             Constant::Units::J,
    5578            6 :                             state.dataWaterThermalTanks->WaterHeaterDesuperheater(this->DesuperheaterNum).HeaterEnergy,
    5579              :                             OutputProcessor::TimeStepType::System,
    5580              :                             OutputProcessor::StoreType::Sum,
    5581            6 :                             state.dataWaterThermalTanks->WaterHeaterDesuperheater(this->DesuperheaterNum).Name,
    5582              :                             Constant::eResource::EnergyTransfer,
    5583              :                             OutputProcessor::Group::Plant,
    5584              :                             OutputProcessor::EndUseCat::WaterSystem, // DHW
    5585              :                             "Water Heater");
    5586              :     }
    5587              : 
    5588              :     // Setup report variables for WaterHeater:Stratified
    5589              :     // CurrentModuleObject='WaterHeater:Stratified'
    5590          195 :     if (this->WaterThermalTankType == DataPlant::PlantEquipmentType::WtrHeaterStratified) {
    5591              : 
    5592           32 :         SetupOutputVariable(state,
    5593              :                             "Water Heater Heater 1 Heating Rate",
    5594              :                             Constant::Units::W,
    5595           16 :                             this->HeaterRate1,
    5596              :                             OutputProcessor::TimeStepType::System,
    5597              :                             OutputProcessor::StoreType::Average,
    5598           16 :                             this->Name);
    5599           32 :         SetupOutputVariable(state,
    5600              :                             "Water Heater Heater 2 Heating Rate",
    5601              :                             Constant::Units::W,
    5602           16 :                             this->HeaterRate2,
    5603              :                             OutputProcessor::TimeStepType::System,
    5604              :                             OutputProcessor::StoreType::Average,
    5605           16 :                             this->Name);
    5606              : 
    5607           32 :         SetupOutputVariable(state,
    5608              :                             "Water Heater Heater 1 Heating Energy",
    5609              :                             Constant::Units::J,
    5610           16 :                             this->HeaterEnergy1,
    5611              :                             OutputProcessor::TimeStepType::System,
    5612              :                             OutputProcessor::StoreType::Sum,
    5613           16 :                             this->Name);
    5614           32 :         SetupOutputVariable(state,
    5615              :                             "Water Heater Heater 2 Heating Energy",
    5616              :                             Constant::Units::J,
    5617           16 :                             this->HeaterEnergy2,
    5618              :                             OutputProcessor::TimeStepType::System,
    5619              :                             OutputProcessor::StoreType::Sum,
    5620           16 :                             this->Name);
    5621              : 
    5622           16 :         SetupOutputVariable(state,
    5623              :                             "Water Heater Heater 1 Cycle On Count",
    5624              :                             Constant::Units::None,
    5625           16 :                             this->CycleOnCount1,
    5626              :                             OutputProcessor::TimeStepType::System,
    5627              :                             OutputProcessor::StoreType::Sum,
    5628           16 :                             this->Name);
    5629           16 :         SetupOutputVariable(state,
    5630              :                             "Water Heater Heater 2 Cycle On Count",
    5631              :                             Constant::Units::None,
    5632           16 :                             this->CycleOnCount2,
    5633              :                             OutputProcessor::TimeStepType::System,
    5634              :                             OutputProcessor::StoreType::Sum,
    5635           16 :                             this->Name);
    5636              : 
    5637           32 :         SetupOutputVariable(state,
    5638              :                             "Water Heater Heater 1 Runtime Fraction",
    5639              :                             Constant::Units::None,
    5640           16 :                             this->RuntimeFraction1,
    5641              :                             OutputProcessor::TimeStepType::System,
    5642              :                             OutputProcessor::StoreType::Average,
    5643           16 :                             this->Name);
    5644           32 :         SetupOutputVariable(state,
    5645              :                             "Water Heater Heater 2 Runtime Fraction",
    5646              :                             Constant::Units::None,
    5647           16 :                             this->RuntimeFraction2,
    5648              :                             OutputProcessor::TimeStepType::System,
    5649              :                             OutputProcessor::StoreType::Average,
    5650           16 :                             this->Name);
    5651              : 
    5652          144 :         for (int NodeNum = 1; NodeNum <= this->Nodes; ++NodeNum) {
    5653          384 :             SetupOutputVariable(state,
    5654          256 :                                 format("Water Heater Temperature Node {}", NodeNum),
    5655              :                                 Constant::Units::C,
    5656          128 :                                 this->Node(NodeNum).TempAvg,
    5657              :                                 OutputProcessor::TimeStepType::System,
    5658              :                                 OutputProcessor::StoreType::Average,
    5659          128 :                                 this->Name);
    5660              :         }
    5661              : 
    5662          144 :         for (int NodeNum = 1; NodeNum <= this->Nodes; ++NodeNum) {
    5663          384 :             SetupOutputVariable(state,
    5664          256 :                                 format("Water Heater Final Temperature Node {}", NodeNum),
    5665              :                                 Constant::Units::C,
    5666          128 :                                 this->Node(NodeNum).Temp,
    5667              :                                 OutputProcessor::TimeStepType::System,
    5668              :                                 OutputProcessor::StoreType::Average,
    5669          128 :                                 this->Name);
    5670              :         }
    5671              :     }
    5672              : 
    5673          195 :     if (this->WaterThermalTankType == DataPlant::PlantEquipmentType::WtrHeaterStratified) {
    5674              : 
    5675          144 :         for (int NodeNum = 1; NodeNum <= this->Nodes; ++NodeNum) {
    5676              :             static constexpr std::string_view Format_723("Water Heater Stratified Node Information,{},{:.4T},{:.4T},{:.3T},{:.4T},{:.4T},{},{}\n");
    5677          128 :             print(state.files.eio,
    5678              :                   Format_723,
    5679              :                   NodeNum,
    5680          128 :                   this->Node(NodeNum).Height,
    5681          128 :                   this->Node(NodeNum).Volume,
    5682          128 :                   this->Node(NodeNum).MaxCapacity,
    5683          128 :                   this->Node(NodeNum).OffCycLossCoeff,
    5684          128 :                   this->Node(NodeNum).OnCycLossCoeff,
    5685          128 :                   this->Node(NodeNum).Inlets,
    5686          128 :                   this->Node(NodeNum).Outlets);
    5687              :         }
    5688              :     }
    5689          195 : }
    5690              : 
    5691            0 : void WaterThermalTankData::ValidatePLFCurve(EnergyPlusData &state, int const CurveIndex, bool &IsValid)
    5692              : {
    5693              : 
    5694              :     // SUBROUTINE INFORMATION:
    5695              :     //       AUTHOR         Peter Graham Ellis
    5696              :     //       DATE WRITTEN   February 2005
    5697              :     //       MODIFIED       na
    5698              :     //       RE-ENGINEERED  na
    5699              : 
    5700              :     // PURPOSE OF THIS SUBROUTINE:
    5701              :     // Validates the Part Load Factor curve by making sure it can never be less than or equal to zero
    5702              :     // over the domain of Part Load Ratio inputs from 0 to 1.
    5703              : 
    5704              :     // METHODOLOGY EMPLOYED:
    5705              :     // Currently can only check 0 and 1.  Need changes in CurveManager to be able to check minimums and
    5706              :     // maximums.
    5707              : 
    5708            0 :     IsValid = true;
    5709              : 
    5710              :     // Check 0 and 1
    5711            0 :     if (Curve::CurveValue(state, CurveIndex, 0.0) <= 0) {
    5712            0 :         IsValid = false;
    5713              :     }
    5714            0 :     if (Curve::CurveValue(state, CurveIndex, 1.0) <= 0) {
    5715            0 :         IsValid = false;
    5716              :     }
    5717            0 : }
    5718              : 
    5719           18 : void WaterThermalTankData::SetupStratifiedNodes(EnergyPlusData &state)
    5720              : {
    5721              : 
    5722              :     // SUBROUTINE INFORMATION:
    5723              :     //       AUTHOR         Peter Graham Ellis
    5724              :     //       DATE WRITTEN   January 2007
    5725              :     //       MODIFIED       na
    5726              :     //       RE-ENGINEERED  na
    5727              : 
    5728              :     // PURPOSE OF THIS SUBROUTINE:
    5729              :     // Sets up node properties based on the tank shape, i.e., vertical cylinder, horizontal cylinder, or other.
    5730              :     // Node height, skin area, vertical conduction area, and loss coefficients are calculated and assigned.
    5731              :     // Heating elements, parasitics, and fluid inlet and outlet flows are assigned according to node height.
    5732              : 
    5733              :     // METHODOLOGY EMPLOYED:
    5734              :     // Tank is divided into nodes of equal mass.  For horizontal cylinders, node heights are calculated using
    5735              :     // the Newton-Raphson iterative method.  For vertical cylinders and other shapes, the node heights are calculated
    5736              :     // using basic geometry.
    5737              : 
    5738              :     static constexpr std::string_view RoutineName("GetWaterThermalTankInput");
    5739              : 
    5740           18 :     constexpr Real64 Tolerance(1.0e-8); // Tolerance for Newton-Raphson solution
    5741           18 :     constexpr Real64 FluidCond(0.6);    // Conductivity of water (W/m-K)
    5742              : 
    5743           18 :     int NumNodes = this->Nodes;
    5744           18 :     this->Node.allocate(NumNodes);
    5745              :     Real64 rho;
    5746           18 :     if ((this->UseSidePlantLoc.loopNum > 0) && allocated(state.dataPlnt->PlantLoop)) {
    5747            0 :         rho = state.dataPlnt->PlantLoop(this->UseSidePlantLoc.loopNum).glycol->getDensity(state, Constant::InitConvTemp, RoutineName);
    5748              :     } else {
    5749           18 :         rho = this->water->getDensity(state, Constant::InitConvTemp, RoutineName);
    5750              :     }
    5751              : 
    5752           18 :     Real64 NodeMass = this->Volume * rho / NumNodes;
    5753              :     Real64 TankHeight;
    5754              : 
    5755              :     // Mixing rate set to 50% of the max value for dt = 1.0
    5756           18 :     this->InversionMixingRate = NodeMass * 0.5 * 1.0;
    5757              : 
    5758           18 :     if ((this->Shape == TankShape::VertCylinder) || (this->Shape == TankShape::Other)) {
    5759           18 :         TankHeight = this->Height;
    5760           18 :         Real64 EndArea = this->Volume / TankHeight;
    5761           18 :         Real64 NodeHeight = TankHeight / NumNodes;
    5762           18 :         Real64 CondCoeff = (FluidCond + this->AdditionalCond) * EndArea / NodeHeight;
    5763              : 
    5764              :         Real64 Perimeter_loc;
    5765           18 :         if (this->Shape == TankShape::VertCylinder) {
    5766           18 :             Real64 Radius = std::sqrt(EndArea / Constant::Pi);
    5767           18 :             Perimeter_loc = 2.0 * Constant::Pi * Radius;
    5768              :         } else { // TankShapeOther
    5769            0 :             Perimeter_loc = this->Perimeter;
    5770              :         }
    5771              : 
    5772          158 :         for (int NodeNum = 1; NodeNum <= NumNodes; ++NodeNum) {
    5773          140 :             this->Node(NodeNum).Mass = NodeMass;
    5774          140 :             this->Node(NodeNum).Volume = this->Volume / NumNodes;
    5775          140 :             this->Node(NodeNum).Height = NodeHeight;
    5776          140 :             this->Node(NodeNum).CondCoeffUp = CondCoeff;
    5777          140 :             this->Node(NodeNum).CondCoeffDn = CondCoeff;
    5778              : 
    5779              :             Real64 SkinArea;
    5780          140 :             if ((NodeNum == 1) || (NodeNum == NumNodes)) {
    5781           34 :                 SkinArea = Perimeter_loc * NodeHeight + EndArea;
    5782              :             } else {
    5783          106 :                 SkinArea = Perimeter_loc * NodeHeight;
    5784              :             }
    5785              : 
    5786          140 :             this->Node(NodeNum).OnCycLossCoeff = this->SkinLossCoeff * SkinArea + this->AdditionalLossCoeff(NodeNum);
    5787              : 
    5788          140 :             this->Node(NodeNum).OffCycLossCoeff = this->Node(NodeNum).OnCycLossCoeff + this->OffCycFlueLossCoeff;
    5789              : 
    5790              :         } // NodeNum
    5791              : 
    5792           18 :         this->Node(1).CondCoeffUp = 0.0;
    5793           18 :         this->Node(NumNodes).CondCoeffDn = 0.0;
    5794              : 
    5795           18 :     } else {                              // Tank%Shape == TankShapeHorizCylinder
    5796            0 :         Real64 TankLength = this->Height; // Height is the length in the axial direction
    5797            0 :         Real64 EndArea = this->Volume / TankLength;
    5798            0 :         Real64 Radius = std::sqrt(EndArea / Constant::Pi);
    5799            0 :         TankHeight = 2.0 * Radius; // Actual vertical height
    5800            0 :         Real64 NodeEndArea = EndArea / NumNodes;
    5801              : 
    5802            0 :         Real64 R = Radius;
    5803            0 :         Real64 H0 = 0.0;
    5804            0 :         Real64 ChordLength = 0.0;
    5805            0 :         for (int NodeNum = 1; NodeNum <= NumNodes; ++NodeNum) {
    5806            0 :             this->Node(NodeNum).Mass = NodeMass;
    5807            0 :             this->Node(NodeNum).Volume = this->Volume / NumNodes;
    5808              :             Real64 H;
    5809            0 :             if (NodeNum == NumNodes) {
    5810            0 :                 H = TankHeight;
    5811              :             } else {
    5812              :                 // Use the Newton-Raphson method to solve the nonlinear algebraic equation for node height
    5813            0 :                 H = H0 + TankHeight / NumNodes; // Initial guess
    5814              : 
    5815              :                 while (true) {
    5816            0 :                     Real64 a = std::sqrt(H);
    5817            0 :                     Real64 b = std::sqrt(2.0 * R - H);
    5818            0 :                     Real64 c = 2.0 * R * R * std::atan(a / b) - (2.0 * R * R - 3.0 * H * R + H * H) * (a / b);
    5819              :                     Real64 c0;
    5820            0 :                     if (H0 > 0.0) {
    5821            0 :                         Real64 a0 = std::sqrt(H0);
    5822            0 :                         Real64 b0 = std::sqrt(2.0 * R - H0);
    5823            0 :                         c0 = 2.0 * R * R * std::atan(a0 / b0) - (2.0 * R * R - 3.0 * H0 * R + H0 * H0) * (a0 / b0);
    5824              :                     } else {
    5825            0 :                         c0 = 0.0;
    5826              :                     }
    5827              : 
    5828            0 :                     Real64 ApproxEndArea = c - c0;          // Area approximated by iteration
    5829            0 :                     Real64 G = ApproxEndArea - NodeEndArea; // G is the function that should converge to zero
    5830              : 
    5831            0 :                     if (std::abs(G) < Tolerance) {
    5832            0 :                         break; // Converged !!!
    5833              :                     } else {
    5834            0 :                         H -= G / (2.0 * a * b); // Calculate next guess:  H = Hprev - G/G'
    5835              :                     }
    5836            0 :                 } // Newton-Raphson
    5837              :             }
    5838              : 
    5839            0 :             this->Node(NodeNum).Height = H - H0;
    5840              : 
    5841            0 :             if (NodeNum > 1) {
    5842            0 :                 Real64 CrossArea = 2.0 * ChordLength * TankLength; // Use old ChordLength from previous node
    5843            0 :                 Real64 CondCoeff = (FluidCond + this->AdditionalCond) * CrossArea / (0.5 * (H - H0) + 0.5 * this->Node(NodeNum - 1).Height);
    5844            0 :                 this->Node(NodeNum - 1).CondCoeffUp = CondCoeff; // Set for previous node
    5845            0 :                 this->Node(NodeNum).CondCoeffDn = CondCoeff;     // Set for this node
    5846              :             }
    5847              : 
    5848            0 :             ChordLength = std::sqrt(2.0 * R * H - H * H); // Calc new ChordLength to be used with next node
    5849              : 
    5850            0 :             Real64 Perimeter_loc = 2.0 * R * (std::acos((R - H) / R) - std::acos((R - H0) / R)); // Segments of circular perimeter
    5851            0 :             Real64 SkinArea = Perimeter_loc * TankLength + 2.0 * NodeEndArea;
    5852              : 
    5853            0 :             this->Node(NodeNum).OnCycLossCoeff = this->SkinLossCoeff * SkinArea + this->AdditionalLossCoeff(NodeNum);
    5854              : 
    5855            0 :             this->Node(NodeNum).OffCycLossCoeff = this->Node(NodeNum).OnCycLossCoeff + this->OffCycFlueLossCoeff;
    5856              :             // Although it doesn't make much sense to have a flue in a horizontal tank, keep it in anyway
    5857              : 
    5858            0 :             H0 = H;
    5859              :         } // NodeNum
    5860              : 
    5861            0 :         this->Node(1).CondCoeffUp = 0.0;
    5862            0 :         this->Node(NumNodes).CondCoeffDn = 0.0;
    5863              :     }
    5864              : 
    5865              :     // Loop through nodes again (from top to bottom this time) and assign heating elements, parasitics, flow inlets/outlets
    5866              :     // according to their vertical heights in the tank
    5867           18 :     Real64 H0 = TankHeight;
    5868          158 :     for (int NodeNum = 1; NodeNum <= NumNodes; ++NodeNum) {
    5869              :         Real64 H;
    5870          140 :         if (NodeNum == NumNodes) {
    5871           18 :             H = -1.0; // Avoids rounding errors and ensures that anything at height 0.0 goes into the bottom node
    5872              :         } else {
    5873          122 :             H = H0 - this->Node(NodeNum).Height;
    5874              :         }
    5875              : 
    5876              :         // Assign heater elements to the nodes at the specified heights
    5877          140 :         if ((this->HeaterHeight1 <= H0) && (this->HeaterHeight1 > H)) {
    5878              :             //       sensor node will not get set if user enters 0 for this heater capacity
    5879              :             //       (Tank%MaxCapacity > 0.0d0)) THEN
    5880           18 :             this->HeaterNode1 = NodeNum;
    5881           18 :             this->Node(NodeNum).MaxCapacity = this->MaxCapacity;
    5882              :         }
    5883              : 
    5884          140 :         if ((this->HeaterHeight2 <= H0) && (this->HeaterHeight2 > H)) {
    5885              :             //       sensor node will not get set if user enters 0 for this heater capacity
    5886              :             //      .AND. (Tank%MaxCapacity2 > 0.0d0)) THEN
    5887           18 :             this->HeaterNode2 = NodeNum;
    5888              : 
    5889           18 :             if ((NodeNum == this->HeaterNode1) && (this->StratifiedControlMode == PriorityControlMode::Simultaneous)) {
    5890            0 :                 this->Node(NodeNum).MaxCapacity += this->MaxCapacity2;
    5891              :             } else {
    5892           18 :                 this->Node(NodeNum).MaxCapacity = this->MaxCapacity2;
    5893              :             }
    5894              :         }
    5895              : 
    5896              :         // Assign parasitic heat gains to the nodes at the specified heights
    5897          140 :         if ((this->OffCycParaHeight <= H0) && (this->OffCycParaHeight > H)) {
    5898           18 :             this->Node(NodeNum).OffCycParaLoad = this->OffCycParaFracToTank * this->OffCycParaLoad;
    5899              :         }
    5900              : 
    5901          140 :         if ((this->OnCycParaHeight <= H0) && (this->OnCycParaHeight > H)) {
    5902           18 :             this->Node(NodeNum).OnCycParaLoad = this->OnCycParaFracToTank * this->OnCycParaLoad;
    5903              :         }
    5904              : 
    5905              :         // Assign inlets and outlets to the nodes at the specified heights
    5906          140 :         if ((this->UseInletHeight <= H0) && (this->UseInletHeight > H)) {
    5907           18 :             this->UseInletStratNode = NodeNum;
    5908              : 
    5909           18 :             if ((this->UseInletNode > 0) || (this->MassFlowRateMax > 0.0)) {
    5910           18 :                 ++this->Node(NodeNum).Inlets;
    5911              :             }
    5912              :         }
    5913              : 
    5914          140 :         if ((this->UseOutletHeight <= H0) && (this->UseOutletHeight > H)) {
    5915           18 :             this->UseOutletStratNode = NodeNum;
    5916              : 
    5917           18 :             if ((this->UseOutletNode > 0) || (this->MassFlowRateMax > 0.0)) {
    5918           18 :                 ++this->Node(NodeNum).Outlets;
    5919              :             }
    5920              :         }
    5921              : 
    5922          140 :         if ((this->SourceInletHeight <= H0) && (this->SourceInletHeight > H) && (this->SourceInletNode > 0)) {
    5923              : 
    5924           11 :             this->SourceInletStratNode = NodeNum;
    5925           11 :             ++this->Node(NodeNum).Inlets;
    5926              :         }
    5927              : 
    5928          140 :         if ((this->SourceOutletHeight <= H0) && (this->SourceOutletHeight > H) && (this->SourceOutletNode > 0)) {
    5929              : 
    5930           11 :             this->SourceOutletStratNode = NodeNum;
    5931           11 :             ++this->Node(NodeNum).Outlets;
    5932              :         }
    5933              : 
    5934          140 :         H0 = H;
    5935              :     } // NodeNum
    5936           18 : }
    5937              : 
    5938      6337420 : void WaterThermalTankData::initialize(EnergyPlusData &state, bool const FirstHVACIteration)
    5939              : {
    5940              : 
    5941              :     // SUBROUTINE INFORMATION:
    5942              :     //       AUTHOR         Peter Graham Ellis
    5943              :     //       DATE WRITTEN   February 2004
    5944              :     //       MODIFIED       FSEC, July 2005
    5945              :     //                      Brent Griffith, October 2007 indirect fired water heater
    5946              :     //                        B. Shen 12/2014, add air-source variable-speed heat pump water heating
    5947              :     //       RE-ENGINEERED  na
    5948              : 
    5949              :     // PURPOSE OF THIS SUBROUTINE:
    5950              :     // Initialize the water heater, heat pump water heater, or desuperheater heating coil objects during the simulation.
    5951              :     // determine flow rates thru use side and source side plant connections (if any)
    5952              : 
    5953              :     // METHODOLOGY EMPLOYED:
    5954              :     // Inlet and outlet nodes are initialized.  Scheduled values are retrieved for the current timestep.
    5955              : 
    5956      6337420 :     auto &ZoneEqSizing = state.dataSize->ZoneEqSizing;
    5957              : 
    5958              :     static constexpr std::string_view RoutineName("InitWaterThermalTank");
    5959              :     static constexpr std::string_view GetWaterThermalTankInput("GetWaterThermalTankInput");
    5960              :     static constexpr std::string_view SizeTankForDemand("SizeTankForDemandSide");
    5961              : 
    5962      6337420 :     if (this->scanPlantLoopsFlag && allocated(state.dataPlnt->PlantLoop)) {
    5963          201 :         if ((this->UseInletNode > 0) && (this->HeatPumpNum == 0)) {
    5964          123 :             bool errFlag = false;
    5965          369 :             PlantUtilities::ScanPlantLoopsForObject(
    5966          246 :                 state, this->Name, this->WaterThermalTankType, this->UseSidePlantLoc, errFlag, _, _, _, this->UseInletNode, _);
    5967          123 :             if (errFlag) {
    5968            0 :                 ShowFatalError(state, "InitWaterThermalTank: Program terminated due to previous condition(s).");
    5969              :             }
    5970              :         }
    5971          201 :         if ((this->UseInletNode > 0) && (this->HeatPumpNum > 0)) {
    5972              :             // this is a heat pump water heater, need a separate block because TypeOf_HeatPumpWtrHeater shows up on Branch
    5973              :             //  (input should probably have been the associated tank )
    5974           10 :             bool errFlag = false;
    5975           30 :             PlantUtilities::ScanPlantLoopsForObject(state,
    5976           10 :                                                     state.dataWaterThermalTanks->HPWaterHeater(this->HeatPumpNum).Name,
    5977           10 :                                                     state.dataWaterThermalTanks->HPWaterHeater(this->HeatPumpNum).HPWHType,
    5978           10 :                                                     this->UseSidePlantLoc,
    5979              :                                                     errFlag,
    5980              :                                                     _,
    5981              :                                                     _,
    5982              :                                                     _,
    5983           10 :                                                     this->UseInletNode,
    5984              :                                                     _);
    5985           10 :             if (errFlag) {
    5986            0 :                 ShowFatalError(state, "InitWaterThermalTank: Program terminated due to previous condition(s).");
    5987              :             }
    5988              :         }
    5989          201 :         if ((this->SourceInletNode > 0) && (this->DesuperheaterNum == 0) && (this->HeatPumpNum == 0)) {
    5990           21 :             bool errFlag = false;
    5991           63 :             PlantUtilities::ScanPlantLoopsForObject(
    5992           42 :                 state, this->Name, this->WaterThermalTankType, this->SrcSidePlantLoc, errFlag, _, _, _, this->SourceInletNode, _);
    5993           21 :             if (this->UseInletNode > 0) {
    5994           21 :                 PlantUtilities::InterConnectTwoPlantLoopSides(state, this->UseSidePlantLoc, this->SrcSidePlantLoc, this->WaterThermalTankType, true);
    5995              :             }
    5996           21 :             if (errFlag) {
    5997            0 :                 ShowFatalError(state, "InitWaterThermalTank: Program terminated due to previous condition(s).");
    5998              :             }
    5999              :         }
    6000          201 :         this->scanPlantLoopsFlag = false;
    6001              :     }
    6002              : 
    6003      6337420 :     if (this->SetLoopIndexFlag && allocated(state.dataPlnt->PlantLoop)) {
    6004         1474 :         if ((this->UseInletNode > 0) && (this->HeatPumpNum == 0)) {
    6005              :             Real64 rho =
    6006         1396 :                 state.dataPlnt->PlantLoop(this->UseSidePlantLoc.loopNum).glycol->getDensity(state, Constant::InitConvTemp, GetWaterThermalTankInput);
    6007         1396 :             this->PlantUseMassFlowRateMax = this->UseDesignVolFlowRate * rho;
    6008         1396 :             this->Mass = this->Volume * rho;
    6009         1396 :             this->UseSidePlantSizNum = state.dataPlnt->PlantLoop(this->UseSidePlantLoc.loopNum).PlantSizNum;
    6010         1396 :             if ((this->UseDesignVolFlowRateWasAutoSized) && (this->UseSidePlantSizNum == 0)) {
    6011            0 :                 ShowSevereError(state,
    6012            0 :                                 format("InitWaterThermalTank: Did not find Sizing:Plant object for use side of plant thermal tank = {}", this->Name));
    6013            0 :                 ShowFatalError(state, "InitWaterThermalTank: Program terminated due to previous condition(s).");
    6014              :             }
    6015              :         }
    6016         1474 :         if ((this->UseInletNode > 0) && (this->HeatPumpNum > 0)) {
    6017              :             Real64 rho =
    6018           10 :                 state.dataPlnt->PlantLoop(this->UseSidePlantLoc.loopNum).glycol->getDensity(state, Constant::InitConvTemp, GetWaterThermalTankInput);
    6019           10 :             this->PlantUseMassFlowRateMax = this->UseDesignVolFlowRate * rho;
    6020           10 :             this->Mass = this->Volume * rho;
    6021           10 :             this->UseSidePlantSizNum = state.dataPlnt->PlantLoop(this->UseSidePlantLoc.loopNum).PlantSizNum;
    6022           10 :             if ((this->UseDesignVolFlowRateWasAutoSized) && (this->UseSidePlantSizNum == 0)) {
    6023            0 :                 ShowSevereError(state,
    6024            0 :                                 format("InitWaterThermalTank: Did not find Sizing:Plant object for use side of plant thermal tank = {}", this->Name));
    6025            0 :                 ShowFatalError(state, "InitWaterThermalTank: Program terminated due to previous condition(s).");
    6026              :             }
    6027              :         }
    6028         1474 :         if ((this->SourceInletNode > 0) && (this->DesuperheaterNum == 0) && (this->HeatPumpNum == 0)) {
    6029              :             Real64 rho =
    6030          379 :                 state.dataPlnt->PlantLoop(this->SrcSidePlantLoc.loopNum).glycol->getDensity(state, Constant::InitConvTemp, GetWaterThermalTankInput);
    6031          379 :             this->PlantSourceMassFlowRateMax = this->SourceDesignVolFlowRate * rho;
    6032          379 :             this->SourceSidePlantSizNum = state.dataPlnt->PlantLoop(this->SrcSidePlantLoc.loopNum).PlantSizNum;
    6033          379 :             if ((this->SourceDesignVolFlowRateWasAutoSized) && (this->SourceSidePlantSizNum == 0)) {
    6034            0 :                 ShowSevereError(
    6035            0 :                     state, format("InitWaterThermalTank: Did not find Sizing:Plant object for source side of plant thermal tank = {}", this->Name));
    6036            0 :                 ShowFatalError(state, "InitWaterThermalTank: Program terminated due to previous condition(s).");
    6037              :             }
    6038              :         }
    6039         1474 :         if (((this->SourceInletNode > 0) && (this->DesuperheaterNum > 0)) || (this->HeatPumpNum > 0)) {
    6040           29 :             this->SetLoopIndexFlag = false;
    6041              :         }
    6042         1474 :         if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
    6043          123 :             this->SetLoopIndexFlag = false;
    6044              :         }
    6045         1474 :         if (this->StandAlone) {
    6046           49 :             this->SizeStandAloneWaterHeater(state);
    6047           49 :             this->SetLoopIndexFlag = false;
    6048              :         }
    6049      6335946 :     } else if (this->SetLoopIndexFlag && !state.dataGlobal->AnyPlantInModel) {
    6050            0 :         if (this->StandAlone) {
    6051            0 :             this->SizeStandAloneWaterHeater(state);
    6052              :         }
    6053            0 :         this->SetLoopIndexFlag = false;
    6054              :     }
    6055              : 
    6056      6337420 :     if (state.dataGlobal->BeginEnvrnFlag && this->MyEnvrnFlag && !this->SetLoopIndexFlag) {
    6057              : 
    6058        49777 :         if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
    6059              : 
    6060        48873 :             if (this->ControlType == HeaterControlMode::Cycle) {
    6061        48355 :                 this->MinCapacity = this->MaxCapacity;
    6062              :             }
    6063              : 
    6064              :             // check for sizing issues that model can not support
    6065              : 
    6066              :             // if stratified tank model, ensure that nominal change over rate is greater than one minute, avoid numerical problems.
    6067              : 
    6068        48873 :             if ((this->WaterThermalTankType == DataPlant::PlantEquipmentType::WtrHeaterStratified) ||
    6069        46547 :                 (this->WaterThermalTankType == DataPlant::PlantEquipmentType::ChilledWaterTankStratified)) {
    6070         3004 :                 Real64 MaxSideVolFlow = max(this->UseDesignVolFlowRate, this->SourceDesignVolFlowRate);
    6071              : 
    6072         3004 :                 if (MaxSideVolFlow > 0.0) { // protect div by zero
    6073         2827 :                     Real64 TankChangeRateScale = this->Volume / MaxSideVolFlow;
    6074         2827 :                     if (TankChangeRateScale < 60.0) { // nominal change over in less than one minute
    6075            0 :                         ShowSevereError(state, "InitWaterThermalTank: Detected problem for stratified tank model.  Model cannot be applied.");
    6076            0 :                         ShowContinueError(state, format("Occurs for stratified tank name = {}", this->Name));
    6077            0 :                         ShowContinueError(state, format("Tank volume = {:.4R} [m3]", this->Volume));
    6078            0 :                         ShowContinueError(state, format("Tank use side volume flow rate = {:.4R} [m3/s]", this->UseDesignVolFlowRate));
    6079            0 :                         ShowContinueError(state, format("Tank source side volume flow rate = {:.4R} [m3/s]", this->SourceDesignVolFlowRate));
    6080            0 :                         ShowContinueError(state, format("Nominal tank change over rate = {:.2R} [s]", TankChangeRateScale));
    6081            0 :                         ShowContinueError(
    6082              :                             state, "Change over rate is too fast, increase tank volume, decrease connection flow rates or use mixed tank model");
    6083              : 
    6084            0 :                         ShowFatalError(state, "InitWaterThermalTank: Simulation halted because of sizing problem in stratified tank model.");
    6085              :                     }
    6086              :                 }
    6087              :             }
    6088              :         }
    6089              : 
    6090              :         // Clear node initial conditions
    6091        49777 :         if (this->UseInletNode > 0 && this->UseOutletNode > 0) {
    6092        48284 :             state.dataLoopNodes->Node(this->UseInletNode).Temp = 0.0;
    6093              :             Real64 rho =
    6094        48284 :                 state.dataPlnt->PlantLoop(this->UseSidePlantLoc.loopNum).glycol->getDensity(state, Constant::InitConvTemp, GetWaterThermalTankInput);
    6095        48284 :             this->MassFlowRateMin = this->VolFlowRateMin * rho;
    6096        48284 :             this->PlantUseMassFlowRateMax = this->UseDesignVolFlowRate * rho;
    6097        48284 :             PlantUtilities::InitComponentNodes(state, this->MassFlowRateMin, this->PlantUseMassFlowRateMax, this->UseInletNode, this->UseOutletNode);
    6098        48284 :             this->UseOutletTemp = 0.0;
    6099        48284 :             this->UseMassFlowRate = 0.0;
    6100        48284 :             this->SavedUseOutletTemp = 0.0;
    6101              : 
    6102        48284 :             this->Mass = this->Volume * rho;
    6103        48284 :             this->UseBranchControlType = DataPlant::CompData::getPlantComponent(state, this->UseSidePlantLoc).FlowCtrl;
    6104              :         }
    6105              : 
    6106        49777 :         if ((this->SourceInletNode > 0) && (this->DesuperheaterNum == 0) && (this->HeatPumpNum == 0)) {
    6107              :             Real64 rho =
    6108        14760 :                 state.dataPlnt->PlantLoop(this->SrcSidePlantLoc.loopNum).glycol->getDensity(state, Constant::InitConvTemp, GetWaterThermalTankInput);
    6109        14760 :             this->PlantSourceMassFlowRateMax = this->SourceDesignVolFlowRate * rho;
    6110        14760 :             PlantUtilities::InitComponentNodes(state, 0.0, this->PlantSourceMassFlowRateMax, this->SourceInletNode, this->SourceOutletNode);
    6111              : 
    6112        14760 :             this->SourceOutletTemp = 0.0;
    6113        14760 :             this->SourceMassFlowRate = 0.0;
    6114        14760 :             this->SavedSourceOutletTemp = 0.0;
    6115              : 
    6116        14760 :             this->SourceBranchControlType = DataPlant::CompData::getPlantComponent(state, this->SrcSidePlantLoc).FlowCtrl;
    6117              :         }
    6118              : 
    6119        49777 :         if ((this->SourceInletNode > 0) && ((this->DesuperheaterNum > 0) || (this->HeatPumpNum > 0))) {
    6120         2410 :             state.dataLoopNodes->Node(this->SourceInletNode).Temp = 0.0;
    6121         2410 :             this->SourceOutletTemp = 0.0;
    6122         2410 :             this->SourceMassFlowRate = 0.0;
    6123         2410 :             this->SavedSourceOutletTemp = 0.0;
    6124         2410 :             Real64 rho = this->water->getDensity(state, Constant::InitConvTemp, SizeTankForDemand);
    6125         2410 :             this->PlantSourceMassFlowRateMax = this->SourceDesignVolFlowRate * rho;
    6126              :         }
    6127              : 
    6128              :         // Initialize tank temperature to setpoint of first hour of warm up period
    6129              :         // (use HPWH or Desuperheater heating coil set point if applicable)
    6130        49777 :         Sched::Schedule *sched = nullptr;
    6131        49777 :         if (this->HeatPumpNum > 0) {
    6132         2278 :             state.dataWaterThermalTanks->HPWaterHeater(this->HeatPumpNum).Mode = TankOperatingMode::Floating;
    6133         2278 :             state.dataWaterThermalTanks->HPWaterHeater(this->HeatPumpNum).SaveMode = TankOperatingMode::Floating;
    6134         2278 :             state.dataWaterThermalTanks->HPWaterHeater(this->HeatPumpNum).SaveWHMode = TankOperatingMode::Floating;
    6135         2278 :             sched = state.dataWaterThermalTanks->HPWaterHeater(this->HeatPumpNum).setptTempSched;
    6136        47499 :         } else if (this->DesuperheaterNum > 0) {
    6137          132 :             state.dataWaterThermalTanks->WaterHeaterDesuperheater(this->DesuperheaterNum).Mode = TankOperatingMode::Floating;
    6138          132 :             sched = state.dataWaterThermalTanks->WaterHeaterDesuperheater(this->DesuperheaterNum).setptTempSched;
    6139              :         } else {
    6140        47367 :             sched = this->setptTempSched;
    6141              :         }
    6142              : 
    6143        49777 :         if (sched != nullptr) {
    6144        49777 :             this->TankTemp = sched->getCurrentVal();
    6145        49777 :             this->SavedTankTemp = this->TankTemp;
    6146              : 
    6147        49777 :             if (this->Nodes > 0) {
    6148        27013 :                 for (auto &e : this->Node) {
    6149        23926 :                     e.Temp = e.SavedTemp = this->TankTemp;
    6150              :                 }
    6151              :             }
    6152              :         } else {
    6153            0 :             this->TankTemp = 20.0;
    6154            0 :             this->SavedTankTemp = this->TankTemp;
    6155              : 
    6156            0 :             if (this->Nodes > 0) {
    6157            0 :                 for (auto &e : this->Node) {
    6158            0 :                     e.Temp = e.SavedTemp = this->TankTemp;
    6159              :                 }
    6160              :             }
    6161              :         }
    6162        49777 :         this->SourceOutletTemp = this->SavedTankTemp;
    6163        49777 :         this->SavedSourceOutletTemp = this->SavedTankTemp;
    6164        49777 :         this->UseOutletTemp = this->SavedTankTemp;
    6165        49777 :         this->SavedUseOutletTemp = this->SavedTankTemp;
    6166        49777 :         this->TankTempAvg = this->SavedTankTemp;
    6167              : 
    6168        49777 :         this->SavedHeaterOn1 = false;
    6169        49777 :         this->SavedHeaterOn2 = false;
    6170        49777 :         this->Mode = TankOperatingMode::Floating;
    6171        49777 :         this->SavedMode = TankOperatingMode::Floating;
    6172        49777 :         this->FirstRecoveryDone = false;
    6173        49777 :         this->FirstRecoveryFuel = 0.0;
    6174        49777 :         this->UnmetEnergy = 0.0;
    6175        49777 :         this->LossEnergy = 0.0;
    6176        49777 :         this->FlueLossEnergy = 0.0;
    6177        49777 :         this->UseEnergy = 0.0;
    6178        49777 :         this->TotalDemandEnergy = 0.0;
    6179        49777 :         this->SourceEnergy = 0.0;
    6180        49777 :         this->HeaterEnergy = 0.0;
    6181        49777 :         this->HeaterEnergy1 = 0.0;
    6182        49777 :         this->HeaterEnergy2 = 0.0;
    6183        49777 :         this->FuelEnergy = 0.0;
    6184        49777 :         this->FuelEnergy1 = 0.0;
    6185        49777 :         this->FuelEnergy2 = 0.0;
    6186        49777 :         this->VentEnergy = 0.0;
    6187        49777 :         this->OffCycParaFuelEnergy = 0.0;
    6188        49777 :         this->OffCycParaEnergyToTank = 0.0;
    6189        49777 :         this->OnCycParaFuelEnergy = 0.0;
    6190        49777 :         this->OnCycParaEnergyToTank = 0.0;
    6191        49777 :         this->NetHeatTransferEnergy = 0.0;
    6192              :     }
    6193              : 
    6194      6337420 :     if (!state.dataGlobal->BeginEnvrnFlag) {
    6195      6286370 :         this->MyEnvrnFlag = true;
    6196              :     }
    6197              : 
    6198      6337420 :     if (this->WarmupFlag && (!state.dataGlobal->WarmupFlag)) {
    6199              :         // reInitialize tank temperature to setpoint of first hour (use HPWH or Desuperheater heating coil set point if applicable)
    6200              :         // BG's interpretation here is that its better to reset initial condition to setpoint once warm up is over.
    6201              :         // (otherwise with a dynamic storage model it is difficult for the user to see the initial performance if it isn't periodic.)
    6202          445 :         Sched::Schedule *sched = nullptr;
    6203          445 :         if (this->HeatPumpNum > 0) {
    6204           46 :             state.dataWaterThermalTanks->HPWaterHeater(this->HeatPumpNum).Mode = TankOperatingMode::Floating;
    6205           46 :             sched = state.dataWaterThermalTanks->HPWaterHeater(this->HeatPumpNum).setptTempSched;
    6206          399 :         } else if (this->DesuperheaterNum > 0) {
    6207           12 :             state.dataWaterThermalTanks->WaterHeaterDesuperheater(this->DesuperheaterNum).Mode = TankOperatingMode::Floating;
    6208           12 :             sched = state.dataWaterThermalTanks->WaterHeaterDesuperheater(this->DesuperheaterNum).setptTempSched;
    6209              :         } else {
    6210          387 :             sched = this->setptTempSched;
    6211              :         }
    6212              : 
    6213          445 :         if (sched != nullptr) {
    6214          445 :             this->TankTemp = sched->getCurrentVal();
    6215          445 :             this->SavedTankTemp = this->TankTemp;
    6216              : 
    6217          445 :             if (this->Nodes > 0) {
    6218          316 :                 for (auto &e : this->Node) {
    6219          280 :                     e.Temp = e.SavedTemp = this->TankTemp;
    6220              :                 }
    6221              :             }
    6222              :         } else {
    6223            0 :             this->TankTemp = 20.0;
    6224            0 :             this->SavedTankTemp = this->TankTemp;
    6225              : 
    6226            0 :             if (this->Nodes > 0) {
    6227            0 :                 for (auto &e : this->Node) {
    6228            0 :                     e.Temp = e.SavedTemp = this->TankTemp;
    6229              :                 }
    6230              :             }
    6231              :         }
    6232          445 :         this->SourceOutletTemp = this->SavedTankTemp;
    6233          445 :         this->SavedSourceOutletTemp = this->SavedTankTemp;
    6234          445 :         this->UseOutletTemp = this->SavedTankTemp;
    6235          445 :         this->SavedUseOutletTemp = this->SavedTankTemp;
    6236          445 :         this->SavedHeaterOn1 = false;
    6237          445 :         this->SavedHeaterOn2 = false;
    6238          445 :         this->Mode = TankOperatingMode::Floating;
    6239          445 :         this->SavedMode = TankOperatingMode::Floating;
    6240          445 :         this->WarmupFlag = false;
    6241              :     }
    6242      6337420 :     if (state.dataGlobal->WarmupFlag) {
    6243      5395346 :         this->WarmupFlag = true;
    6244              :     }
    6245              : 
    6246      6337420 :     if (FirstHVACIteration) {
    6247              :         // Get all scheduled values
    6248      3036687 :         this->SetPointTemp = this->setptTempSched->getCurrentVal();
    6249              : 
    6250      3036687 :         if (!this->IsChilledWaterTank) {
    6251      2766386 :             if (this->SetPointTemp > this->TankTempLimit) {
    6252              :                 // Setpoint temperature scheduled higher than maximum tank temperature limit
    6253            0 :                 this->SetPointTemp = this->TankTempLimit - 1.0;
    6254              : 
    6255            0 :                 if (this->ShowSetPointWarning) {
    6256            0 :                     ShowSevereError(
    6257              :                         state,
    6258            0 :                         format("Water heater = {}:  Water heater tank set point temperature is greater than the maximum tank temperature limit.",
    6259            0 :                                this->Name));
    6260            0 :                     ShowContinueErrorTimeStamp(state,
    6261            0 :                                                format("Water heater tank set point temperature is reset to Tank Temperature Limit minus 1 C "
    6262              :                                                       "({:.2T}) and simulation continues.",
    6263            0 :                                                       this->SetPointTemp));
    6264            0 :                     this->ShowSetPointWarning = false;
    6265              :                 }
    6266              :             }
    6267              :         } else {
    6268       270301 :             if (this->SetPointTemp < this->TankTempLimit) {
    6269              :                 // Setpoint temperature scheduled lower than minimum tank temperature limit
    6270            0 :                 this->SetPointTemp = this->TankTempLimit + 1.0;
    6271              : 
    6272            0 :                 if (this->ShowSetPointWarning) {
    6273            0 :                     ShowSevereError(
    6274              :                         state,
    6275            0 :                         format("Chilled Water Tank = {}:  Water heater tank set point temperature is lower than the minimum tank temperature limit.",
    6276            0 :                                this->Name));
    6277            0 :                     ShowContinueErrorTimeStamp(state,
    6278            0 :                                                format("Chilled water tank set point temperature is reset to Tank Temperature Limit plus 1 C "
    6279              :                                                       "({:.2T}) and simulation continues.",
    6280            0 :                                                       this->SetPointTemp));
    6281            0 :                     this->ShowSetPointWarning = false;
    6282              :                 }
    6283              :             }
    6284              :         }
    6285              : 
    6286      3036687 :         if (this->setptTemp2Sched != nullptr) {
    6287       159273 :             this->SetPointTemp2 = this->setptTemp2Sched->getCurrentVal();
    6288              :         }
    6289              : 
    6290      3036687 :         switch (this->AmbientTempIndicator) {
    6291      2273391 :         case WTTAmbientTemp::Schedule: {
    6292      2273391 :             this->AmbientTemp = this->ambientTempSched->getCurrentVal();
    6293      2273391 :         } break;
    6294              : 
    6295       628642 :         case WTTAmbientTemp::TempZone: {
    6296       628642 :             this->AmbientTemp = state.dataZoneTempPredictorCorrector->zoneHeatBalance(this->AmbientTempZone).MAT;
    6297              : 
    6298       628642 :             break;
    6299              :         }
    6300       134654 :         case WTTAmbientTemp::OutsideAir: {
    6301       134654 :             this->AmbientTemp = state.dataLoopNodes->Node(this->AmbientTempOutsideAirNode).Temp;
    6302       134654 :             break;
    6303              :         }
    6304            0 :         default:
    6305            0 :             break;
    6306              :         }
    6307              : 
    6308      3036687 :         if (this->UseInletNode == 0) { // Stand-alone operation
    6309              : 
    6310       203028 :             this->UseInletTemp = (this->useInletTempSched != nullptr) ? this->useInletTempSched->getCurrentVal() : state.dataEnvrn->WaterMainsTemp;
    6311              : 
    6312       203028 :             this->UseMassFlowRate = this->MassFlowRateMax;
    6313       203028 :             if (this->flowRateSched != nullptr) {
    6314       203028 :                 this->UseMassFlowRate *= this->flowRateSched->getCurrentVal();
    6315              :             }
    6316       203028 :             this->VolFlowRate = this->UseMassFlowRate / Psychrometrics::RhoH2O(Constant::InitConvTemp);
    6317              :         }
    6318              : 
    6319      3036687 :         if (this->HeatPumpNum > 0) {
    6320       206578 :             state.dataWaterThermalTanks->HPWaterHeater(this->HeatPumpNum).SetPointTemp =
    6321       206578 :                 state.dataWaterThermalTanks->HPWaterHeater(this->HeatPumpNum).setptTempSched->getCurrentVal();
    6322       206578 :             if (state.dataWaterThermalTanks->HPWaterHeater(this->HeatPumpNum).SetPointTemp >= this->TankTempLimit) {
    6323              :                 // HP setpoint temperature scheduled equal to or higher than tank temperature limit
    6324            0 :                 state.dataWaterThermalTanks->HPWaterHeater(this->HeatPumpNum).SetPointTemp = this->TankTempLimit - 1.0;
    6325              : 
    6326            0 :                 if (state.dataWaterThermalTanks->HPWaterHeater(this->HeatPumpNum).ShowSetPointWarning) {
    6327            0 :                     ShowSevereError(state,
    6328            0 :                                     format("Heat Pump Water Heater = {}:  Heat Pump water heater set point temperature is equal to or greater than "
    6329              :                                            "the maximum tank temperature limit.",
    6330            0 :                                            state.dataWaterThermalTanks->HPWaterHeater(this->HeatPumpNum).Name));
    6331            0 :                     ShowContinueErrorTimeStamp(state,
    6332            0 :                                                format("Heat Pump water heater tank set point temperature is reset to Tank Temperature Limit "
    6333              :                                                       "minus 1 C ({:.2T}) and simulation continues.",
    6334            0 :                                                       state.dataWaterThermalTanks->HPWaterHeater(this->HeatPumpNum).SetPointTemp));
    6335            0 :                     state.dataWaterThermalTanks->HPWaterHeater(this->HeatPumpNum).ShowSetPointWarning = false;
    6336              :                 }
    6337              :             }
    6338              :         }
    6339              : 
    6340      3036687 :         if (this->DesuperheaterNum > 0) {
    6341        14742 :             state.dataWaterThermalTanks->WaterHeaterDesuperheater(this->DesuperheaterNum).SetPointTemp =
    6342        14742 :                 state.dataWaterThermalTanks->WaterHeaterDesuperheater(this->DesuperheaterNum).setptTempSched->getCurrentVal();
    6343              :         }
    6344              : 
    6345              :     } // first HVAC Iteration
    6346              : 
    6347      6337420 :     if (this->UseInletNode > 0 && !this->SetLoopIndexFlag) { // setup mass flows for plant connections
    6348              :         Real64 DeadBandTemp;
    6349      5934824 :         if (this->IsChilledWaterTank) {
    6350       545258 :             DeadBandTemp = this->SetPointTemp + this->DeadBandDeltaTemp;
    6351              :         } else {
    6352      5389566 :             DeadBandTemp = this->SetPointTemp - this->DeadBandDeltaTemp;
    6353              :         }
    6354              : 
    6355     11869648 :         Real64 mdotUse = this->PlantMassFlowRatesFunc(state,
    6356              :                                                       this->UseInletNode,
    6357              :                                                       FirstHVACIteration,
    6358              :                                                       WaterHeaterSide::Use,
    6359              :                                                       this->UseSidePlantLoc.loopSideNum,
    6360      5934824 :                                                       this->UseSideSeries,
    6361              :                                                       this->UseBranchControlType,
    6362              :                                                       this->SavedUseOutletTemp,
    6363              :                                                       DeadBandTemp,
    6364      5934824 :                                                       this->SetPointTemp);
    6365      5934824 :         PlantUtilities::SetComponentFlowRate(state, mdotUse, this->UseInletNode, this->UseOutletNode, this->UseSidePlantLoc);
    6366              : 
    6367      5934824 :         this->UseInletTemp = state.dataLoopNodes->Node(this->UseInletNode).Temp;
    6368      5934824 :         this->UseMassFlowRate = mdotUse;
    6369              :     }
    6370              : 
    6371      6337420 :     if (this->SourceInletNode > 0 && !this->SetLoopIndexFlag) { // setup mass flows for plant connections
    6372              :         Real64 DeadBandTemp;
    6373      1800858 :         if (this->IsChilledWaterTank) {
    6374       410016 :             DeadBandTemp = this->SetPointTemp + this->DeadBandDeltaTemp;
    6375              :         } else {
    6376      1390842 :             DeadBandTemp = this->SetPointTemp - this->DeadBandDeltaTemp;
    6377              :         }
    6378              : 
    6379              :         Real64 sensedTemp;
    6380      1800858 :         if (this->WaterThermalTankType == DataPlant::PlantEquipmentType::ChilledWaterTankStratified) {
    6381       104044 :             int tmpNodeNum = this->HeaterNode1;
    6382       104044 :             sensedTemp = this->Node(tmpNodeNum).SavedTemp;
    6383              :         } else {
    6384      1696814 :             sensedTemp = this->SavedSourceOutletTemp;
    6385              :         }
    6386              : 
    6387      3601716 :         Real64 mdotSource = this->PlantMassFlowRatesFunc(state,
    6388              :                                                          this->SourceInletNode,
    6389              :                                                          FirstHVACIteration,
    6390              :                                                          WaterHeaterSide::Source,
    6391              :                                                          this->SrcSidePlantLoc.loopSideNum,
    6392      1800858 :                                                          this->SourceSideSeries,
    6393              :                                                          this->SourceBranchControlType,
    6394              :                                                          sensedTemp,
    6395              :                                                          DeadBandTemp,
    6396      1800858 :                                                          this->SetPointTemp);
    6397      1800858 :         if (this->SrcSidePlantLoc.loopNum > 0) {
    6398      1362856 :             PlantUtilities::SetComponentFlowRate(state, mdotSource, this->SourceInletNode, this->SourceOutletNode, this->SrcSidePlantLoc);
    6399              :         } else { // not really plant connected (desuperheater or heat pump)
    6400       438002 :             state.dataLoopNodes->Node(this->SourceInletNode).MassFlowRate = mdotSource;
    6401       438002 :             state.dataLoopNodes->Node(this->SourceOutletNode).MassFlowRate = mdotSource;
    6402              :         }
    6403              : 
    6404      1800858 :         this->SourceInletTemp = state.dataLoopNodes->Node(this->SourceInletNode).Temp;
    6405      1800858 :         this->SourceMassFlowRate = mdotSource;
    6406              :     }
    6407              : 
    6408              :     // initialize HPWHs each iteration
    6409      6337420 :     if (this->HeatPumpNum > 0) {
    6410              : 
    6411       408518 :         int HPNum = this->HeatPumpNum;
    6412              : 
    6413       408518 :         if (this->MyHPSizeFlag) {
    6414              :             //     autosize info must be calculated in GetWaterThermalTankInputFlag for use in StandardRating procedure
    6415              :             //       (called at end of GetWaterThermalTankInputFlag)
    6416              :             //     report autosizing information here (must be done after GetWaterThermalTankInputFlag is complete)
    6417           61 :             if (state.dataWaterThermalTanks->HPWaterHeater(HPNum).WaterFlowRateAutoSized &&
    6418           16 :                 (state.dataPlnt->PlantFirstSizesOkayToReport || !state.dataGlobal->AnyPlantInModel || this->AlreadyRated)) {
    6419           16 :                 BaseSizer::reportSizerOutput(state,
    6420            8 :                                              state.dataWaterThermalTanks->HPWaterHeater(HPNum).Type,
    6421            8 :                                              state.dataWaterThermalTanks->HPWaterHeater(HPNum).Name,
    6422              :                                              "Condenser water flow rate [m3/s]",
    6423            8 :                                              state.dataWaterThermalTanks->HPWaterHeater(HPNum).OperatingWaterFlowRate);
    6424              :             }
    6425           65 :             if (state.dataWaterThermalTanks->HPWaterHeater(HPNum).AirFlowRateAutoSized &&
    6426           20 :                 (state.dataPlnt->PlantFirstSizesOkayToReport || !state.dataGlobal->AnyPlantInModel || this->AlreadyRated)) {
    6427           20 :                 BaseSizer::reportSizerOutput(state,
    6428           10 :                                              state.dataWaterThermalTanks->HPWaterHeater(HPNum).Type,
    6429           10 :                                              state.dataWaterThermalTanks->HPWaterHeater(HPNum).Name,
    6430              :                                              "Evaporator air flow rate [m3/s]",
    6431           10 :                                              state.dataWaterThermalTanks->HPWaterHeater(HPNum).OperatingAirFlowRate);
    6432              :             }
    6433           45 :             state.dataSize->DataNonZoneNonAirloopValue = state.dataWaterThermalTanks->HPWaterHeater(HPNum).OperatingAirFlowRate;
    6434           45 :             state.dataWaterThermalTanks->HPWaterHeater(HPNum).OperatingAirMassFlowRate =
    6435           45 :                 state.dataWaterThermalTanks->HPWaterHeater(HPNum).OperatingAirFlowRate * state.dataEnvrn->StdRhoAir;
    6436           45 :             if (state.dataSize->CurZoneEqNum > 0) {
    6437           12 :                 ZoneEqSizing(state.dataSize->CurZoneEqNum).CoolingAirFlow = true;
    6438           12 :                 ZoneEqSizing(state.dataSize->CurZoneEqNum).CoolingAirVolFlow = state.dataSize->DataNonZoneNonAirloopValue;
    6439              :             }
    6440           45 :             if (state.dataPlnt->PlantFirstSizesOkayToReport || !state.dataGlobal->AnyPlantInModel || this->AlreadyRated) {
    6441           23 :                 this->MyHPSizeFlag = false;
    6442              :             }
    6443              :         }
    6444              : 
    6445       408518 :         int HPAirInletNode = state.dataWaterThermalTanks->HPWaterHeater(HPNum).HeatPumpAirInletNode;
    6446       408518 :         int HPAirOutletNode = state.dataWaterThermalTanks->HPWaterHeater(HPNum).HeatPumpAirOutletNode;
    6447       408518 :         int OutdoorAirNode = state.dataWaterThermalTanks->HPWaterHeater(HPNum).OutsideAirNode;
    6448       408518 :         int ExhaustAirNode = state.dataWaterThermalTanks->HPWaterHeater(HPNum).ExhaustAirNode;
    6449       408518 :         int HPWaterInletNode = state.dataWaterThermalTanks->HPWaterHeater(HPNum).CondWaterInletNode;
    6450       408518 :         int HPWaterOutletNode = state.dataWaterThermalTanks->HPWaterHeater(HPNum).CondWaterOutletNode;
    6451       408518 :         int InletAirMixerNode = state.dataWaterThermalTanks->HPWaterHeater(HPNum).InletAirMixerNode;
    6452       408518 :         int OutletAirSplitterNode = state.dataWaterThermalTanks->HPWaterHeater(HPNum).OutletAirSplitterNode;
    6453              : 
    6454       408518 :         switch (state.dataWaterThermalTanks->HPWaterHeater(HPNum).CrankcaseTempIndicator) {
    6455       183624 :         case CrankcaseHeaterControlTemp::Zone: {
    6456       367248 :             state.dataHVACGlobal->HPWHCrankcaseDBTemp =
    6457       183624 :                 state.dataZoneTempPredictorCorrector->zoneHeatBalance(state.dataWaterThermalTanks->HPWaterHeater(HPNum).AmbientTempZone).MAT;
    6458       183624 :             break;
    6459              :         }
    6460       208978 :         case CrankcaseHeaterControlTemp::Outdoors: {
    6461       208978 :             state.dataHVACGlobal->HPWHCrankcaseDBTemp = state.dataEnvrn->OutDryBulbTemp;
    6462       208978 :             break;
    6463              :         }
    6464        15916 :         case CrankcaseHeaterControlTemp::Schedule: {
    6465        15916 :             state.dataHVACGlobal->HPWHCrankcaseDBTemp = state.dataWaterThermalTanks->HPWaterHeater(HPNum).crankcaseTempSched->getCurrentVal();
    6466        15916 :             break;
    6467              :         }
    6468            0 :         default:
    6469            0 :             break;
    6470              :         }
    6471              : 
    6472              :         //   initialize HPWH report variables to 0 and set tank inlet node equal to outlet node
    6473       408518 :         state.dataWaterThermalTanks->HPWaterHeater(HPNum).HPWaterHeaterSensibleCapacity = 0.0;
    6474       408518 :         state.dataWaterThermalTanks->HPWaterHeater(HPNum).HPWaterHeaterLatentCapacity = 0.0;
    6475       408518 :         this->SourceMassFlowRate = 0.0;
    6476       408518 :         state.dataWaterThermalTanks->HPWaterHeater(HPNum).HeatingPLR = 0.0;
    6477       408518 :         this->SourceInletTemp = this->SourceOutletTemp;
    6478              : 
    6479              :         //   determine HPWH inlet air conditions based on inlet air configuration (Zone, ZoneAndOA, OutdoorAir, or Schedule)
    6480       408518 :         Real64 HPInletDryBulbTemp = 0.0;
    6481       408518 :         Real64 HPInletHumRat = 0.0;
    6482              :         Real64 HPInletRelHum;
    6483       408518 :         switch (state.dataWaterThermalTanks->HPWaterHeater(HPNum).InletAirConfiguration) {
    6484       167586 :         case WTTAmbientTemp::TempZone: {
    6485       167586 :             state.dataWaterThermalTanks->mixerInletAirSchedule = 0.0;
    6486       167586 :             HPInletDryBulbTemp = state.dataLoopNodes->Node(HPAirInletNode).Temp;
    6487       167586 :             HPInletHumRat = state.dataLoopNodes->Node(HPAirInletNode).HumRat;
    6488       167586 :             break;
    6489              :         }
    6490        16038 :         case WTTAmbientTemp::ZoneAndOA: {
    6491        16038 :             if (state.dataWaterThermalTanks->HPWaterHeater(HPNum).inletAirMixerSched != nullptr) {
    6492              :                 //         schedule values are checked for boundary of 0 and 1 in GetWaterThermalTankInputFlag
    6493        16038 :                 state.dataWaterThermalTanks->mixerInletAirSchedule =
    6494        16038 :                     state.dataWaterThermalTanks->HPWaterHeater(HPNum).inletAirMixerSched->getCurrentVal();
    6495              :             } else {
    6496            0 :                 state.dataWaterThermalTanks->mixerInletAirSchedule = 0.0;
    6497              :             }
    6498        16038 :             HPInletDryBulbTemp = state.dataWaterThermalTanks->mixerInletAirSchedule * state.dataLoopNodes->Node(OutdoorAirNode).Temp +
    6499        16038 :                                  (1.0 - state.dataWaterThermalTanks->mixerInletAirSchedule) * state.dataLoopNodes->Node(HPAirInletNode).Temp;
    6500        16038 :             HPInletHumRat = state.dataWaterThermalTanks->mixerInletAirSchedule * state.dataLoopNodes->Node(OutdoorAirNode).HumRat +
    6501        16038 :                             (1.0 - state.dataWaterThermalTanks->mixerInletAirSchedule) * state.dataLoopNodes->Node(HPAirInletNode).HumRat;
    6502        16038 :             break;
    6503              :         }
    6504       208978 :         case WTTAmbientTemp::OutsideAir: {
    6505       208978 :             state.dataWaterThermalTanks->mixerInletAirSchedule = 1.0;
    6506       208978 :             HPInletDryBulbTemp = state.dataLoopNodes->Node(OutdoorAirNode).Temp;
    6507       208978 :             HPInletHumRat = state.dataLoopNodes->Node(OutdoorAirNode).HumRat;
    6508              : 
    6509       208978 :             break;
    6510              :         }
    6511        15916 :         case WTTAmbientTemp::Schedule: {
    6512        15916 :             HPInletDryBulbTemp = state.dataWaterThermalTanks->HPWaterHeater(HPNum).ambientTempSched->getCurrentVal();
    6513        15916 :             HPInletRelHum = state.dataWaterThermalTanks->HPWaterHeater(HPNum).ambientRHSched->getCurrentVal();
    6514        15916 :             HPInletHumRat = Psychrometrics::PsyWFnTdbRhPb(state, HPInletDryBulbTemp, HPInletRelHum, state.dataEnvrn->OutBaroPress, RoutineName);
    6515        15916 :             state.dataLoopNodes->Node(HPAirInletNode).Temp = HPInletDryBulbTemp;
    6516        15916 :             state.dataLoopNodes->Node(HPAirInletNode).HumRat = HPInletHumRat;
    6517        15916 :             state.dataLoopNodes->Node(HPAirInletNode).Enthalpy = Psychrometrics::PsyHFnTdbW(HPInletDryBulbTemp, HPInletHumRat);
    6518        15916 :             state.dataLoopNodes->Node(HPAirInletNode).Press = state.dataEnvrn->OutBaroPress;
    6519              : 
    6520        15916 :             break;
    6521              :         }
    6522            0 :         default:
    6523            0 :             assert(false);
    6524              :             break;
    6525              :         }
    6526              : 
    6527       408518 :         state.dataWaterThermalTanks->mdotAir = state.dataWaterThermalTanks->HPWaterHeater(HPNum).OperatingAirMassFlowRate;
    6528              : 
    6529              :         //   set up initial conditions on nodes
    6530       408518 :         if (InletAirMixerNode > 0) {
    6531        16038 :             state.dataLoopNodes->Node(InletAirMixerNode).MassFlowRate = 0.0;
    6532        16038 :             state.dataLoopNodes->Node(InletAirMixerNode).MassFlowRateMax = state.dataWaterThermalTanks->mdotAir;
    6533        16038 :             state.dataLoopNodes->Node(InletAirMixerNode).MassFlowRateMaxAvail = state.dataWaterThermalTanks->mdotAir;
    6534        16038 :             state.dataLoopNodes->Node(InletAirMixerNode).Temp = HPInletDryBulbTemp;
    6535        16038 :             state.dataLoopNodes->Node(InletAirMixerNode).HumRat = HPInletHumRat;
    6536        16038 :             state.dataLoopNodes->Node(InletAirMixerNode).Enthalpy = Psychrometrics::PsyHFnTdbW(HPInletDryBulbTemp, HPInletHumRat);
    6537        16038 :             state.dataLoopNodes->Node(HPAirInletNode).MassFlowRate = 0.0;
    6538        16038 :             state.dataLoopNodes->Node(HPAirOutletNode).MassFlowRate = 0.0;
    6539        16038 :             state.dataLoopNodes->Node(OutdoorAirNode).MassFlowRate = 0.0;
    6540        16038 :             state.dataLoopNodes->Node(ExhaustAirNode).MassFlowRate = 0.0;
    6541              :         } else {
    6542       392480 :             if (OutdoorAirNode == 0) {
    6543       183502 :                 state.dataLoopNodes->Node(HPAirInletNode).MassFlowRate = 0.0;
    6544       183502 :                 state.dataLoopNodes->Node(HPAirInletNode).MassFlowRateMax = state.dataWaterThermalTanks->mdotAir;
    6545       183502 :                 state.dataLoopNodes->Node(HPAirInletNode).MassFlowRateMaxAvail = state.dataWaterThermalTanks->mdotAir;
    6546       183502 :                 state.dataLoopNodes->Node(HPAirOutletNode).MassFlowRate = 0.0;
    6547              :             } else {
    6548       208978 :                 state.dataLoopNodes->Node(OutdoorAirNode).MassFlowRate = 0.0;
    6549       208978 :                 state.dataLoopNodes->Node(OutdoorAirNode).MassFlowRateMax = state.dataWaterThermalTanks->mdotAir;
    6550       208978 :                 state.dataLoopNodes->Node(OutdoorAirNode).MassFlowRateMaxAvail = state.dataWaterThermalTanks->mdotAir;
    6551       208978 :                 state.dataLoopNodes->Node(ExhaustAirNode).MassFlowRate = 0.0;
    6552              :             }
    6553              :         }
    6554              : 
    6555       408518 :         if (OutletAirSplitterNode > 0) {
    6556        16038 :             state.dataLoopNodes->Node(OutletAirSplitterNode).MassFlowRate = 0.0;
    6557              :         }
    6558              :         // these are water nodes are not managed by plant. the HP connects
    6559              :         // directly to the WH without using plant.
    6560       408518 :         if (state.dataWaterThermalTanks->HPWaterHeater(HPNum).HPWHType == DataPlant::PlantEquipmentType::HeatPumpWtrHeaterPumped) {
    6561       304563 :             state.dataLoopNodes->Node(HPWaterInletNode).MassFlowRate = 0.0;
    6562       304563 :             state.dataLoopNodes->Node(HPWaterOutletNode).MassFlowRate = 0.0;
    6563              :         }
    6564              : 
    6565              :         //   set the max mass flow rate for outdoor fans
    6566       408518 :         state.dataLoopNodes->Node(state.dataWaterThermalTanks->HPWaterHeater(HPNum).FanOutletNode).MassFlowRateMax =
    6567       408518 :             state.dataWaterThermalTanks->mdotAir;
    6568              : 
    6569              :         //   Curve objects in DXCoils::CalcHPWHDXCoil will use inlet conditions to HPWH not inlet air conditions to DX Coil
    6570              :         //   HPWHInletDBTemp and HPWHInletWBTemp are DataHVACGlobals to pass info to HPWHDXCoil
    6571       408518 :         state.dataHVACGlobal->HPWHInletDBTemp = HPInletDryBulbTemp;
    6572       817036 :         state.dataHVACGlobal->HPWHInletWBTemp =
    6573       408518 :             Psychrometrics::PsyTwbFnTdbWPb(state, state.dataHVACGlobal->HPWHInletDBTemp, HPInletHumRat, state.dataEnvrn->OutBaroPress);
    6574              : 
    6575              :         // initialize flow rates at speed levels for variable-speed HPWH
    6576       418564 :         if ((state.dataWaterThermalTanks->HPWaterHeater(HPNum).bIsIHP) &&
    6577        10046 :             (0 == state.dataWaterThermalTanks->HPWaterHeater(HPNum).NumofSpeed)) // use SCWH coil represents
    6578              :         {
    6579            1 :             IntegratedHeatPump::SizeIHP(state, state.dataWaterThermalTanks->HPWaterHeater(HPNum).DXCoilNum); //
    6580              :             // IntegratedHeatPump::SimIHP(modBlankString, HPWaterHeater(HPNum).DXCoilNum,
    6581              :             //    0, EMP1, EMP2, EMP3, 0, 0.0, 1, 0.0, 0.0, 0.0, false, 0.0); //conduct the sizing operation in the IHP
    6582            1 :             int VSCoilID = state.dataIntegratedHP->IntegratedHeatPumps(state.dataWaterThermalTanks->HPWaterHeater(HPNum).DXCoilNum).SCWHCoilIndex;
    6583            1 :             state.dataWaterThermalTanks->HPWaterHeater(HPNum).NumofSpeed = state.dataVariableSpeedCoils->VarSpeedCoil(VSCoilID).NumOfSpeeds;
    6584              : 
    6585       408517 :         } else if (Util::SameString(state.dataWaterThermalTanks->HPWaterHeater(HPNum).DXCoilType,
    6586       463795 :                                     "Coil:WaterHeating:AirToWaterHeatPump:VariableSpeed") &&
    6587        55278 :                    (state.dataWaterThermalTanks->HPWaterHeater(HPNum).NumofSpeed == 0)) {
    6588            6 :             VariableSpeedCoils::SimVariableSpeedCoils(state,
    6589            6 :                                                       std::string(),
    6590            6 :                                                       state.dataWaterThermalTanks->HPWaterHeater(HPNum).DXCoilNum,
    6591              :                                                       HVAC::FanOp::Invalid, // Invalid instead of off?
    6592              :                                                       HVAC::CompressorOp::Off,
    6593              :                                                       0.0,
    6594              :                                                       1,
    6595              :                                                       0.0,
    6596              :                                                       0.0,
    6597              :                                                       0.0,
    6598              :                                                       0.0); // conduct the sizing operation in the VS WSHP
    6599            6 :             int VSCoilID = state.dataWaterThermalTanks->HPWaterHeater(HPNum).DXCoilNum;
    6600            6 :             state.dataWaterThermalTanks->HPWaterHeater(HPNum).NumofSpeed = state.dataVariableSpeedCoils->VarSpeedCoil(VSCoilID).NumOfSpeeds;
    6601              :             // below pass the flow rates from the VS coil to the water heater object
    6602              :         }
    6603              : 
    6604       408518 :         if (state.dataWaterThermalTanks->HPWaterHeater(HPNum).NumofSpeed > 0) {
    6605              :             int VSCoilID;
    6606        65324 :             if (state.dataWaterThermalTanks->HPWaterHeater(HPNum).bIsIHP) {
    6607        10046 :                 VSCoilID = state.dataIntegratedHP->IntegratedHeatPumps(state.dataWaterThermalTanks->HPWaterHeater(HPNum).DXCoilNum).SCWHCoilIndex;
    6608              :             } else {
    6609        55278 :                 VSCoilID = state.dataWaterThermalTanks->HPWaterHeater(HPNum).DXCoilNum;
    6610              :             }
    6611              : 
    6612              :             // scale air flow rates
    6613        65324 :             Real64 MulSpeedFlowScale = state.dataVariableSpeedCoils->VarSpeedCoil(VSCoilID).RatedAirVolFlowRate /
    6614        65324 :                                        state.dataVariableSpeedCoils->VarSpeedCoil(VSCoilID).MSRatedAirVolFlowRate(
    6615        65324 :                                            state.dataVariableSpeedCoils->VarSpeedCoil(VSCoilID).NormSpedLevel);
    6616       718564 :             for (int Iter = 1; Iter <= state.dataWaterThermalTanks->HPWaterHeater(HPNum).NumofSpeed; ++Iter) {
    6617       653240 :                 state.dataWaterThermalTanks->HPWaterHeater(HPNum).HPWHAirVolFlowRate(Iter) =
    6618       653240 :                     state.dataVariableSpeedCoils->VarSpeedCoil(VSCoilID).MSRatedAirVolFlowRate(Iter) * MulSpeedFlowScale;
    6619              :             }
    6620              : 
    6621              :             // check fan flow rate, should be larger than the max flow rate of the VS coil
    6622        65324 :             Real64 FanVolFlow = state.dataFans->fans(state.dataWaterThermalTanks->HPWaterHeater(HPNum).FanNum)->maxAirFlowRate;
    6623              : 
    6624       130648 :             if (FanVolFlow < state.dataWaterThermalTanks->HPWaterHeater(HPNum).HPWHAirVolFlowRate(
    6625        65324 :                                  state.dataWaterThermalTanks->HPWaterHeater(HPNum).NumofSpeed)) { // but this is the not the scaled mas flow
    6626              :                 // if ( FanVolFlow  < HPWaterHeater( HPNum ).HPWHAirVolFlowRate( HPWaterHeater( HPNum ).NumofSpeed ) ) {
    6627              : 
    6628            0 :                 ShowWarningError(state,
    6629            0 :                                  format("InitWaterThermalTank: -air flow rate = {:.7T} in fan object  is less than the MSHP system air flow rate "
    6630              :                                         "when waterheating is required({:.7T}).",
    6631              :                                         FanVolFlow,
    6632            0 :                                         state.dataWaterThermalTanks->HPWaterHeater(HPNum).HPWHAirVolFlowRate(
    6633            0 :                                             state.dataWaterThermalTanks->HPWaterHeater(HPNum).NumofSpeed)));
    6634            0 :                 ShowContinueError(state,
    6635              :                                   " The MSHP system flow rate when waterheating is required is reset to the"
    6636              :                                   " fan flow rate and the simulation continues.");
    6637            0 :                 ShowContinueError(state, format(" Occurs in {}", state.dataWaterThermalTanks->HPWaterHeater(HPNum).Name));
    6638            0 :                 state.dataWaterThermalTanks->HPWaterHeater(HPNum).HPWHAirVolFlowRate(state.dataWaterThermalTanks->HPWaterHeater(HPNum).NumofSpeed) =
    6639              :                     FanVolFlow;
    6640              :                 // Check flow rates in other speeds and ensure flow rates are not above the max flow rate
    6641            0 :                 for (int Iter = state.dataWaterThermalTanks->HPWaterHeater(HPNum).NumofSpeed - 1; Iter >= 1; --Iter) {
    6642            0 :                     if (state.dataWaterThermalTanks->HPWaterHeater(HPNum).HPWHAirVolFlowRate(Iter) >
    6643            0 :                         state.dataWaterThermalTanks->HPWaterHeater(HPNum).HPWHAirVolFlowRate(Iter + 1)) {
    6644            0 :                         ShowContinueError(state,
    6645            0 :                                           format(" The MSHP system flow rate when waterheating is required is reset to the flow rate at higher "
    6646              :                                                  "speed and the simulation continues at Speed{}.",
    6647              :                                                  Iter));
    6648            0 :                         ShowContinueError(state, format(" Occurs in {}", state.dataWaterThermalTanks->HPWaterHeater(HPNum).Name));
    6649            0 :                         state.dataWaterThermalTanks->HPWaterHeater(HPNum).HPWHAirVolFlowRate(Iter) =
    6650            0 :                             state.dataWaterThermalTanks->HPWaterHeater(HPNum).HPWHAirVolFlowRate(Iter + 1);
    6651              :                     }
    6652              :                 }
    6653              :             }
    6654              : 
    6655       718564 :             for (int Iter = 1; Iter <= state.dataWaterThermalTanks->HPWaterHeater(HPNum).NumofSpeed; ++Iter) {
    6656       653240 :                 state.dataWaterThermalTanks->HPWaterHeater(HPNum).MSAirSpeedRatio(Iter) =
    6657       653240 :                     state.dataWaterThermalTanks->HPWaterHeater(HPNum).HPWHAirVolFlowRate(Iter) /
    6658      1306480 :                     state.dataWaterThermalTanks->HPWaterHeater(HPNum).HPWHAirVolFlowRate(
    6659       653240 :                         state.dataWaterThermalTanks->HPWaterHeater(HPNum).NumofSpeed);
    6660              :             }
    6661              : 
    6662              :             // scale water flow rates
    6663        65324 :             MulSpeedFlowScale = state.dataVariableSpeedCoils->VarSpeedCoil(VSCoilID).RatedWaterVolFlowRate /
    6664        65324 :                                 state.dataVariableSpeedCoils->VarSpeedCoil(VSCoilID).MSRatedWaterVolFlowRate(
    6665        65324 :                                     state.dataVariableSpeedCoils->VarSpeedCoil(VSCoilID).NormSpedLevel);
    6666       718564 :             for (int Iter = 1; Iter <= state.dataWaterThermalTanks->HPWaterHeater(HPNum).NumofSpeed; ++Iter) {
    6667       653240 :                 state.dataWaterThermalTanks->HPWaterHeater(HPNum).HPWHWaterVolFlowRate(Iter) =
    6668       653240 :                     state.dataVariableSpeedCoils->VarSpeedCoil(VSCoilID).MSRatedWaterVolFlowRate(Iter) * MulSpeedFlowScale;
    6669       653240 :                 state.dataWaterThermalTanks->HPWaterHeater(HPNum).HPWHWaterMassFlowRate(Iter) =
    6670       653240 :                     state.dataVariableSpeedCoils->VarSpeedCoil(VSCoilID).MSRatedWaterMassFlowRate(Iter) * MulSpeedFlowScale;
    6671       653240 :                 state.dataWaterThermalTanks->HPWaterHeater(HPNum).MSWaterSpeedRatio(Iter) =
    6672       653240 :                     state.dataVariableSpeedCoils->VarSpeedCoil(VSCoilID).MSRatedWaterVolFlowRate(Iter) /
    6673      1306480 :                     state.dataVariableSpeedCoils->VarSpeedCoil(VSCoilID).MSRatedWaterVolFlowRate(
    6674       653240 :                         state.dataWaterThermalTanks->HPWaterHeater(HPNum).NumofSpeed);
    6675              :             }
    6676              : 
    6677        65324 :             Real64 rhoAir = Psychrometrics::PsyRhoAirFnPbTdbW(state, state.dataEnvrn->OutBaroPress, HPInletDryBulbTemp, HPInletHumRat);
    6678              : 
    6679       718564 :             for (int Iter = 1; Iter <= state.dataWaterThermalTanks->HPWaterHeater(HPNum).NumofSpeed; ++Iter) {
    6680       653240 :                 state.dataWaterThermalTanks->HPWaterHeater(HPNum).HPWHAirMassFlowRate(Iter) =
    6681       653240 :                     state.dataWaterThermalTanks->HPWaterHeater(HPNum).HPWHAirVolFlowRate(Iter) * rhoAir;
    6682              :             }
    6683              : 
    6684              :             //   set the max mass flow rate for outdoor fans
    6685        65324 :             state.dataLoopNodes->Node(state.dataWaterThermalTanks->HPWaterHeater(HPNum).FanOutletNode).MassFlowRateMax =
    6686        65324 :                 state.dataWaterThermalTanks->HPWaterHeater(HPNum).HPWHAirMassFlowRate(state.dataWaterThermalTanks->HPWaterHeater(HPNum).NumofSpeed);
    6687              :         }
    6688              : 
    6689              :     } //  IF(WaterThermalTank(WaterThermalTankNum)%HeatPumpNum .GT. 0)THEN
    6690              : 
    6691              :     // calling CalcStandardRatings early bypasses fan sizing since DataSizing::DataNonZoneNonAirloopValue has not been set yet
    6692      6337420 :     if (!this->AlreadyRated) {
    6693          297 :         if (this->IsChilledWaterTank) {
    6694            6 :             this->AlreadyRated = true;
    6695              :         } else {
    6696          395 :             if (!state.dataGlobal->AnyPlantInModel || state.dataPlnt->PlantFirstSizesOkayToReport || this->MaxCapacity > 0.0 ||
    6697          104 :                 this->HeatPumpNum > 0) {
    6698          189 :                 this->CalcStandardRatings(state);
    6699              :             }
    6700              :         }
    6701              :     }
    6702      6337420 : }
    6703              : 
    6704      6551906 : void WaterThermalTankData::CalcWaterThermalTankMixed(EnergyPlusData &state) // Water Heater being simulated
    6705              : {
    6706              : 
    6707              :     // SUBROUTINE INFORMATION:
    6708              :     //       AUTHOR         Peter Graham Ellis
    6709              :     //       DATE WRITTEN   January 2005
    6710              :     //       MODIFIED       na
    6711              :     //       RE-ENGINEERED  na
    6712              : 
    6713              :     // PURPOSE OF THIS SUBROUTINE:
    6714              :     // Simulates a well-mixed, single node water heater tank.
    6715              : 
    6716              :     // METHODOLOGY EMPLOYED:
    6717              :     // This model uses analytical calculations based on the differential equation describing the tank energy
    6718              :     // balance.  The model operates in three different modes:  heating, floating, and venting.  Temperatures and
    6719              :     // energies change dynamically over the timestep.  The final reported tank temperature is the average over
    6720              :     // the timestep.  The final reported heat rates are averages based on the total energy transfer over the
    6721              :     // timestep.
    6722              : 
    6723              :     static constexpr std::string_view RoutineName("CalcWaterThermalTankMixed");
    6724              : 
    6725              :     Real64 TimeElapsed_loc =
    6726      6551906 :         state.dataGlobal->HourOfDay + state.dataGlobal->TimeStep * state.dataGlobal->TimeStepZone + state.dataHVACGlobal->SysTimeElapsed;
    6727              : 
    6728      6551906 :     if (this->TimeElapsed != TimeElapsed_loc) {
    6729              :         // The simulation has advanced to the next system DataGlobals::TimeStep.  Save conditions from the end of the previous system
    6730              :         // DataGlobals::TimeStep for use as the initial conditions of each iteration that does not advance the system DataGlobals::TimeStep.
    6731       594372 :         this->SavedTankTemp = this->TankTemp;
    6732       594372 :         this->SavedMode = this->Mode;
    6733              : 
    6734              :         // Save outlet temperatures for demand-side flow control
    6735       594372 :         this->SavedUseOutletTemp = this->UseOutletTemp;
    6736       594372 :         this->SavedSourceOutletTemp = this->SourceOutletTemp;
    6737              : 
    6738       594372 :         this->TimeElapsed = TimeElapsed_loc;
    6739              :     }
    6740              : 
    6741      6551906 :     Real64 TankTemp_loc = this->SavedTankTemp;
    6742      6551906 :     TankOperatingMode Mode_loc = this->SavedMode;
    6743              : 
    6744      6551906 :     Real64 Qmaxcap = this->MaxCapacity;
    6745      6551906 :     Real64 Qmincap = this->MinCapacity;
    6746      6551906 :     Real64 Qoffcycfuel = this->OffCycParaLoad;
    6747      6551906 :     Real64 Qoffcycheat = Qoffcycfuel * this->OffCycParaFracToTank;
    6748      6551906 :     Real64 Qoncycfuel = this->OnCycParaLoad;
    6749      6551906 :     Real64 Qoncycheat = Qoncycfuel * this->OnCycParaFracToTank;
    6750              : 
    6751      6551906 :     Real64 SetPointTemp_loc = this->SetPointTemp;
    6752      6551906 :     Real64 DeadBandTemp = this->getDeadBandTemp();
    6753      6551906 :     Real64 MaxTemp = this->TankTempLimit;
    6754      6551906 :     Real64 AmbientTemp_loc = this->AmbientTemp;
    6755              : 
    6756      6551906 :     Real64 UseInletTemp_loc = this->UseInletTemp;
    6757      6551906 :     Real64 UseMassFlowRate_loc = this->UseMassFlowRate * this->UseEffectiveness;
    6758      6551906 :     Real64 SourceInletTemp_loc = this->SourceInletTemp;
    6759      6551906 :     Real64 SourceMassFlowRate_loc = this->SourceMassFlowRate * this->SourceEffectiveness;
    6760              : 
    6761              :     Real64 rho;
    6762      6551906 :     if (this->UseSidePlantLoc.loopNum > 0) {
    6763      6040675 :         rho = state.dataPlnt->PlantLoop(this->UseSidePlantLoc.loopNum).glycol->getDensity(state, TankTemp_loc, RoutineName);
    6764              :     } else {
    6765       511231 :         rho = this->water->getDensity(state, TankTemp_loc, RoutineName);
    6766              :     }
    6767              : 
    6768      6551906 :     Real64 TankMass = rho * this->Volume;
    6769              : 
    6770              :     Real64 Cp;
    6771      6551906 :     if (this->UseSidePlantLoc.loopNum > 0) {
    6772      6040675 :         Cp = state.dataPlnt->PlantLoop(this->UseSidePlantLoc.loopNum).glycol->getSpecificHeat(state, TankTemp_loc, RoutineName);
    6773              :     } else {
    6774       511231 :         Cp = this->water->getSpecificHeat(state, TankTemp_loc, RoutineName);
    6775              :     }
    6776              : 
    6777      6551906 :     Real64 SecInTimeStep = state.dataHVACGlobal->TimeStepSysSec;
    6778      6551906 :     Real64 TimeRemaining = SecInTimeStep;
    6779      6551906 :     int CycleOnCount_loc = 0;
    6780      6551906 :     int MaxCycles = SecInTimeStep;
    6781      6551906 :     Real64 Runtime = 0.0;
    6782      6551906 :     bool SetPointRecovered = false;
    6783              : 
    6784      6551906 :     Real64 Tsum = 0.0;
    6785      6551906 :     Real64 Eloss = 0.0;
    6786      6551906 :     Real64 Elosszone = 0.0;
    6787      6551906 :     Real64 Euse = 0.0;
    6788      6551906 :     Real64 Esource = 0.0;
    6789      6551906 :     Real64 Eheater = 0.0;
    6790      6551906 :     Real64 Event = 0.0;
    6791      6551906 :     Real64 Eneeded = 0.0;
    6792      6551906 :     Real64 Eunmet = 0.0;
    6793      6551906 :     Real64 Efuel = 0.0;
    6794      6551906 :     Real64 Eoncycfuel = 0.0;
    6795      6551906 :     Real64 Eoffcycfuel = 0.0;
    6796      6551906 :     Real64 PLR = 0.0;
    6797      6551906 :     Real64 PLRsum = 0.0;
    6798              : 
    6799      6551906 :     Real64 Qheat = 0.0;
    6800      6551906 :     Real64 Qheater = 0.0;
    6801      6551906 :     Real64 Qvent = 0.0;
    6802      6551906 :     Real64 Qneeded = 0.0;
    6803      6551906 :     Real64 Qunmet = 0.0;
    6804      6551906 :     Real64 Qfuel = 0.0;
    6805              : 
    6806              :     // Calculate the heating rate from the heat pump.
    6807      6551906 :     Real64 HPWHCondenserDeltaT = 0.0;
    6808              : 
    6809      6551906 :     if (this->HeatPumpNum > 0) {
    6810       811623 :         HeatPumpWaterHeaterData const &HeatPump = state.dataWaterThermalTanks->HPWaterHeater(this->HeatPumpNum);
    6811       811623 :         DataLoopNode::NodeData const &HPWHCondWaterInletNode = state.dataLoopNodes->Node(HeatPump.CondWaterInletNode);
    6812       811623 :         DataLoopNode::NodeData const &HPWHCondWaterOutletNode = state.dataLoopNodes->Node(HeatPump.CondWaterOutletNode);
    6813       811623 :         HPWHCondenserDeltaT = HPWHCondWaterOutletNode.Temp - HPWHCondWaterInletNode.Temp;
    6814              :     }
    6815      6551906 :     assert(HPWHCondenserDeltaT >= 0);
    6816              : 
    6817              :     Real64 Qheatpump;
    6818              :     Real64 Qsource;
    6819      6551906 :     EnergyPlus::WaterThermalTanks::WaterThermalTankData::CalcMixedTankSourceSideHeatTransferRate(
    6820              :         HPWHCondenserDeltaT, SourceInletTemp_loc, Cp, SetPointTemp_loc, SourceMassFlowRate_loc, Qheatpump, Qsource);
    6821              : 
    6822              :     // Calculate steady-state use heat rate.
    6823      6551906 :     Real64 Quse = UseMassFlowRate_loc * Cp * (UseInletTemp_loc - SetPointTemp_loc);
    6824      6551906 :     Real64 Qloss = 0.0, PLF = 0.0;
    6825              : 
    6826     24956299 :     while (TimeRemaining > 0.0) {
    6827              : 
    6828     18404393 :         Real64 TimeNeeded = 0.0;
    6829              : 
    6830     18404393 :         Real64 NewTankTemp = TankTemp_loc;
    6831     18404393 :         Real64 LossCoeff_loc = 0.0;
    6832     18404393 :         Real64 LossFracToZone = 0.0;
    6833              : 
    6834     18404393 :         switch (Mode_loc) {
    6835              : 
    6836      8308633 :         case TankOperatingMode::Heating: // Heater is on
    6837              : 
    6838              :             // Calculate heat rate needed to maintain the setpoint at steady-state conditions
    6839      8308633 :             LossCoeff_loc = this->OnCycLossCoeff;
    6840      8308633 :             LossFracToZone = this->OnCycLossFracToZone;
    6841      8308633 :             Qloss = LossCoeff_loc * (AmbientTemp_loc - SetPointTemp_loc);
    6842      8308633 :             Qneeded = -Quse - Qsource - Qloss - Qoncycheat;
    6843              : 
    6844      8308633 :             if (TankTemp_loc > SetPointTemp_loc) {
    6845              :                 // Heater is not needed after all, possibly due to step change in scheduled SetPointTemp
    6846              : 
    6847            8 :                 Qheater = 0.0;
    6848            8 :                 Qunmet = 0.0;
    6849            8 :                 Mode_loc = TankOperatingMode::Floating;
    6850            8 :                 continue;
    6851              : 
    6852      8308625 :             } else if (TankTemp_loc < SetPointTemp_loc) {
    6853              :                 // Attempt to recover to the setpoint as quickly as possible by using maximum heater capacity
    6854              : 
    6855              :                 // Qneeded is calculated above
    6856              :                 // Qneeded does not account for the extra energy needed to recover to the setpoint
    6857      4390322 :                 Qheater = Qmaxcap;
    6858      4390322 :                 Qunmet = max(Qneeded - Qheater, 0.0);
    6859      4390322 :                 Qheat = Qoncycheat + Qheater + Qheatpump;
    6860              : 
    6861              :                 // Calculate time needed to recover to the setpoint at maximum heater capacity
    6862      4390322 :                 TimeNeeded = EnergyPlus::WaterThermalTanks::WaterThermalTankData::CalcTimeNeeded(TankTemp_loc,
    6863              :                                                                                                  SetPointTemp_loc,
    6864              :                                                                                                  AmbientTemp_loc,
    6865              :                                                                                                  UseInletTemp_loc,
    6866              :                                                                                                  SourceInletTemp_loc,
    6867              :                                                                                                  TankMass,
    6868              :                                                                                                  Cp,
    6869              :                                                                                                  UseMassFlowRate_loc,
    6870              :                                                                                                  SourceMassFlowRate_loc,
    6871              :                                                                                                  LossCoeff_loc,
    6872              :                                                                                                  Qheat);
    6873              : 
    6874      4390322 :                 if (TimeNeeded > TimeRemaining) {
    6875              :                     // Heater is at maximum capacity and heats for all of the remaining time
    6876              :                     // Setpoint temperature WILL NOT be recovered
    6877              : 
    6878       523901 :                     TimeNeeded = TimeRemaining;
    6879              : 
    6880       523901 :                     NewTankTemp = EnergyPlus::WaterThermalTanks::WaterThermalTankData::CalcTankTemp(TankTemp_loc,
    6881              :                                                                                                     AmbientTemp_loc,
    6882              :                                                                                                     UseInletTemp_loc,
    6883              :                                                                                                     SourceInletTemp_loc,
    6884              :                                                                                                     TankMass,
    6885              :                                                                                                     Cp,
    6886              :                                                                                                     UseMassFlowRate_loc,
    6887              :                                                                                                     SourceMassFlowRate_loc,
    6888              :                                                                                                     LossCoeff_loc,
    6889              :                                                                                                     Qheat,
    6890              :                                                                                                     TimeNeeded);
    6891              : 
    6892              :                 } else { // TimeNeeded <= TimeRemaining
    6893              :                     // Heater is at maximum capacity but will not heat for all of the remaining time (at maximum anyway)
    6894              :                     // Setpoint temperature WILL be recovered
    6895              : 
    6896      3866421 :                     NewTankTemp = SetPointTemp_loc;
    6897              : 
    6898      3866421 :                     SetPointRecovered = true;
    6899              : 
    6900              :                 } // TimeNeeded > TimeRemaining
    6901              : 
    6902              :             } else { // TankTemp == SetPointTemp
    6903              :                 // Attempt to maintain the setpoint by using the needed heater capacity (modulating, if allowed)
    6904              : 
    6905      3918303 :                 if (Qneeded <= 0.0) {
    6906              :                     // Heater is not needed
    6907              : 
    6908         9256 :                     Qneeded = 0.0;
    6909         9256 :                     Qheater = 0.0;
    6910         9256 :                     Qunmet = 0.0;
    6911         9256 :                     Mode_loc = TankOperatingMode::Floating;
    6912         9256 :                     continue;
    6913              : 
    6914      3909047 :                 } else if (Qneeded < Qmincap) {
    6915              :                     // Heater is required at less than the minimum capacity
    6916              :                     // If cycling, Qmincap = Qmaxcap.  Once the setpoint is reached, heater will almost always be shut off here
    6917              : 
    6918      3856502 :                     if (this->ControlType == HeaterControlMode::Cycle) {
    6919              :                         // Control will cycle on and off based on DeadBandTemp
    6920      3856502 :                         Qheater = 0.0;
    6921      3856502 :                         Qunmet = 0.0;
    6922      3856502 :                         Mode_loc = TankOperatingMode::Floating;
    6923      3856502 :                         continue;
    6924              : 
    6925            0 :                     } else if (this->ControlType == HeaterControlMode::Modulate) {
    6926              :                         // Control will cycle on and off based on DeadBandTemp until Qneeded > Qmincap again
    6927            0 :                         Qheater = 0.0;
    6928            0 :                         Qunmet = Qneeded;
    6929            0 :                         Mode_loc = TankOperatingMode::Floating;
    6930            0 :                         continue;
    6931              : 
    6932              :                         // CASE (ControlTypeModulateWithOverheat)  ! Not yet implemented
    6933              :                         // Calculate time to reach steady-state temp; check for venting at MaxTemp limit
    6934              :                         // Qheater = Qmincap
    6935              : 
    6936              :                         // CASE (ControlTypeModulateWithUnderheat)  ! Not yet implemented
    6937              :                         // Heater must not come back on until Qneeded >= Qmincap
    6938              :                         // Mode = modfloatMode
    6939              :                     }
    6940              : 
    6941        52545 :                 } else if (Qneeded <= Qmaxcap) {
    6942              :                     // Heater can exactly meet the needed heat rate (usually by modulating) and heats for all of the remaining time
    6943              :                     // Setpoint temperature WILL be maintained
    6944              : 
    6945        52503 :                     TimeNeeded = TimeRemaining;
    6946              : 
    6947        52503 :                     Qheater = Qneeded;
    6948        52503 :                     Qunmet = 0.0;
    6949              : 
    6950        52503 :                     NewTankTemp = SetPointTemp_loc;
    6951              : 
    6952              :                 } else { // Qneeded > Qmaxcap
    6953              :                     // Heater is at maximum capacity and heats for all of the remaining time
    6954              :                     // Setpoint temperature WILL NOT be maintained
    6955              : 
    6956           42 :                     TimeNeeded = TimeRemaining;
    6957              : 
    6958           42 :                     Qheater = Qmaxcap;
    6959           42 :                     Qunmet = Qneeded - Qheater;
    6960           42 :                     Qheat = Qoncycheat + Qheater + Qheatpump;
    6961              : 
    6962           42 :                     NewTankTemp = EnergyPlus::WaterThermalTanks::WaterThermalTankData::CalcTankTemp(TankTemp_loc,
    6963              :                                                                                                     AmbientTemp_loc,
    6964              :                                                                                                     UseInletTemp_loc,
    6965              :                                                                                                     SourceInletTemp_loc,
    6966              :                                                                                                     TankMass,
    6967              :                                                                                                     Cp,
    6968              :                                                                                                     UseMassFlowRate_loc,
    6969              :                                                                                                     SourceMassFlowRate_loc,
    6970              :                                                                                                     LossCoeff_loc,
    6971              :                                                                                                     Qheat,
    6972              :                                                                                                     TimeNeeded);
    6973              : 
    6974              :                 } // Qneeded > Qmaxcap
    6975              : 
    6976              :             } // TankTemp > SetPointTemp
    6977              : 
    6978              :             // Update summed values
    6979      4442867 :             Eneeded += Qneeded * TimeNeeded;
    6980      4442867 :             Eheater += Qheater * TimeNeeded;
    6981      4442867 :             Eunmet += Qunmet * TimeNeeded;
    6982      4442867 :             Eoncycfuel += Qoncycfuel * TimeNeeded;
    6983              : 
    6984      4442867 :             if (Qmaxcap > 0.0) {
    6985      4345931 :                 PLR = Qheater / Qmaxcap;
    6986              :             }
    6987      4442867 :             PLF = this->PartLoadFactor(state, PLR);
    6988      4442867 :             Efuel += Qheater * TimeNeeded / (PLF * this->Efficiency);
    6989              : 
    6990      4442867 :             Runtime += TimeNeeded;
    6991      4442867 :             PLRsum += PLR * TimeNeeded;
    6992              : 
    6993      4442867 :             if (!this->FirstRecoveryDone) {
    6994       108874 :                 this->FirstRecoveryFuel += Efuel + Eoffcycfuel + Eoncycfuel;
    6995       108874 :                 if (SetPointRecovered) {
    6996         7456 :                     this->FirstRecoveryDone = true;
    6997              :                 }
    6998              :             }
    6999      4442867 :             break;
    7000              : 
    7001      9959094 :         case TankOperatingMode::Floating:
    7002              :         case TankOperatingMode::Cooling: // Heater is off
    7003              : 
    7004              :             // Calculate heat rate needed to maintain the setpoint at steady-state conditions
    7005      9959094 :             LossCoeff_loc = this->OffCycLossCoeff;
    7006      9959094 :             LossFracToZone = this->OffCycLossFracToZone;
    7007      9959094 :             Qloss = LossCoeff_loc * (AmbientTemp_loc - SetPointTemp_loc);
    7008      9959094 :             Qneeded = -Quse - Qsource - Qloss - Qoffcycheat;
    7009              : 
    7010              :             // This section really needs to work differently depending on ControlType
    7011              :             // CYCLE will look at TankTemp, MODULATE will look at Qneeded
    7012              : 
    7013      9959094 :             if ((TankTemp_loc < DeadBandTemp) && (!this->IsChilledWaterTank)) {
    7014              :                 // Tank temperature is already below the minimum, possibly due to step change in scheduled SetPointTemp
    7015              : 
    7016          455 :                 Mode_loc = TankOperatingMode::Heating;
    7017          455 :                 ++CycleOnCount_loc;
    7018          455 :                 continue;
    7019              : 
    7020      9958639 :             } else if ((TankTemp_loc >= DeadBandTemp) && (!this->IsChilledWaterTank)) {
    7021              : 
    7022      9568979 :                 Qheat = Qoffcycheat + Qheatpump;
    7023              : 
    7024              :                 // Calculate time needed for tank temperature to fall to minimum (setpoint - deadband)
    7025      9568979 :                 TimeNeeded = EnergyPlus::WaterThermalTanks::WaterThermalTankData::CalcTimeNeeded(TankTemp_loc,
    7026              :                                                                                                  DeadBandTemp,
    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              : 
    7037      9568979 :                 if (TimeNeeded <= TimeRemaining) {
    7038              :                     // Heating will be needed in this DataGlobals::TimeStep
    7039              : 
    7040      4058811 :                     NewTankTemp = DeadBandTemp;
    7041      4058811 :                     Mode_loc = TankOperatingMode::Heating;
    7042      4058811 :                     ++CycleOnCount_loc;
    7043              : 
    7044              :                 } else { // TimeNeeded > TimeRemaining
    7045              :                     // Heating will not be needed for all of the remaining time
    7046              : 
    7047      5510168 :                     NewTankTemp = EnergyPlus::WaterThermalTanks::WaterThermalTankData::CalcTankTemp(TankTemp_loc,
    7048              :                                                                                                     AmbientTemp_loc,
    7049              :                                                                                                     UseInletTemp_loc,
    7050              :                                                                                                     SourceInletTemp_loc,
    7051              :                                                                                                     TankMass,
    7052              :                                                                                                     Cp,
    7053              :                                                                                                     UseMassFlowRate_loc,
    7054              :                                                                                                     SourceMassFlowRate_loc,
    7055              :                                                                                                     LossCoeff_loc,
    7056              :                                                                                                     Qheat,
    7057              :                                                                                                     TimeRemaining);
    7058              : 
    7059      5510168 :                     if ((NewTankTemp < MaxTemp) || (this->IsChilledWaterTank)) {
    7060              :                         // Neither heating nor venting is needed for all of the remaining time
    7061              : 
    7062      5491087 :                         TimeNeeded = TimeRemaining;
    7063              : 
    7064              :                     } else { // NewTankTemp >= MaxTemp
    7065              :                         // Venting will be needed in this DataGlobals::TimeStep
    7066              : 
    7067              :                         // Calculate time needed for tank temperature to rise to the maximum
    7068        19081 :                         TimeNeeded = CalcTimeNeeded(TankTemp_loc,
    7069              :                                                     MaxTemp,
    7070              :                                                     AmbientTemp_loc,
    7071              :                                                     UseInletTemp_loc,
    7072              :                                                     SourceInletTemp_loc,
    7073              :                                                     TankMass,
    7074              :                                                     Cp,
    7075              :                                                     UseMassFlowRate_loc,
    7076              :                                                     SourceMassFlowRate_loc,
    7077              :                                                     LossCoeff_loc,
    7078              :                                                     Qheat);
    7079              : 
    7080              :                         // if limit NewTankTemp >= MaxTemp
    7081        19081 :                         if (TankTemp_loc >= MaxTemp) {
    7082            0 :                             TimeNeeded = TimeRemaining;
    7083              :                         }
    7084        19081 :                         NewTankTemp = MaxTemp;
    7085        19081 :                         Mode_loc = TankOperatingMode::Venting;
    7086              : 
    7087              :                     } // NewTankTemp >= MaxTemp
    7088              : 
    7089              :                 } // TimeNeeded <= TimeRemaining
    7090              : 
    7091       389660 :             } else if ((TankTemp_loc > DeadBandTemp) && (this->IsChilledWaterTank)) {
    7092        77910 :                 Mode_loc = TankOperatingMode::Cooling;
    7093        77910 :                 Qheat = Qheatpump;
    7094              : 
    7095        77910 :                 NewTankTemp = EnergyPlus::WaterThermalTanks::WaterThermalTankData::CalcTankTemp(TankTemp_loc,
    7096              :                                                                                                 AmbientTemp_loc,
    7097              :                                                                                                 UseInletTemp_loc,
    7098              :                                                                                                 SourceInletTemp_loc,
    7099              :                                                                                                 TankMass,
    7100              :                                                                                                 Cp,
    7101              :                                                                                                 UseMassFlowRate_loc,
    7102              :                                                                                                 SourceMassFlowRate_loc,
    7103              :                                                                                                 LossCoeff_loc,
    7104              :                                                                                                 Qheat,
    7105              :                                                                                                 TimeRemaining);
    7106        77910 :                 TimeNeeded = TimeRemaining;
    7107       311750 :             } else if ((TankTemp_loc <= DeadBandTemp) && (this->IsChilledWaterTank)) {
    7108              : 
    7109       311750 :                 if (TankTemp_loc < SetPointTemp_loc) {
    7110        38959 :                     Mode_loc = TankOperatingMode::Floating;
    7111              :                 }
    7112              : 
    7113       311750 :                 Qheat = Qheatpump;
    7114              : 
    7115       311750 :                 NewTankTemp = EnergyPlus::WaterThermalTanks::WaterThermalTankData::CalcTankTemp(TankTemp_loc,
    7116              :                                                                                                 AmbientTemp_loc,
    7117              :                                                                                                 UseInletTemp_loc,
    7118              :                                                                                                 SourceInletTemp_loc,
    7119              :                                                                                                 TankMass,
    7120              :                                                                                                 Cp,
    7121              :                                                                                                 UseMassFlowRate_loc,
    7122              :                                                                                                 SourceMassFlowRate_loc,
    7123              :                                                                                                 LossCoeff_loc,
    7124              :                                                                                                 Qheat,
    7125              :                                                                                                 TimeRemaining);
    7126       311750 :                 TimeNeeded = TimeRemaining;
    7127              :             } // TankTemp vs DeadBandTemp for heaters and chilled water tanks
    7128              : 
    7129              :             // Update summed values
    7130      9958639 :             Eneeded += Qneeded * TimeNeeded;
    7131      9958639 :             Eunmet += Qunmet * TimeNeeded; // Qunmet may be propagated thru from the previous iteration
    7132      9958639 :             Eoffcycfuel += Qoffcycfuel * TimeNeeded;
    7133      9958639 :             break;
    7134              : 
    7135       136666 :         case TankOperatingMode::Venting: // Excess heat is vented
    7136              : 
    7137       136666 :             LossCoeff_loc = this->OffCycLossCoeff;
    7138       136666 :             LossFracToZone = this->OffCycLossFracToZone;
    7139       136666 :             Qheat = Qoffcycheat + Qheatpump;
    7140              : 
    7141       136666 :             NewTankTemp = EnergyPlus::WaterThermalTanks::WaterThermalTankData::CalcTankTemp(TankTemp_loc,
    7142              :                                                                                             AmbientTemp_loc,
    7143              :                                                                                             UseInletTemp_loc,
    7144              :                                                                                             SourceInletTemp_loc,
    7145              :                                                                                             TankMass,
    7146              :                                                                                             Cp,
    7147              :                                                                                             UseMassFlowRate_loc,
    7148              :                                                                                             SourceMassFlowRate_loc,
    7149              :                                                                                             LossCoeff_loc,
    7150              :                                                                                             Qheat,
    7151              :                                                                                             TimeRemaining);
    7152              : 
    7153       136666 :             if (NewTankTemp < MaxTemp) {
    7154              :                 // Venting is no longer needed because conditions have changed
    7155              : 
    7156        41953 :                 Mode_loc = TankOperatingMode::Floating;
    7157        41953 :                 continue;
    7158              : 
    7159              :             } else { // NewTankTemp >= MaxTemp
    7160              : 
    7161        94713 :                 TimeNeeded = TimeRemaining;
    7162              : 
    7163              :                 // Calculate the steady-state venting rate needed to maintain the tank at maximum temperature
    7164        94713 :                 Real64 Qloss = LossCoeff_loc * (AmbientTemp_loc - MaxTemp);
    7165        94713 :                 Quse = UseMassFlowRate_loc * Cp * (UseInletTemp_loc - MaxTemp);
    7166        94713 :                 Qsource = SourceMassFlowRate_loc * Cp * (SourceInletTemp_loc - MaxTemp);
    7167        94713 :                 Qvent = -Quse - Qsource - Qloss - Qoffcycheat;
    7168              : 
    7169        94713 :                 NewTankTemp = MaxTemp;
    7170              : 
    7171              :             } // NewTankTemp < MaxTemp
    7172              : 
    7173              :             // Update summed values
    7174        94713 :             Event += Qvent * TimeNeeded;
    7175        94713 :             Eoffcycfuel += Qoffcycfuel * TimeNeeded;
    7176        94713 :             break;
    7177            0 :         default:
    7178            0 :             assert(false); // should never get here
    7179              :         }
    7180              : 
    7181     14496219 :         Real64 deltaTsum = EnergyPlus::WaterThermalTanks::WaterThermalTankData::CalcTempIntegral(TankTemp_loc,
    7182              :                                                                                                  NewTankTemp,
    7183              :                                                                                                  AmbientTemp_loc,
    7184              :                                                                                                  UseInletTemp_loc,
    7185              :                                                                                                  SourceInletTemp_loc,
    7186              :                                                                                                  TankMass,
    7187              :                                                                                                  Cp,
    7188              :                                                                                                  UseMassFlowRate_loc,
    7189              :                                                                                                  SourceMassFlowRate_loc,
    7190              :                                                                                                  LossCoeff_loc,
    7191              :                                                                                                  Qheat,
    7192              :                                                                                                  TimeNeeded);
    7193              : 
    7194              :         // Update summed values
    7195     14496219 :         Tsum += deltaTsum;
    7196     14496219 :         Eloss += LossCoeff_loc * (AmbientTemp_loc * TimeNeeded - deltaTsum);
    7197     14496219 :         Elosszone += LossFracToZone * LossCoeff_loc * (AmbientTemp_loc * TimeNeeded - deltaTsum);
    7198     14496219 :         Euse += UseMassFlowRate_loc * Cp * (UseInletTemp_loc * TimeNeeded - deltaTsum);
    7199     14496219 :         if (this->HeatPumpNum > 0) {
    7200       895538 :             Esource += Qheatpump * TimeNeeded;
    7201              :         } else {
    7202     13600681 :             Esource += SourceMassFlowRate_loc * Cp * (SourceInletTemp_loc * TimeNeeded - deltaTsum);
    7203              :         }
    7204              : 
    7205     14496219 :         TankTemp_loc = NewTankTemp; // Update tank temperature
    7206              : 
    7207     14496219 :         TimeRemaining -= TimeNeeded;
    7208              : 
    7209     14496219 :         if (CycleOnCount_loc > MaxCycles) {
    7210              : 
    7211            0 :             if (!state.dataGlobal->WarmupFlag) {
    7212            0 :                 if (this->MaxCycleErrorIndex == 0) {
    7213            0 :                     ShowWarningError(state, format("WaterHeater:Mixed = {}:  Heater is cycling on and off more than once per second.", this->Name));
    7214            0 :                     ShowContinueError(state, "Try increasing Deadband Temperature Difference or Tank Volume");
    7215            0 :                     ShowContinueErrorTimeStamp(state, "");
    7216              :                 }
    7217            0 :                 ShowRecurringWarningErrorAtEnd(state,
    7218            0 :                                                "WaterHeater:Mixed = " + this->Name + " Heater is cycling on and off more than once per second:",
    7219            0 :                                                this->MaxCycleErrorIndex);
    7220              :             }
    7221              : 
    7222            0 :             break;
    7223              : 
    7224              :         } // CycleOnCount > MaxCycles
    7225              : 
    7226              :     } // TimeRemaining > 0.0
    7227              : 
    7228              :     // 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
    7229      6551906 :     Real64 TankTempAvg_loc = Tsum / SecInTimeStep;
    7230      6551906 :     Qloss = Eloss / SecInTimeStep;
    7231      6551906 :     Real64 Qlosszone = Elosszone / SecInTimeStep;
    7232      6551906 :     Quse = Euse / SecInTimeStep;
    7233      6551906 :     Qsource = Esource / SecInTimeStep;
    7234      6551906 :     Qheater = Eheater / SecInTimeStep;
    7235      6551906 :     Qoffcycfuel = Eoffcycfuel / SecInTimeStep;
    7236      6551906 :     Qoffcycheat = Qoffcycfuel * this->OffCycParaFracToTank;
    7237      6551906 :     Qoncycfuel = Eoncycfuel / SecInTimeStep;
    7238      6551906 :     Qoncycheat = Qoncycfuel * this->OnCycParaFracToTank;
    7239      6551906 :     Qvent = Event / SecInTimeStep;
    7240      6551906 :     Qneeded = Eneeded / SecInTimeStep;
    7241      6551906 :     Qunmet = Eunmet / SecInTimeStep;
    7242      6551906 :     Real64 RTF = Runtime / SecInTimeStep;
    7243      6551906 :     PLR = PLRsum / SecInTimeStep;
    7244              : 
    7245      6551906 :     if (this->ControlType == HeaterControlMode::Cycle) {
    7246              :         // Recalculate Part Load Factor and fuel energy based on Runtime Fraction, instead of Part Load Ratio
    7247      6498118 :         PLF = this->PartLoadFactor(state, RTF);
    7248      6498118 :         Efuel = Eheater / (PLF * this->Efficiency);
    7249              :     }
    7250              : 
    7251      6551906 :     Qfuel = Efuel / SecInTimeStep;
    7252              : 
    7253      6551906 :     this->Mode = Mode_loc;               // Operating mode for carry-over to next DataGlobals::TimeStep
    7254      6551906 :     this->TankTemp = TankTemp_loc;       // Final tank temperature for carry-over to next DataGlobals::TimeStep
    7255      6551906 :     this->TankTempAvg = TankTempAvg_loc; // Average tank temperature over the DataGlobals::TimeStep for reporting
    7256              : 
    7257      6551906 :     if (!state.dataGlobal->WarmupFlag) {
    7258              :         // Warn for potential freezing when avg of final temp over all nodes is below 2°C (nearing 0°C)
    7259       951848 :         if (this->TankTemp < 2) {
    7260            0 :             if (this->FreezingErrorIndex == 0) {
    7261            0 :                 ShowWarningError(state,
    7262            0 :                                  format("{}: {} = '{}':  Temperature of tank < 2C indicates of possibility of freeze. Tank Temperature = {:.2R} C.",
    7263              :                                         RoutineName,
    7264            0 :                                         this->Type,
    7265            0 :                                         this->Name,
    7266            0 :                                         this->TankTemp));
    7267            0 :                 ShowContinueErrorTimeStamp(state, "");
    7268              :             }
    7269            0 :             ShowRecurringWarningErrorAtEnd(state,
    7270            0 :                                            this->Type + " = '" + this->Name + "':  Temperature of tank < 2C indicates of possibility of freeze",
    7271            0 :                                            this->FreezingErrorIndex,
    7272            0 :                                            this->TankTemp, // Report Max
    7273            0 :                                            this->TankTemp, // Report Min
    7274              :                                            _,              // Don't report Sum
    7275              :                                            "{C}",          // Max Unit
    7276              :                                            "{C}");         // Min Unit
    7277              :         }
    7278              :     }
    7279      6551906 :     this->UseOutletTemp = TankTempAvg_loc;    // Because entire tank is at same temperature
    7280      6551906 :     this->SourceOutletTemp = TankTempAvg_loc; // Because entire tank is at same temperature
    7281      6551906 :     if (this->HeatPumpNum > 0) {
    7282       811623 :         this->SourceInletTemp =
    7283       811623 :             TankTempAvg_loc + HPWHCondenserDeltaT; // Update the source inlet temperature to the average over the DataGlobals::TimeStep
    7284              :     }
    7285              : 
    7286      6551906 :     this->LossRate = Qloss;
    7287      6551906 :     this->UseRate = Quse;
    7288      6551906 :     this->SourceRate = Qsource;
    7289      6551906 :     this->OffCycParaRateToTank = Qoffcycheat;
    7290      6551906 :     this->OnCycParaRateToTank = Qoncycheat;
    7291      6551906 :     this->TotalDemandRate = -Quse - Qsource - Qloss - Qoffcycheat - Qoncycheat;
    7292      6551906 :     this->HeaterRate = Qheater;
    7293      6551906 :     this->UnmetRate = Qunmet;
    7294      6551906 :     this->VentRate = Qvent;
    7295      6551906 :     this->NetHeatTransferRate = Quse + Qsource + Qloss + Qoffcycheat + Qoncycheat + Qheater + Qvent;
    7296              : 
    7297      6551906 :     this->CycleOnCount = CycleOnCount_loc;
    7298      6551906 :     this->RuntimeFraction = RTF;
    7299      6551906 :     this->PartLoadRatio = PLR;
    7300              : 
    7301      6551906 :     this->FuelRate = Qfuel;
    7302      6551906 :     this->OffCycParaFuelRate = Qoffcycfuel;
    7303      6551906 :     this->OnCycParaFuelRate = Qoncycfuel;
    7304              : 
    7305              :     // Add water heater skin losses and venting losses to ambient zone, if specified
    7306      6551906 :     if (this->AmbientTempZone > 0) {
    7307      1296253 :         this->AmbientZoneGain = -Qlosszone - Qvent;
    7308              :     }
    7309      6551906 : }
    7310              : 
    7311      6551906 : void WaterThermalTankData::CalcMixedTankSourceSideHeatTransferRate(
    7312              :     Real64 HPWHCondenserDeltaT, // input, The temperature difference (C) across the heat pump, zero if
    7313              :                                 // there is no heat pump or if the heat pump is off
    7314              :     Real64 SourceInletTemp,     // input, Source inlet temperature (C)
    7315              :     Real64 Cp,                  // Specific heat of fluid (J/kg deltaC)
    7316              :     Real64 SetPointTemp,        // input, Mixed tank set point temperature
    7317              :     Real64 &SourceMassFlowRate, // source mass flow rate (kg/s)
    7318              :     Real64 &Qheatpump,          // heat transfer rate from heat pump
    7319              :     Real64 &Qsource             // steady state heat transfer rate from a constant temperature source side flow
    7320              : )
    7321              : {
    7322              :     // Function Information:
    7323              :     //        Author: Noel Merket
    7324              :     //        Date Written: January 2015
    7325              :     //        Modified: na
    7326              :     //        Re-engineered: na
    7327              : 
    7328              :     // Purpose of this function:
    7329              :     // Determines if the source side heat transfer is coming from a heat pump.
    7330              :     // If so it treats the source side heat transfer as a constant heat source
    7331              :     // If it is not coming from a heat pump it treats the source side heat transfer
    7332              :     // as a constant temperature.
    7333              : 
    7334              :     // Determine if the source side heating is coming from a heat pump.
    7335      6551906 :     Qheatpump = SourceMassFlowRate * Cp * HPWHCondenserDeltaT;
    7336      6551906 :     if (Qheatpump > 0.0) {
    7337       546752 :         SourceMassFlowRate = 0.0; // Handle this heating as a constant heat source
    7338       546752 :         Qsource = Qheatpump;
    7339              :     } else {
    7340      6005154 :         Qsource = SourceMassFlowRate * Cp * (SourceInletTemp - SetPointTemp);
    7341              :     }
    7342      6551906 : }
    7343              : 
    7344     13978382 : Real64 WaterThermalTankData::CalcTimeNeeded(Real64 const Ti, // Initial tank temperature (C)
    7345              :                                             Real64 const Tf, // Final tank temperature (C)
    7346              :                                             Real64 const Ta, // Ambient environment temperature (C)
    7347              :                                             Real64 const T1, // Temperature of flow 1 (C)
    7348              :                                             Real64 const T2, // Temperature of flow 2 (C)
    7349              :                                             Real64 const m,  // Mass of tank fluid (kg)
    7350              :                                             Real64 const Cp, // Specific heat of fluid (J/kg deltaC)
    7351              :                                             Real64 const m1, // Mass flow rate 1 (kg/s)
    7352              :                                             Real64 const m2, // Mass flow rate 2 (kg/s)
    7353              :                                             Real64 const UA, // Heat loss coefficient to ambient environment (W/deltaC)
    7354              :                                             Real64 const Q   // Net heating rate for non-temp dependent sources, i.e. heater and parasitics (W)
    7355              : )
    7356              : {
    7357              : 
    7358              :     // SUBROUTINE INFORMATION:
    7359              :     //       AUTHOR         Peter Graham Ellis
    7360              :     //       DATE WRITTEN   February 2005
    7361              :     //       MODIFIED       na
    7362              :     //       RE-ENGINEERED  na
    7363              : 
    7364              :     // PURPOSE OF THIS SUBROUTINE:
    7365              :     // Calculates the time needed for the tank temperature to change from Ti to Tf given heat loss,
    7366              :     // mass flow rates and temperatures, and net heat transfer due to heater and parasitics.
    7367              : 
    7368              :     // METHODOLOGY EMPLOYED:
    7369              :     // Equations are derived by solving the differential equation governing the tank energy balance.
    7370              :     // Special cases which cause the natural logarithm to blow up are trapped and interpreted as
    7371              :     // requiring an infinite amount of time because Tf can never be reached under the given conditions.
    7372              : 
    7373              :     // Return value
    7374              :     Real64 CalcTimeNeeded;
    7375              : 
    7376              :     // SUBROUTINE PARAMETER DEFINITIONS:
    7377     13978382 :     Real64 constexpr Infinity(99999999.9); // A time interval much larger than any single DataGlobals::TimeStep (s)
    7378              : 
    7379              :     Real64 t; // Time elapsed from Ti to Tf (s)
    7380              : 
    7381     13978382 :     if (Tf == Ti) {
    7382              :         // Already at Tf; no time is needed
    7383            0 :         t = 0.0;
    7384              : 
    7385              :     } else {
    7386              :         Real64 a;        // Intermediate variable
    7387              :         Real64 b;        // Intermediate variable
    7388              :         Real64 Tm;       // Mixed temperature after an infinite amount of time has passed (C)
    7389              :         Real64 quotient; // Intermediate variable
    7390              : 
    7391     13978382 :         if (UA / Cp + m1 + m2 == 0.0) {
    7392              : 
    7393        22891 :             if (Q == 0.0) {
    7394              :                 // With no mass flow and no heat flow and Tf<>Ti, then Tf can never be reached
    7395        21952 :                 t = Infinity;
    7396              : 
    7397              :             } else {
    7398          939 :                 a = Q / (m * Cp);
    7399              : 
    7400          939 :                 t = (Tf - Ti) / a;
    7401              :             }
    7402              : 
    7403              :         } else {
    7404     13955491 :             a = (Q / Cp + UA * Ta / Cp + m1 * T1 + m2 * T2) / m;
    7405     13955491 :             b = -(UA / Cp + m1 + m2) / m;
    7406              : 
    7407              :             // Calculate the mixed temperature Tm of the tank after an infinite amount of time has passed
    7408     13955491 :             Tm = -a / b;
    7409              : 
    7410     13955491 :             if (Tm == Ti) {
    7411              :                 // Mixed temperature is the same as Ti; if Tf<>Ti, then Tf can never be reached
    7412         1515 :                 t = Infinity;
    7413              : 
    7414     13953976 :             } else if (Tm == Tf) {
    7415              :                 // Tf only approaches Tm; it can never actually get there in finite time (also avoids divide by zero error)
    7416            0 :                 t = Infinity;
    7417              : 
    7418              :             } else {
    7419     13953976 :                 quotient = (Tf - Tm) / (Ti - Tm);
    7420              : 
    7421     13953976 :                 if (quotient <= 0.0) { // Autodesk:Num Changed < to <= to elim poss floating point error in LOG call
    7422              :                     // Tm is in between Ti and Tf; Tf can never be reached
    7423       538083 :                     t = Infinity;
    7424              : 
    7425              :                 } else {
    7426     13415893 :                     t = std::log(quotient) / b;
    7427              :                 }
    7428              :             }
    7429              :         }
    7430              : 
    7431     13978382 :         if (t < 0.0) {
    7432       583368 :             t = Infinity; // If negative time, Tf can never be reached in the future
    7433              :         }
    7434              :     }
    7435              : 
    7436     13978382 :     CalcTimeNeeded = t;
    7437              : 
    7438     13978382 :     return CalcTimeNeeded;
    7439              : }
    7440              : 
    7441      6577212 : Real64 WaterThermalTankData::CalcTankTemp(Real64 const Ti, // Initial tank temperature (C)
    7442              :                                           Real64 const Ta, // Ambient environment temperature (C)
    7443              :                                           Real64 const T1, // Temperature of flow 1 (C)
    7444              :                                           Real64 const T2, // Temperature of flow 2 (C)
    7445              :                                           Real64 const m,  // Mass of tank fluid (kg)
    7446              :                                           Real64 const Cp, // Specific heat of fluid (J/kg deltaC)
    7447              :                                           Real64 const m1, // Mass flow rate 1 (kg/s)
    7448              :                                           Real64 const m2, // Mass flow rate 2 (kg/s)
    7449              :                                           Real64 const UA, // Heat loss coefficient to ambient environment (W/deltaC)
    7450              :                                           Real64 const Q,  // Net heating rate for non-temp dependent sources, i.e. heater and parasitics (W)
    7451              :                                           Real64 const t   // Time elapsed from Ti to Tf (s)
    7452              : )
    7453              : {
    7454              : 
    7455              :     // SUBROUTINE INFORMATION:
    7456              :     //       AUTHOR         Peter Graham Ellis
    7457              :     //       DATE WRITTEN   February 2005
    7458              :     //       MODIFIED       na
    7459              :     //       RE-ENGINEERED  na
    7460              : 
    7461              :     // PURPOSE OF THIS SUBROUTINE:
    7462              :     // Calculates the final tank temperature Tf after time t has elapsed given heat loss,
    7463              :     // mass flow rates and temperatures, and net heat transfer due to heater and parasitics.
    7464              : 
    7465              :     // METHODOLOGY EMPLOYED:
    7466              :     // Equations are derived by solving the differential equation governing the tank energy balance.
    7467              : 
    7468              :     // Return value
    7469              :     Real64 CalcTankTemp;
    7470              : 
    7471              :     // Locals
    7472              :     // SUBROUTINE ARGUMENT DEFINITIONS:
    7473              : 
    7474              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    7475              :     Real64 a;  // Intermediate variable
    7476              :     Real64 b;  // Intermediate variable
    7477              :     Real64 Tf; // Final tank temperature (C)
    7478              : 
    7479      6577212 :     if (UA / Cp + m1 + m2 == 0.0) {
    7480        22819 :         a = Q / (m * Cp);
    7481              : 
    7482        22819 :         Tf = a * t + Ti;
    7483              : 
    7484              :     } else {
    7485      6554393 :         a = (Q / Cp + UA * Ta / Cp + m1 * T1 + m2 * T2) / m;
    7486      6554393 :         b = -(UA / Cp + m1 + m2) / m;
    7487              : 
    7488      6554393 :         Tf = (a / b + Ti) * std::exp(b * t) - a / b;
    7489              :     }
    7490              : 
    7491      6577212 :     CalcTankTemp = Tf;
    7492              : 
    7493      6577212 :     return CalcTankTemp;
    7494              : }
    7495              : 
    7496     14512994 : Real64 WaterThermalTankData::CalcTempIntegral(Real64 const Ti, // Initial tank temperature (C)
    7497              :                                               Real64 const Tf, // Final tank temperature (C)
    7498              :                                               Real64 const Ta, // Ambient environment temperature (C)
    7499              :                                               Real64 const T1, // Temperature of flow 1 (C)
    7500              :                                               Real64 const T2, // Temperature of flow 2 (C)
    7501              :                                               Real64 const m,  // Mass of tank fluid (kg)
    7502              :                                               Real64 const Cp, // Specific heat of fluid (J/kg deltaC)
    7503              :                                               Real64 const m1, // Mass flow rate 1 (kg/s)
    7504              :                                               Real64 const m2, // Mass flow rate 2 (kg/s)
    7505              :                                               Real64 const UA, // Heat loss coefficient to ambient environment (W/deltaC)
    7506              :                                               Real64 const Q,  // Net heating rate for non-temp dependent sources, i.e. heater and parasitics (W)
    7507              :                                               Real64 const t   // Time elapsed from Ti to Tf (s)
    7508              : )
    7509              : {
    7510              : 
    7511              :     // SUBROUTINE INFORMATION:
    7512              :     //       AUTHOR         Peter Graham Ellis
    7513              :     //       DATE WRITTEN   February 2005
    7514              :     //       MODIFIED       na
    7515              :     //       RE-ENGINEERED  na
    7516              : 
    7517              :     // PURPOSE OF THIS SUBROUTINE:
    7518              :     // Calculates the integral of the tank temperature from Ti to Tf.  The integral is added to a sum which is
    7519              :     // later divided by the elapsed time to yield the average tank temperature over the DataGlobals::TimeStep.
    7520              : 
    7521              :     // METHODOLOGY EMPLOYED:
    7522              :     // Equations are the mathematical integrals of the governing differential equations.
    7523              : 
    7524              :     // Return value
    7525              :     Real64 CalcTempIntegral;
    7526              : 
    7527              :     // Locals
    7528              :     // SUBROUTINE ARGUMENT DEFINITIONS:
    7529              : 
    7530              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    7531              :     Real64 a;     // Intermediate variable
    7532              :     Real64 b;     // Intermediate variable
    7533              :     Real64 dTsum; // Integral of tank temperature (C s)
    7534              : 
    7535     14512994 :     if (t == 0.0) {
    7536            0 :         dTsum = 0.0;
    7537              : 
    7538     14512994 :     } else if (Tf == Ti) { // Steady-state conditions
    7539       187500 :         dTsum = Tf * t;
    7540              : 
    7541     14325494 :     } else if (UA / Cp + m1 + m2 == 0.0) {
    7542          939 :         a = Q / (m * Cp);
    7543              : 
    7544              :         // Integral of T(t) = a * t + Ti, evaluated from 0 to t
    7545          939 :         dTsum = 0.5 * a * t * t + Ti * t;
    7546              : 
    7547              :     } else {
    7548     14324555 :         a = (Q / Cp + UA * Ta / Cp + m1 * T1 + m2 * T2) / m;
    7549     14324555 :         b = -(UA / Cp + m1 + m2) / m;
    7550              : 
    7551              :         // Integral of T(t) = (a / b + Ti) * EXP(b * t) - a / b, evaluated from 0 to t
    7552     14324555 :         dTsum = (a / b + Ti) * (std::exp(b * t) - 1.0) / b - a * t / b;
    7553              :     }
    7554              : 
    7555     14512994 :     CalcTempIntegral = dTsum;
    7556              : 
    7557     14512994 :     return CalcTempIntegral;
    7558              : }
    7559              : 
    7560     10940985 : Real64 WaterThermalTankData::PartLoadFactor(EnergyPlusData &state, Real64 const PartLoadRatio_loc)
    7561              : {
    7562              : 
    7563              :     // SUBROUTINE INFORMATION:
    7564              :     //       AUTHOR         Peter Graham Ellis
    7565              :     //       DATE WRITTEN   January 2005
    7566              :     //       MODIFIED       na
    7567              :     //       RE-ENGINEERED  na
    7568              : 
    7569              :     // PURPOSE OF THIS SUBROUTINE:
    7570              :     // Calculates the Part Load Factor (PLF) based on a curve correlated to Part Load Ratio, if Heater Control Type
    7571              :     // is MODULATE, or correlated to Runtime Fraction, if Heater Control Type is CYCLE.
    7572              : 
    7573     10940985 :     if (this->PLFCurve > 0) {
    7574         1260 :         return max(Curve::CurveValue(state, this->PLFCurve, PartLoadRatio_loc), 0.1);
    7575              :     } else {
    7576     10939725 :         return 1.0;
    7577              :     }
    7578              : }
    7579              : 
    7580      1146020 : void WaterThermalTankData::CalcWaterThermalTankStratified(EnergyPlusData &state)
    7581              : {
    7582              :     // SUBROUTINE INFORMATION:
    7583              :     //       AUTHOR         Noel Merket, originally by Peter Graham Ellis
    7584              :     //       DATE WRITTEN   January 2007
    7585              :     //       MODIFIED       Nov 2011, BAN; modified the use and source outlet temperature calculation
    7586              :     //       RE-ENGINEERED  Noel Merket, November 2018
    7587              : 
    7588              :     // PURPOSE OF THIS SUBROUTINE:
    7589              :     // Simulates a stratified, multi-node water heater tank with up to two heating elements.
    7590              : 
    7591              :     // METHODOLOGY EMPLOYED:
    7592              :     // This model uses a numerical calculation based on an analytical solution of the ODE dT/dt = a*T + b.
    7593              :     // A heat balance is calculated for each node.
    7594              :     // Temperatures and energies change dynamically over the system time step.
    7595              :     // Final node temperatures are reported as final instantaneous values as well as averages over the
    7596              :     // time step.  Heat transfer rates are averages over the time step.
    7597              : 
    7598              :     static constexpr std::string_view RoutineName("CalcWaterThermalTankStratified");
    7599      1146020 :     constexpr Real64 TemperatureConvergenceCriteria = 0.0001;
    7600      1146020 :     constexpr Real64 SubTimestepMax = 60.0 * 10.0; // seconds
    7601      1146020 :     constexpr Real64 SubTimestepMin = 10.0;        // seconds
    7602              :     Real64 dt;
    7603              : 
    7604              :     // Tank object reference
    7605      1146020 :     const Real64 &nTankNodes = this->Nodes;
    7606              : 
    7607              :     // Fraction of the current hour that has elapsed (h)
    7608              :     const Real64 TimeElapsed_loc =
    7609      1146020 :         state.dataGlobal->HourOfDay + state.dataGlobal->TimeStep * state.dataGlobal->TimeStepZone + state.dataHVACGlobal->SysTimeElapsed;
    7610              : 
    7611              :     // Seconds in one DataGlobals::TimeStep (s)
    7612      1146020 :     const Real64 SecInTimeStep = state.dataHVACGlobal->TimeStepSysSec;
    7613              : 
    7614              :     // Advance tank simulation to the next system DataGlobals::TimeStep, if applicable
    7615      1146020 :     if (this->TimeElapsed != TimeElapsed_loc) {
    7616              :         // The simulation has advanced to the next system DataGlobals::TimeStep.  Save conditions from the end of the previous system
    7617              :         // DataGlobals::TimeStep for use as the initial conditions of each iteration that does not advance the system DataGlobals::TimeStep.
    7618       407354 :         for (auto &e : this->Node) {
    7619       362412 :             e.SavedTemp = e.Temp;
    7620              :         }
    7621              : 
    7622        44942 :         this->SavedHeaterOn1 = this->HeaterOn1;
    7623        44942 :         this->SavedHeaterOn2 = this->HeaterOn2;
    7624              : 
    7625              :         // Save outlet temperatures for demand-side flow control
    7626        44942 :         this->SavedUseOutletTemp = this->UseOutletTemp;
    7627        44942 :         this->SavedSourceOutletTemp = this->SourceOutletTemp;
    7628              : 
    7629        44942 :         this->TimeElapsed = TimeElapsed_loc;
    7630              :     }
    7631              : 
    7632              :     // Reset node temperatures to what they were at the beginning of the system DataGlobals::TimeStep.
    7633      9263262 :     for (auto &e : this->Node) {
    7634      8117242 :         e.Temp = e.SavedTemp;
    7635              :     }
    7636              : 
    7637      1146020 :     this->HeaterOn1 = this->SavedHeaterOn1;
    7638      1146020 :     this->HeaterOn2 = this->SavedHeaterOn2;
    7639              : 
    7640              :     // Condenser configuration of heat pump water heater
    7641              :     const DataPlant::PlantEquipmentType HPWHCondenserConfig =
    7642      1146020 :         this->HeatPumpNum > 0 ? state.dataWaterThermalTanks->HPWaterHeater(this->HeatPumpNum).HPWHType : DataPlant::PlantEquipmentType::Invalid;
    7643              : 
    7644              :     // Heat rate from the heat pump (W)
    7645            0 :     const Real64 Qheatpump = [&, this] { // BLB
    7646      1146020 :         if (this->HeatPumpNum == 0) {
    7647       244578 :             return 0.0;
    7648              :         }
    7649       901442 :         HeatPumpWaterHeaterData const &HPWH = state.dataWaterThermalTanks->HPWaterHeater(this->HeatPumpNum);
    7650              :         Real64 CoilTotalHeatingEnergyRate;
    7651       901442 :         if (HPWH.NumofSpeed > 0) {
    7652              :             // VSHPWH
    7653        70625 :             VariableSpeedCoils::VariableSpeedCoilData const &Coil = state.dataVariableSpeedCoils->VarSpeedCoil(HPWH.DXCoilNum);
    7654        70625 :             CoilTotalHeatingEnergyRate = Coil.TotalHeatingEnergyRate;
    7655              :         } else {
    7656              :             // Single speed HPWH
    7657       830817 :             DXCoils::DXCoilData const &Coil = state.dataDXCoils->DXCoil(HPWH.DXCoilNum);
    7658       830817 :             CoilTotalHeatingEnergyRate = Coil.TotalHeatingEnergyRate;
    7659              :         }
    7660       901442 :         return CoilTotalHeatingEnergyRate * this->SourceEffectiveness;
    7661      1146020 :     }();
    7662              : 
    7663              :     // Minimum tank temperatures
    7664      1146020 :     const Real64 MinTemp1 = this->SetPointTemp - this->DeadBandDeltaTemp;
    7665      1146020 :     const Real64 MinTemp2 = this->SetPointTemp2 - this->DeadBandDeltaTemp2;
    7666              : 
    7667              :     // Specific Heat of water (J/kg K)
    7668            0 :     const Real64 Cp = [&] {
    7669      1146020 :         if (this->UseSidePlantLoc.loopNum > 0) {
    7670      1076885 :             return state.dataPlnt->PlantLoop(this->UseSidePlantLoc.loopNum).glycol->getSpecificHeat(state, this->TankTemp, RoutineName);
    7671              :         } else {
    7672        69135 :             return this->water->getSpecificHeat(state, this->TankTemp, RoutineName);
    7673              :         }
    7674      1146020 :     }();
    7675              : 
    7676      1146020 :     Real64 Eloss = 0.0;             // Energy change due to ambient losses over the DataGlobals::TimeStep (J)
    7677      1146020 :     Real64 Euse = 0.0;              // Energy change due to use side mass flow over the DataGlobals::TimeStep (J)
    7678      1146020 :     Real64 Esource = 0.0;           // Energy change due to source side mass flow over the DataGlobals::TimeStep (J)
    7679      1146020 :     Real64 Eheater1 = 0.0;          // Energy change due to heater 1 over the DataGlobals::TimeStep (J)
    7680      1146020 :     Real64 Eheater2 = 0.0;          // Energy change due to heater 2 over the DataGlobals::TimeStep (J)
    7681      1146020 :     Real64 Eunmet = 0.0;            // Energy change unmet over the DataGlobals::TimeStep (J)
    7682      1146020 :     Real64 Event = 0.0;             // Energy change due to venting over the DataGlobals::TimeStep (J)
    7683      1146020 :     int CycleOnCount1_loc = 0;      // Number of times heater 1 cycles on in the current time step
    7684      1146020 :     int CycleOnCount2_loc = 0;      // Number of times heater 2 cycles on in the current time step
    7685      1146020 :     Real64 Runtime = 0.0;           // Time that either heater is running (s)
    7686      1146020 :     Real64 Runtime1 = 0.0;          // Time that heater 1 is running (s)
    7687      1146020 :     Real64 Runtime2 = 0.0;          // Time that heater 2 is running (s)
    7688      1146020 :     bool SetPointRecovered = false; // Flag to indicate when set point is recovered for the first time
    7689              :     // Added three variables for desuperheater sourceinlet temperature update
    7690              :     Real64 MdotDesuperheaterWater;        // mass flow rate of desuperheater source side water, kg/s
    7691      1146020 :     Real64 DesuperheaterPLR = 0.0;        // Desuperheater part load ratio
    7692      1146020 :     Real64 DesuperheaterHeaterRate = 0.0; // Desuperheater heater rate (W)
    7693      1146020 :     Real64 SourceInletTempSum = 0.0;      // Sum the source inlet temperature in sub time step to calculate average tempearature
    7694              :     Real64 Qheater1;                      // Heating rate of burner or electric heating element 1 (W)
    7695              :     Real64 Qheater2;                      // Heating rate of burner or electric heating element 2 (W)
    7696              : 
    7697      1146020 :     if (this->InletMode == InletPositionMode::Fixed) {
    7698       990387 :         CalcNodeMassFlows(InletPositionMode::Fixed);
    7699              :     }
    7700              : 
    7701              :     // Time remaining in the current DataGlobals::TimeStep (s)
    7702      1146020 :     Real64 TimeRemaining = SecInTimeStep;
    7703              : 
    7704              :     // Diff Eq. Coefficients for each node
    7705      1146020 :     std::vector<Real64> A;
    7706      1146020 :     A.resize(nTankNodes);
    7707      1146020 :     std::vector<Real64> B;
    7708      1146020 :     B.resize(nTankNodes);
    7709              : 
    7710              :     // Temperature at the end of the internal DataGlobals::TimeStep
    7711      1146020 :     std::vector<Real64> Tfinal;
    7712      1146020 :     Tfinal.resize(nTankNodes);
    7713              : 
    7714              :     // Average temperature of each node over the internal DataGlobals::TimeStep
    7715      1146020 :     std::vector<Real64> Tavg;
    7716      1146020 :     Tavg.resize(nTankNodes);
    7717              : 
    7718      1146020 :     int SubTimestepCount = 0;
    7719              : 
    7720      6321905 :     while (TimeRemaining > 0.0) {
    7721              : 
    7722      5175885 :         ++SubTimestepCount;
    7723              : 
    7724      5175885 :         bool PrevHeaterOn1 = this->HeaterOn1;
    7725      5175885 :         bool PrevHeaterOn2 = this->HeaterOn2;
    7726              : 
    7727      5175885 :         if (this->InletMode == InletPositionMode::Seeking) {
    7728       311442 :             CalcNodeMassFlows(InletPositionMode::Seeking);
    7729              :         }
    7730              : 
    7731              :         // Heater control logic
    7732      5175885 :         if (this->IsChilledWaterTank) {
    7733              :             // Chilled Water Tank, no heating
    7734       311442 :             Qheater1 = 0.0;
    7735       311442 :             Qheater2 = 0.0;
    7736              :         } else {
    7737              :             // Control the first heater element (master)
    7738      4864443 :             if (this->MaxCapacity > 0.0) {
    7739      2927138 :                 const Real64 &NodeTemp = this->Node(this->HeaterNode1).Temp;
    7740              : 
    7741      2927138 :                 if (this->HeaterOn1) {
    7742       307687 :                     if (NodeTemp >= this->SetPointTemp) {
    7743        47340 :                         this->HeaterOn1 = false;
    7744        47340 :                         SetPointRecovered = true;
    7745              :                     }
    7746              :                 } else { // Heater is off
    7747      2619451 :                     if (NodeTemp < MinTemp1) {
    7748        89293 :                         this->HeaterOn1 = true;
    7749        89293 :                         ++CycleOnCount1_loc;
    7750              :                     }
    7751              :                 }
    7752              :             }
    7753              : 
    7754      4864443 :             if (this->HeaterOn1) {
    7755       349677 :                 Qheater1 = this->MaxCapacity;
    7756              :             } else {
    7757      4514766 :                 Qheater1 = 0.0;
    7758              :             }
    7759              : 
    7760              :             // Control the second heater element (slave)
    7761      4864443 :             if (this->MaxCapacity2 > 0.0) {
    7762       756904 :                 if ((this->StratifiedControlMode == PriorityControlMode::MasterSlave) && this->HeaterOn1) {
    7763        30937 :                     this->HeaterOn2 = false;
    7764              : 
    7765              :                 } else {
    7766       725967 :                     const Real64 &NodeTemp = this->Node(this->HeaterNode2).Temp;
    7767              : 
    7768       725967 :                     if (this->HeaterOn2) {
    7769       422778 :                         if (NodeTemp >= this->SetPointTemp2) {
    7770         7028 :                             this->HeaterOn2 = false;
    7771         7028 :                             SetPointRecovered = true;
    7772              :                         }
    7773              :                     } else { // Heater is off
    7774       303189 :                         if (NodeTemp < MinTemp2) {
    7775        58361 :                             this->HeaterOn2 = true;
    7776        58361 :                             ++CycleOnCount2_loc;
    7777              :                         }
    7778              :                     }
    7779              :                 }
    7780              :             }
    7781              : 
    7782      4864443 :             if (this->HeaterOn2) {
    7783       474111 :                 Qheater2 = this->MaxCapacity2;
    7784              :             } else {
    7785      4390332 :                 Qheater2 = 0.0;
    7786              :             }
    7787              :         }
    7788              : 
    7789      5175885 :         if (SubTimestepCount == 1) {
    7790      1146020 :             dt = SubTimestepMin;
    7791              :         } else {
    7792              : 
    7793              :             // Set the maximum tank temperature change allowed
    7794      4029865 :             Real64 dT_max = std::numeric_limits<Real64>::max();
    7795      4029865 :             if (this->HeaterOn1) {
    7796       339991 :                 if (this->Node(this->HeaterNode1).Temp < this->SetPointTemp) {
    7797              :                     // Node temperature is less than setpoint and heater is on
    7798       339975 :                     dT_max = min(dT_max, this->SetPointTemp - this->Node(this->HeaterNode1).Temp);
    7799              :                 } else {
    7800              :                     // Node temperature is greater than or equal to setpoint and heater is on
    7801              :                     // Heater will turn off next time around, calculate assuming that
    7802           16 :                     dT_max = min(dT_max, this->Node(this->HeaterNode1).Temp - MinTemp1);
    7803              :                 }
    7804              :             } else { // Heater off
    7805      3689874 :                 if (this->Node(this->HeaterNode1).Temp >= MinTemp1) {
    7806              :                     // Node temperature is greater than or equal to cut in temperature and heater is off
    7807      2907526 :                     dT_max = min(dT_max, this->Node(this->HeaterNode1).Temp - MinTemp1);
    7808              :                 } else {
    7809              :                     // Heater will turn on next time around, calculate to setpoint
    7810       782348 :                     dT_max = min(dT_max, this->SetPointTemp - this->Node(this->HeaterNode1).Temp);
    7811              :                 }
    7812              :             }
    7813      4029865 :             if (this->HeaterOn2) {
    7814       454824 :                 if (this->Node(this->HeaterNode2).Temp < this->SetPointTemp2) {
    7815              :                     // Node temperature is less than setpoint and heater is on
    7816       454824 :                     dT_max = min(dT_max, this->SetPointTemp2 - this->Node(this->HeaterNode2).Temp);
    7817              :                 } else {
    7818              :                     // Node temperature is greater than or equal to setpoint and heater is on
    7819              :                     // Heater will turn off next time around, calculate assuming that
    7820            0 :                     dT_max = min(dT_max, this->Node(this->HeaterNode2).Temp - MinTemp2);
    7821              :                 }
    7822              :             } else { // Heater off
    7823      3575041 :                 if (this->Node(this->HeaterNode2).Temp >= MinTemp2) {
    7824              :                     // Node temperature is greater than or equal to cut in temperature and heater is off
    7825      1890064 :                     dT_max = min(dT_max, this->Node(this->HeaterNode2).Temp - MinTemp2);
    7826              :                 } else {
    7827              :                     // Heater will turn on next time around, calculate to setpoint
    7828      1684977 :                     dT_max = min(dT_max, this->SetPointTemp2 - this->Node(this->HeaterNode2).Temp);
    7829              :                 }
    7830              :             }
    7831              : 
    7832              :             // Make adjustments to A and B to account for heaters being on or off now
    7833      4029865 :             if (this->HeaterOn1 && !PrevHeaterOn1) {
    7834              :                 // If heater 1 is on now and wasn't before add the heat rate to the B term
    7835        88617 :                 B[this->HeaterNode1 - 1] += Qheater1 / (this->Node(this->HeaterNode1).Mass * Cp);
    7836      3941248 :             } else if (!this->HeaterOn1 && PrevHeaterOn1) {
    7837              :                 // If heater 1 is off now and was on before, remove the heat rate from the B term
    7838        46511 :                 B[this->HeaterNode1 - 1] -= this->MaxCapacity / (this->Node(this->HeaterNode1).Mass * Cp);
    7839              :             }
    7840      4029865 :             if (this->HeaterOn2 && !PrevHeaterOn2) {
    7841              :                 // If heater 2 is on now and wasn't before add the heat rate to the B term
    7842        57921 :                 B[this->HeaterNode2 - 1] += Qheater2 / (this->Node(this->HeaterNode2).Mass * Cp);
    7843      3971944 :             } else if (!this->HeaterOn2 && PrevHeaterOn2) {
    7844              :                 // If heater 1 is off now and was on before, remove the heat rate from the B term
    7845        12215 :                 B[this->HeaterNode2 - 1] -= this->MaxCapacity / (this->Node(this->HeaterNode2).Mass * Cp);
    7846              :             }
    7847              : 
    7848      4029865 :             if ((this->HeaterOn1 || this->HeaterOn2) && !(PrevHeaterOn1 || PrevHeaterOn2)) {
    7849              :                 // Remove off cycle loads
    7850              :                 // Apply on cycle loads
    7851      1322647 :                 for (int i = 0; i < nTankNodes; i++) {
    7852      1182048 :                     auto const &node = this->Node[i];
    7853      1182048 :                     Real64 NodeCapacitance = node.Mass * Cp;
    7854      1182048 :                     A[i] += (node.OffCycLossCoeff - node.OnCycLossCoeff) / NodeCapacitance;
    7855      1182048 :                     B[i] += (-node.OffCycParaLoad + node.OnCycParaLoad + (node.OnCycLossCoeff - node.OffCycLossCoeff) * this->AmbientTemp) /
    7856              :                             NodeCapacitance;
    7857              :                 }
    7858      4029865 :             } else if (!(this->HeaterOn1 || this->HeaterOn2) && (PrevHeaterOn1 || PrevHeaterOn2)) {
    7859              :                 // Remove on cycle loads
    7860              :                 // Apply off cycle loads
    7861       554773 :                 for (int i = 0; i < nTankNodes; i++) {
    7862       501986 :                     auto const &node = this->Node[i];
    7863       501986 :                     Real64 NodeCapacitance = node.Mass * Cp;
    7864       501986 :                     A[i] -= (node.OffCycLossCoeff - node.OnCycLossCoeff) / NodeCapacitance;
    7865       501986 :                     B[i] -= (-node.OffCycParaLoad + node.OnCycParaLoad + (node.OnCycLossCoeff - node.OffCycLossCoeff) * this->AmbientTemp) /
    7866              :                             NodeCapacitance;
    7867              :                 }
    7868              :             }
    7869              : 
    7870              :             // Set the sub DataGlobals::TimeStep (dt)
    7871      4029865 :             dt = TimeRemaining;
    7872     30580865 :             for (int i = 0; i < nTankNodes; ++i) {
    7873     26551000 :                 const Real64 Denominator = fabs(A[i] * Tavg[i] + B[i]);
    7874     26551000 :                 if (Denominator != 0.0) {
    7875     26513977 :                     dt = min(dt, dT_max / Denominator);
    7876              :                 }
    7877              :             }
    7878      4029865 :             dt = max(min(SubTimestepMin, TimeRemaining), dt);
    7879      4029865 :             dt = min(SubTimestepMax, dt);
    7880              :         }
    7881              : 
    7882              :         // Make initial guess that average and final temperatures over the DataGlobals::TimeStep are equal to the starting temperatures
    7883     39844127 :         for (int i = 0; i < nTankNodes; i++) {
    7884     34668242 :             const auto &NodeTemp = this->Node[i].Temp;
    7885     34668242 :             Tfinal[i] = NodeTemp;
    7886     34668242 :             Tavg[i] = NodeTemp;
    7887              :         }
    7888              : 
    7889     22992092 :         for (int ConvergenceCounter = 1; ConvergenceCounter <= 10; ConvergenceCounter++) {
    7890              : 
    7891     22634590 :             std::fill(A.begin(), A.end(), 0.0);
    7892     22634590 :             std::fill(B.begin(), B.end(), 0.0);
    7893              : 
    7894              :             // Heater Coefficients
    7895     22634590 :             B[this->HeaterNode1 - 1] += Qheater1;
    7896     22634590 :             B[this->HeaterNode2 - 1] += Qheater2;
    7897              : 
    7898    209030656 :             for (int i = 0; i < nTankNodes; i++) {
    7899    186396066 :                 const int NodeNum = i + 1;
    7900    186396066 :                 const auto &tank_node = this->Node(NodeNum);
    7901              : 
    7902              :                 // Parasitic Loads and Losses to Ambient
    7903    186396066 :                 if (this->HeaterOn1 || this->HeaterOn2) {
    7904              :                     // Parasitic Loads
    7905     32625970 :                     B[i] += tank_node.OnCycParaLoad;
    7906              :                     // Losses to Ambient
    7907     32625970 :                     A[i] += -tank_node.OnCycLossCoeff;
    7908     32625970 :                     B[i] += tank_node.OnCycLossCoeff * this->AmbientTemp;
    7909              :                 } else {
    7910              :                     // Parasitic Loads
    7911    153770096 :                     B[i] += tank_node.OffCycParaLoad;
    7912              :                     // Losses to Ambient
    7913    153770096 :                     A[i] += -tank_node.OffCycLossCoeff;
    7914    153770096 :                     B[i] += tank_node.OffCycLossCoeff * this->AmbientTemp;
    7915              :                 }
    7916              : 
    7917              :                 // Conduction to adjacent nodes
    7918    186396066 :                 A[i] += -(tank_node.CondCoeffDn + tank_node.CondCoeffUp);
    7919    186396066 :                 if (NodeNum > 1) {
    7920    163761476 :                     B[i] += tank_node.CondCoeffUp * Tavg[i - 1];
    7921              :                 }
    7922    186396066 :                 if (NodeNum < nTankNodes) {
    7923    163761476 :                     B[i] += tank_node.CondCoeffDn * Tavg[i + 1];
    7924              :                 }
    7925              : 
    7926              :                 // Use side plant connection
    7927    186396066 :                 const Real64 use_e_mdot_cp = tank_node.UseMassFlowRate * Cp;
    7928    186396066 :                 A[i] += -use_e_mdot_cp;
    7929    186396066 :                 B[i] += use_e_mdot_cp * this->UseInletTemp;
    7930              : 
    7931              :                 // Source side heat transfer rate
    7932    186396066 :                 if ((this->HeatPumpNum > 0) && (HPWHCondenserConfig == DataPlant::PlantEquipmentType::HeatPumpWtrHeaterPumped)) {
    7933              :                     // Pumped Condenser Heat Pump Water Heater
    7934    126820756 :                     if (tank_node.SourceMassFlowRate > 0.0) {
    7935     10512880 :                         B[i] += Qheatpump;
    7936              :                     }
    7937              :                 } else {
    7938              :                     // Source side plant connection (constant temperature)
    7939     59575310 :                     const Real64 src_e_mdot_cp = tank_node.SourceMassFlowRate * Cp;
    7940     59575310 :                     A[i] += -src_e_mdot_cp;
    7941     59575310 :                     B[i] += src_e_mdot_cp * this->SourceInletTemp;
    7942              :                 }
    7943              : 
    7944              :                 // Wrapped condenser heat pump water heater
    7945    186396066 :                 if ((this->HeatPumpNum > 0) && (HPWHCondenserConfig == DataPlant::PlantEquipmentType::HeatPumpWtrHeaterWrapped)) {
    7946     27582976 :                     B[i] += Qheatpump * tank_node.HPWHWrappedCondenserHeatingFrac;
    7947              :                 }
    7948              : 
    7949              :                 // Internodal flow
    7950    186396066 :                 A[i] += -(tank_node.MassFlowFromUpper + tank_node.MassFlowFromLower) * Cp;
    7951    186396066 :                 if (NodeNum > 1) {
    7952    163761476 :                     B[i] += tank_node.MassFlowFromUpper * Cp * Tavg[i - 1];
    7953              :                 }
    7954    186396066 :                 if (NodeNum < nTankNodes) {
    7955    163761476 :                     B[i] += tank_node.MassFlowFromLower * Cp * Tavg[i + 1];
    7956              :                 }
    7957              : 
    7958              :                 // Divide by mass and specific heat
    7959              :                 // m * cp * dT/dt = q_net  =>  dT/dt = a * T + b
    7960    186396066 :                 A[i] /= tank_node.Mass * Cp;
    7961    186396066 :                 B[i] /= tank_node.Mass * Cp;
    7962              : 
    7963              :             } // end for each node
    7964              : 
    7965              :             // Calculate the average and final temperatures over the interval
    7966     22634590 :             Real64 TfinalDiff = 0.0;
    7967    209030656 :             for (int i = 0; i < nTankNodes; ++i) {
    7968    186396066 :                 const Real64 Tstart = this->Node[i].Temp;
    7969    186396066 :                 const Real64 b_a = B[i] / A[i];
    7970    186396066 :                 const Real64 e_a_dt = exp(A[i] * dt);
    7971    186396066 :                 Tavg[i] = (Tstart + b_a) * (e_a_dt - 1.0) / (A[i] * dt) - b_a;
    7972    186396066 :                 const Real64 Tfinal_old = Tfinal[i];
    7973    186396066 :                 Tfinal[i] = (Tstart + b_a) * e_a_dt - b_a;
    7974    186396066 :                 TfinalDiff = max(fabs(Tfinal[i] - Tfinal_old), TfinalDiff);
    7975              :             }
    7976              : 
    7977     22634590 :             if (TfinalDiff < TemperatureConvergenceCriteria) {
    7978      4818383 :                 break;
    7979              :             }
    7980              : 
    7981     17816207 :             if (this->DesuperheaterNum > 0) {
    7982        47893 :                 DesuperheaterPLR = state.dataWaterThermalTanks->WaterHeaterDesuperheater(this->DesuperheaterNum).DesuperheaterPLR;
    7983        47893 :                 DesuperheaterHeaterRate = state.dataWaterThermalTanks->WaterHeaterDesuperheater(this->DesuperheaterNum).HeaterRate;
    7984        47893 :                 MdotDesuperheaterWater = state.dataWaterThermalTanks->WaterHeaterDesuperheater(this->DesuperheaterNum).OperatingWaterFlowRate *
    7985        47893 :                                          Psychrometrics::RhoH2O(Tavg[this->SourceOutletStratNode - 1]);
    7986        47893 :                 if (DesuperheaterPLR > 0.0 && MdotDesuperheaterWater > 0.0) {
    7987        34540 :                     this->SourceInletTemp =
    7988        34540 :                         Tavg[this->SourceOutletStratNode - 1] + (DesuperheaterHeaterRate / DesuperheaterPLR) / (MdotDesuperheaterWater * Cp);
    7989              :                 } else {
    7990        13353 :                     this->SourceInletTemp = Tavg[this->SourceOutletStratNode - 1];
    7991              :                 }
    7992              :             }
    7993              :         } // end temperature convergence loop
    7994              : 
    7995              :         // Inversion mixing
    7996              :         bool HasInversion;
    7997      8346126 :         do {
    7998      8346126 :             HasInversion = false;
    7999              :             // Starting from the top of the tank check if the node below has a temperature inversion.
    8000     48430959 :             for (int j = 0; j < nTankNodes - 1; ++j) {
    8001     43255074 :                 if (Tfinal[j] < Tfinal[j + 1]) {
    8002              : 
    8003              :                     // Temperature inversion!
    8004      3170241 :                     HasInversion = true;
    8005              : 
    8006              :                     // From the node above the inversion, move down calculating a weighted average
    8007              :                     // of node temperatures until the node below the group of mixed nodes isn't hotter
    8008              :                     // or we hit the bottom of the tank.
    8009      3170241 :                     Real64 Tmixed = 0.0;
    8010      3170241 :                     Real64 MassMixed = 0.0;
    8011              :                     int m;
    8012     15598481 :                     for (m = j; m < nTankNodes; ++m) {
    8013     15598481 :                         Tmixed += Tfinal[m] * this->Node[m].Mass;
    8014     15598481 :                         MassMixed += this->Node[m].Mass;
    8015     15598481 :                         if ((m == nTankNodes - 1) || (Tmixed / MassMixed > Tfinal[m + 1])) {
    8016      3170241 :                             break;
    8017              :                         }
    8018              :                     }
    8019      3170241 :                     Tmixed /= MassMixed;
    8020              : 
    8021              :                     // Now we have a range of nodes (j = top, m = bottom) that are mixed
    8022              :                     // and the mixed temperature (Tmixed).
    8023              :                     // Move through the mixed nodes and set the final temperature to the mixed temperature.
    8024              :                     // Also calculate a corrected average temperature for each node.
    8025     18768722 :                     for (int k = j; k <= m; ++k) {
    8026              :                         Real64 FinalFactorMixing;
    8027              :                         Real64 AvgFactorMixing;
    8028     15598481 :                         const Real64 NodeCapacitance = this->Node[k].Mass * Cp;
    8029     15598481 :                         if (A[k] == 0.0) {
    8030            0 :                             FinalFactorMixing = dt / NodeCapacitance;
    8031            0 :                             AvgFactorMixing = FinalFactorMixing / 2.0;
    8032              :                         } else {
    8033     15598481 :                             FinalFactorMixing = (exp(A[k] * dt) - 1.0) / A[k] / NodeCapacitance;
    8034     15598481 :                             AvgFactorMixing = ((exp(A[k] * dt) - 1.0) / A[k] / dt - 1.0) / A[k] / NodeCapacitance;
    8035              :                         }
    8036     15598481 :                         const Real64 Q_AdiabaticMixing = (Tmixed - Tfinal[k]) / FinalFactorMixing;
    8037     15598481 :                         Tfinal[k] = Tmixed;
    8038     15598481 :                         Tavg[k] += Q_AdiabaticMixing * AvgFactorMixing;
    8039              :                     }
    8040              : 
    8041              :                     // Since we mixed, get out of here and start from the top to check again for mixing.
    8042      3170241 :                     break;
    8043              :                 }
    8044              :             }
    8045              :         } while (HasInversion);
    8046              : 
    8047              :         // Venting
    8048      5175885 :         if (!this->IsChilledWaterTank) {
    8049      4864443 :             if (Tfinal[0] > this->TankTempLimit) {
    8050      1056270 :                 for (int i = 0; i < nTankNodes; ++i) {
    8051       912834 :                     if (Tfinal[i] > this->TankTempLimit) {
    8052       364737 :                         Event += this->Node[i].Mass * Cp * (this->TankTempLimit - Tfinal[i]);
    8053       364737 :                         Tfinal[i] = this->TankTempLimit;
    8054              :                     }
    8055              :                 }
    8056              :             }
    8057              :         }
    8058              : 
    8059              :         // Increment to next internal time step
    8060      5175885 :         TimeRemaining -= dt;
    8061      5175885 :         Real64 Qloss = 0.0;
    8062     39844127 :         for (int i = 0; i < nTankNodes; ++i) {
    8063     34668242 :             auto &node = this->Node[i];
    8064     34668242 :             node.Temp = Tfinal[i];
    8065     34668242 :             node.TempSum += Tavg[i] * dt;
    8066              : 
    8067              :             // Bookkeeping for reporting variables, mostly for Qunmet.
    8068     34668242 :             Real64 Qloss_node = (this->AmbientTemp - Tavg[i]);
    8069              :             Real64 Qheat_node;
    8070     34668242 :             const Real64 Quse_node = node.UseMassFlowRate * Cp * (this->UseInletTemp - Tavg[i]);
    8071    104004726 :             const Real64 Qsource_node = [&] {
    8072     34668242 :                 if (this->HeatPumpNum > 0) {
    8073     28440288 :                     if (HPWHCondenserConfig == DataPlant::PlantEquipmentType::HeatPumpWtrHeaterPumped) {
    8074     21912506 :                         if (node.SourceMassFlowRate > 0.0) {
    8075      1594749 :                             return Qheatpump;
    8076              :                         } else {
    8077     20317757 :                             return 0.0;
    8078              :                         }
    8079              :                     } else {
    8080      6527782 :                         assert(HPWHCondenserConfig == DataPlant::PlantEquipmentType::HeatPumpWtrHeaterWrapped);
    8081      6527782 :                         return Qheatpump * node.HPWHWrappedCondenserHeatingFrac;
    8082              :                     }
    8083              :                 } else {
    8084      6227954 :                     return node.SourceMassFlowRate * Cp * (this->SourceInletTemp - Tavg[i]);
    8085              :                 }
    8086     34668242 :             }();
    8087              : 
    8088     34668242 :             if (this->HeaterOn1 || this->HeaterOn2) {
    8089      6279800 :                 Qloss_node *= node.OnCycLossCoeff;
    8090      6279800 :                 Qheat_node = node.OnCycParaLoad * this->OnCycParaFracToTank;
    8091              :             } else {
    8092     28388442 :                 Qloss_node *= node.OffCycLossCoeff;
    8093     28388442 :                 Qheat_node = node.OffCycParaLoad * this->OffCycParaFracToTank;
    8094              :             }
    8095     34668242 :             Qloss += Qloss_node;
    8096     34668242 :             const Real64 Qneeded_node = max(-Quse_node - Qsource_node - Qloss_node - Qheat_node, 0.0);
    8097     34668242 :             const Real64 Qunmet_node = max(Qneeded_node - Qheater1 - Qheater2, 0.0);
    8098     34668242 :             Eunmet += Qunmet_node * dt;
    8099              :         }
    8100      5175885 :         SourceInletTempSum += this->SourceInletTemp * dt;
    8101              :         // More bookkeeping for reporting variables
    8102      5175885 :         Eloss += Qloss * dt;
    8103      5175885 :         const Real64 Quse = (this->UseOutletStratNode > 0)
    8104      5175885 :                                 ? this->UseEffectiveness * this->UseMassFlowRate * Cp * (this->UseInletTemp - Tavg[this->UseOutletStratNode - 1])
    8105      5175885 :                                 : 0.0;
    8106      5175885 :         Euse += Quse * dt;
    8107     15527655 :         const Real64 Qsource = [&] {
    8108      5175885 :             if (this->HeatPumpNum > 0) {
    8109      4392702 :                 if (HPWHCondenserConfig == DataPlant::PlantEquipmentType::HeatPumpWtrHeaterPumped) {
    8110      2459147 :                     return Qheatpump;
    8111              :                 } else {
    8112      1933555 :                     assert(HPWHCondenserConfig == DataPlant::PlantEquipmentType::HeatPumpWtrHeaterWrapped);
    8113      1933555 :                     return 0.0;
    8114              :                 }
    8115              :             } else {
    8116       783183 :                 if (this->SourceOutletStratNode > 0) {
    8117       575437 :                     return this->SourceEffectiveness * this->SourceMassFlowRate * Cp *
    8118       575437 :                            (this->SourceInletTemp - Tavg[this->SourceOutletStratNode - 1]);
    8119              :                 } else {
    8120       207746 :                     return 0.0;
    8121              :                 }
    8122              :             }
    8123      5175885 :         }();
    8124      5175885 :         Esource += Qsource * dt;
    8125      5175885 :         if (this->HeaterOn1) {
    8126       349677 :             Runtime1 += dt;
    8127              :         }
    8128      5175885 :         if (this->HeaterOn2) {
    8129       474111 :             Runtime2 += dt;
    8130              :         }
    8131      5175885 :         if (this->HeaterOn1 || this->HeaterOn2) {
    8132       823788 :             Runtime += dt;
    8133              :         }
    8134      5175885 :         Eheater1 += Qheater1 * dt;
    8135      5175885 :         Eheater2 += Qheater2 * dt;
    8136              : 
    8137              :         // Calculation for standard ratings
    8138      5175885 :         if (!this->FirstRecoveryDone) {
    8139              :             Real64 Qrecovery;
    8140      3142507 :             if (this->HeaterOn1 || this->HeaterOn2) {
    8141       110333 :                 Qrecovery = (Qheater1 + Qheater1) / this->Efficiency + this->OnCycParaLoad;
    8142              :             } else {
    8143      3032174 :                 Qrecovery = this->OffCycParaLoad;
    8144              :             }
    8145      3142507 :             this->FirstRecoveryFuel += Qrecovery * dt;
    8146      3142507 :             if (SetPointRecovered) {
    8147           29 :                 this->FirstRecoveryDone = true;
    8148              :             }
    8149              :         }
    8150              :     } // end while TimeRemaining > 0.0
    8151              : 
    8152      9263262 :     for (auto &e : this->Node) {
    8153      8117242 :         e.TempAvg = e.TempSum / SecInTimeStep;
    8154      8117242 :         e.TempSum = 0.0;
    8155              :     }
    8156              : 
    8157      1146020 :     this->TankTemp = sum(this->Node, &StratifiedNodeData::Temp) / this->Nodes;
    8158      1146020 :     this->TankTempAvg = sum(this->Node, &StratifiedNodeData::TempAvg) / this->Nodes;
    8159              : 
    8160      1146020 :     if (!state.dataGlobal->WarmupFlag) {
    8161              :         // Warn for potential freezing when avg of final temp over all nodes is below 2°C (nearing 0°C)
    8162       251621 :         if (this->TankTemp < 2) {
    8163            0 :             if (this->FreezingErrorIndex == 0) {
    8164            0 :                 ShowWarningError(state,
    8165            0 :                                  format("{}: {} = '{}':  Temperature of tank < 2C indicates of possibility of freeze. Tank Temperature = {:.2R} C.",
    8166              :                                         RoutineName,
    8167            0 :                                         this->Type,
    8168            0 :                                         this->Name,
    8169            0 :                                         this->TankTemp));
    8170            0 :                 ShowContinueErrorTimeStamp(state, "");
    8171              :             }
    8172            0 :             ShowRecurringWarningErrorAtEnd(state,
    8173            0 :                                            this->Type + " = '" + this->Name + "':  Temperature of tank < 2C indicates of possibility of freeze",
    8174            0 :                                            this->FreezingErrorIndex,
    8175            0 :                                            this->TankTemp, // Report Max
    8176            0 :                                            this->TankTemp, // Report Min
    8177              :                                            _,              // Don't report Sum
    8178              :                                            "{C}",          // Max Unit
    8179              :                                            "{C}");         // Min Unit
    8180              :         }
    8181              :     }
    8182              : 
    8183      1146020 :     if (this->UseOutletStratNode > 0) {
    8184      1146020 :         this->UseOutletTemp = this->Node(this->UseOutletStratNode).TempAvg;
    8185              :         // Revised use outlet temperature to ensure energy balance. Assumes a constant CP. CR8341/CR8570
    8186      1146020 :         if (this->UseMassFlowRate > 0.0) {
    8187       885741 :             this->UseOutletTemp = this->UseInletTemp * (1.0 - this->UseEffectiveness) + this->UseOutletTemp * this->UseEffectiveness;
    8188              :         }
    8189              :     }
    8190              : 
    8191      1146020 :     if (HPWHCondenserConfig == DataPlant::PlantEquipmentType::HeatPumpWtrHeaterWrapped) {
    8192              :         // If we have a wrapped condenser HPWH, set the source outlet to the weighted average of the node
    8193              :         // temperatures the condenser sees
    8194       476567 :         Real64 WeightedAverageSourceOutletTemp(0.0);
    8195      2912883 :         for (int i = 1; i <= this->Nodes; ++i) {
    8196      2436316 :             WeightedAverageSourceOutletTemp += this->Node(i).TempAvg * this->Node(i).HPWHWrappedCondenserHeatingFrac;
    8197              :         }
    8198       476567 :         this->SourceOutletTemp = WeightedAverageSourceOutletTemp;
    8199       669453 :     } else if (this->SourceOutletStratNode > 0) {
    8200              :         // otherwise set it to the temperature of the source outlet node
    8201       605659 :         this->SourceOutletTemp = this->Node(this->SourceOutletStratNode).TempAvg;
    8202              :         // Output the average inlet temperature for the DataGlobals::TimeStep
    8203       605659 :         this->SourceInletTemp = SourceInletTempSum / SecInTimeStep;
    8204              :     }
    8205      1146020 :     if (HPWHCondenserConfig == DataPlant::PlantEquipmentType::HeatPumpWtrHeaterPumped) {
    8206              :         // For pumped condensers, set the source inlet and outlets to match the delta T
    8207              :         // across the water side of the DX coil.
    8208       424875 :         HeatPumpWaterHeaterData const &HeatPump = state.dataWaterThermalTanks->HPWaterHeater(this->HeatPumpNum);
    8209       424875 :         DataLoopNode::NodeData const &HPWHCondWaterInletNode = state.dataLoopNodes->Node(HeatPump.CondWaterInletNode);
    8210       424875 :         DataLoopNode::NodeData const &HPWHCondWaterOutletNode = state.dataLoopNodes->Node(HeatPump.CondWaterOutletNode);
    8211       424875 :         Real64 const HPWHCondenserDeltaT = HPWHCondWaterOutletNode.Temp - HPWHCondWaterInletNode.Temp;
    8212       424875 :         this->SourceInletTemp = this->SourceOutletTemp + HPWHCondenserDeltaT;
    8213              :     }
    8214              : 
    8215              :     // Revised source outlet temperature to ensure energy balance. Assumes a constant CP. CR8341/CR8570
    8216      1146020 :     if (this->SourceOutletStratNode > 0) {
    8217       605659 :         if (this->SourceMassFlowRate > 0.0) {
    8218       277242 :             this->SourceOutletTemp = this->SourceInletTemp * (1.0 - this->SourceEffectiveness) + this->SourceOutletTemp * this->SourceEffectiveness;
    8219              :         }
    8220              :     }
    8221              : 
    8222      1146020 :     this->LossRate = Eloss / SecInTimeStep;
    8223      1146020 :     this->UseRate = Euse / SecInTimeStep;
    8224      1146020 :     Real64 WrappedCondenserHeatPumpRate = 0.0;
    8225      1146020 :     if ((this->HeatPumpNum > 0) && (HPWHCondenserConfig == DataPlant::PlantEquipmentType::HeatPumpWtrHeaterPumped)) {
    8226       424875 :         this->SourceRate = Qheatpump;
    8227              :     } else {
    8228       721145 :         this->SourceRate = Esource / SecInTimeStep;
    8229       721145 :         WrappedCondenserHeatPumpRate = Qheatpump;
    8230              :     }
    8231              : 
    8232      1146020 :     this->OffCycParaFuelRate = this->OffCycParaLoad * (SecInTimeStep - Runtime) / SecInTimeStep;
    8233      1146020 :     this->OnCycParaFuelRate = this->OnCycParaLoad * Runtime / SecInTimeStep;
    8234      1146020 :     this->OffCycParaRateToTank = this->OffCycParaFuelRate * this->OffCycParaFracToTank;
    8235      1146020 :     this->OnCycParaRateToTank = this->OnCycParaFuelRate * this->OnCycParaFracToTank;
    8236      1146020 :     this->TotalDemandRate =
    8237      1146020 :         -this->UseRate - this->SourceRate - this->LossRate - this->OffCycParaRateToTank - this->OnCycParaRateToTank - WrappedCondenserHeatPumpRate;
    8238      1146020 :     this->HeaterRate1 = Eheater1 / SecInTimeStep;
    8239      1146020 :     this->HeaterRate2 = Eheater2 / SecInTimeStep;
    8240      1146020 :     this->HeaterRate = this->HeaterRate1 + this->HeaterRate2;
    8241              : 
    8242      1146020 :     this->UnmetRate = Eunmet / SecInTimeStep;
    8243      1146020 :     this->VentRate = Event / SecInTimeStep;
    8244      1146020 :     this->NetHeatTransferRate = this->UseRate + this->SourceRate + this->LossRate + this->OffCycParaRateToTank + this->OnCycParaRateToTank +
    8245      1146020 :                                 this->HeaterRate + this->VentRate + WrappedCondenserHeatPumpRate;
    8246              : 
    8247      1146020 :     this->CycleOnCount = CycleOnCount1_loc + CycleOnCount2_loc;
    8248      1146020 :     this->CycleOnCount1 = CycleOnCount1_loc;
    8249      1146020 :     this->CycleOnCount2 = CycleOnCount2_loc;
    8250              : 
    8251      1146020 :     this->RuntimeFraction = Runtime / SecInTimeStep;
    8252      1146020 :     this->RuntimeFraction1 = Runtime1 / SecInTimeStep;
    8253      1146020 :     this->RuntimeFraction2 = Runtime2 / SecInTimeStep;
    8254              : 
    8255      1146020 :     this->FuelRate = (Eheater1 + Eheater2) / this->Efficiency / SecInTimeStep;
    8256              : 
    8257              :     // Add water heater skin losses and venting losses to ambient zone, if specified
    8258      1146020 :     if (this->AmbientTempZone > 0) {
    8259       633391 :         this->AmbientZoneGain = -this->LossRate * this->SkinLossFracToZone - this->VentRate;
    8260              :     }
    8261      1146020 : }
    8262              : 
    8263      1301829 : void WaterThermalTankData::CalcNodeMassFlows(InletPositionMode inletMode)
    8264              : {
    8265              : 
    8266              :     // SUBROUTINE INFORMATION:
    8267              :     //       AUTHOR         Peter Graham Ellis
    8268              :     //       DATE WRITTEN   January 2007
    8269              :     //       MODIFIED       na
    8270              :     //       RE-ENGINEERED  na
    8271              : 
    8272              :     // PURPOSE OF THIS SUBROUTINE:
    8273              :     // Determines mass flow rates between nodes according to the locations of the use- and source-side inlet and outlet
    8274              :     // nodes.
    8275              : 
    8276              :     // METHODOLOGY EMPLOYED:
    8277              :     // In 'Seeking' mode, nodes are searched between the user-specified inlet and outlet nodes to find the node closest
    8278              :     // in temperature to the inlet fluid temperature.  In 'Fixed' mode, the user-specified nodes are always used.
    8279              :     // Upward and downward flows are added to each node between an inlet and outlet.  Flows in both directions cancel out
    8280              :     // to leave only the net flow in one direction.
    8281              : 
    8282      1301829 :     int useInletStratNod = this->UseInletStratNode;
    8283      1301829 :     int useOutletStratNode = this->UseOutletStratNode;
    8284      1301829 :     int sourceInletStratNode = this->SourceInletStratNode;
    8285      1301829 :     int sourceOutletStratNode = this->SourceOutletStratNode;
    8286              : 
    8287      1301829 :     Real64 useMassFlowRate = this->UseMassFlowRate * this->UseEffectiveness;
    8288      1301829 :     Real64 sourceMassFlowRate = this->SourceMassFlowRate * this->SourceEffectiveness;
    8289              : 
    8290     10353925 :     for (auto &e : this->Node) {
    8291      9052096 :         e.UseMassFlowRate = 0.0;
    8292      9052096 :         e.SourceMassFlowRate = 0.0;
    8293      9052096 :         e.MassFlowFromUpper = 0.0;
    8294      9052096 :         e.MassFlowFromLower = 0.0;
    8295      9052096 :         e.MassFlowToUpper = 0.0;
    8296      9052096 :         e.MassFlowToLower = 0.0;
    8297              :     }
    8298              : 
    8299      1301829 :     if (inletMode == InletPositionMode::Seeking) {
    8300              :         // 'Seek' the node with the temperature closest to the inlet temperature
    8301              :         // Start at the user-specified inlet node and search to the user-specified outlet node
    8302              :         int Step;
    8303       311442 :         if (useMassFlowRate > 0.0) {
    8304       143208 :             if (useInletStratNod > useOutletStratNode) {
    8305            0 :                 Step = -1;
    8306              :             } else {
    8307       143208 :                 Step = 1;
    8308              :             }
    8309       143208 :             Real64 MinDeltaTemp = 1.0e6; // Some big number
    8310       143208 :             int const NodeNum_stop(floop_end(useInletStratNod, useOutletStratNode, Step));
    8311       456902 :             for (int NodeNum = useInletStratNod; NodeNum != NodeNum_stop; NodeNum += Step) {
    8312       423205 :                 Real64 DeltaTemp = std::abs(this->Node(NodeNum).Temp - this->UseInletTemp);
    8313       423205 :                 if (DeltaTemp < MinDeltaTemp) {
    8314       229690 :                     MinDeltaTemp = DeltaTemp;
    8315       229690 :                     useInletStratNod = NodeNum;
    8316       193515 :                 } else if (DeltaTemp > MinDeltaTemp) {
    8317       109511 :                     break;
    8318              :                 }
    8319              :             }
    8320              :         }
    8321              : 
    8322       311442 :         if (sourceMassFlowRate > 0.0) {
    8323        46870 :             if (sourceInletStratNode > sourceOutletStratNode) {
    8324        46870 :                 Step = -1;
    8325              :             } else {
    8326            0 :                 Step = 1;
    8327              :             }
    8328        46870 :             Real64 MinDeltaTemp = 1.0e6; // Some big number
    8329        46870 :             int const NodeNum_stop(floop_end(sourceInletStratNode, sourceOutletStratNode, Step));
    8330        94488 :             for (int NodeNum = sourceInletStratNode; NodeNum != NodeNum_stop; NodeNum += Step) {
    8331        94488 :                 Real64 DeltaTemp = std::abs(this->Node(NodeNum).Temp - this->SourceInletTemp);
    8332        94488 :                 if (DeltaTemp < MinDeltaTemp) {
    8333        46870 :                     MinDeltaTemp = DeltaTemp;
    8334        46870 :                     sourceInletStratNode = NodeNum;
    8335        47618 :                 } else if (DeltaTemp > MinDeltaTemp) {
    8336        46870 :                     break;
    8337              :                 }
    8338              :             }
    8339              :         }
    8340              :     }
    8341              : 
    8342      1301829 :     if (useInletStratNod > 0) {
    8343      1301829 :         this->Node(useInletStratNod).UseMassFlowRate = useMassFlowRate;
    8344              :     }
    8345      1301829 :     if (sourceInletStratNode > 0) {
    8346       709773 :         this->Node(sourceInletStratNode).SourceMassFlowRate = sourceMassFlowRate;
    8347              :     }
    8348              : 
    8349      1301829 :     if (useMassFlowRate > 0.0) {
    8350       957384 :         if (useOutletStratNode > useInletStratNod) {
    8351              :             // Use-side flow is down
    8352       770408 :             for (int NodeNum = useInletStratNod; NodeNum <= useOutletStratNode - 1; ++NodeNum) {
    8353       629558 :                 this->Node(NodeNum).MassFlowToLower += useMassFlowRate;
    8354              :             }
    8355       770408 :             for (int NodeNum = useInletStratNod + 1; NodeNum <= useOutletStratNode; ++NodeNum) {
    8356       629558 :                 this->Node(NodeNum).MassFlowFromUpper += useMassFlowRate;
    8357              :             }
    8358              : 
    8359       816534 :         } else if (useOutletStratNode < useInletStratNod) {
    8360              :             // Use-side flow is up
    8361      5148062 :             for (int NodeNum = useOutletStratNode; NodeNum <= useInletStratNod - 1; ++NodeNum) {
    8362      4631310 :                 this->Node(NodeNum).MassFlowFromLower += useMassFlowRate;
    8363              :             }
    8364      5148062 :             for (int NodeNum = useOutletStratNode + 1; NodeNum <= useInletStratNod; ++NodeNum) {
    8365      4631310 :                 this->Node(NodeNum).MassFlowToUpper += useMassFlowRate;
    8366              :             }
    8367              : 
    8368              :         } else {
    8369              :             // Use-side flow is across the node; no flow to other nodes
    8370              :         }
    8371              :     }
    8372              : 
    8373      1301829 :     if (sourceMassFlowRate > 0.0) {
    8374       300677 :         if (sourceOutletStratNode > sourceInletStratNode) {
    8375              :             // Source-side flow is down
    8376       672770 :             for (int NodeNum = sourceInletStratNode; NodeNum <= sourceOutletStratNode - 1; ++NodeNum) {
    8377       574385 :                 this->Node(NodeNum).MassFlowToLower += sourceMassFlowRate;
    8378              :             }
    8379       672770 :             for (int NodeNum = sourceInletStratNode + 1; NodeNum <= sourceOutletStratNode; ++NodeNum) {
    8380       574385 :                 this->Node(NodeNum).MassFlowFromUpper += sourceMassFlowRate;
    8381              :             }
    8382              : 
    8383       202292 :         } else if (sourceOutletStratNode < sourceInletStratNode) {
    8384              :             // Source-side flow is up
    8385      1135967 :             for (int NodeNum = sourceOutletStratNode; NodeNum <= sourceInletStratNode - 1; ++NodeNum) {
    8386       933675 :                 this->Node(NodeNum).MassFlowFromLower += sourceMassFlowRate;
    8387              :             }
    8388      1135967 :             for (int NodeNum = sourceOutletStratNode + 1; NodeNum <= sourceInletStratNode; ++NodeNum) {
    8389       933675 :                 this->Node(NodeNum).MassFlowToUpper += sourceMassFlowRate;
    8390              :             }
    8391              : 
    8392              :         } else {
    8393              :             // Source-side flow is across the node; no flow to other nodes
    8394              :         }
    8395              :     }
    8396              : 
    8397              :     // Cancel out any up and down flows
    8398     10353925 :     for (int NodeNum = 1; NodeNum <= this->Nodes; ++NodeNum) {
    8399      9052096 :         this->Node(NodeNum).MassFlowFromUpper = max((this->Node(NodeNum).MassFlowFromUpper - this->Node(NodeNum).MassFlowToUpper), 0.0);
    8400      9052096 :         this->Node(NodeNum).MassFlowFromLower = max((this->Node(NodeNum).MassFlowFromLower - this->Node(NodeNum).MassFlowToLower), 0.0);
    8401              :     }
    8402      1301829 : }
    8403              : 
    8404        29484 : void WaterThermalTankData::CalcDesuperheaterWaterHeater(EnergyPlusData &state, bool const FirstHVACIteration)
    8405              : {
    8406              : 
    8407              :     // SUBROUTINE INFORMATION:
    8408              :     //       AUTHOR         Richard Raustad
    8409              :     //       DATE WRITTEN   July 2005
    8410              :     //       MODIFIED       na
    8411              :     //       RE-ENGINEERED  na
    8412              : 
    8413              :     // PURPOSE OF THIS SUBROUTINE:
    8414              :     // Simulates a refrigerant desuperheater to heat water
    8415              : 
    8416              :     // METHODOLOGY EMPLOYED:
    8417              :     // This model uses the rated heat reclaim recovery efficiency, recovery efficiency modifier curve,
    8418              :     // set point temperature, and dead band temperature difference to simulate the desuperheater coil
    8419              :     // and sets up inputs to the tank model associated with the desuperheater coil
    8420              : 
    8421        29484 :     int constexpr MaxIte(500); // Maximum number of iterations for RegulaFalsi
    8422              : 
    8423        29484 :     auto &DesupHtr = state.dataWaterThermalTanks->WaterHeaterDesuperheater(this->DesuperheaterNum);
    8424              : 
    8425        29484 :     int WaterInletNode = DesupHtr.WaterInletNode;
    8426        29484 :     int WaterOutletNode = DesupHtr.WaterOutletNode;
    8427              : 
    8428              :     // store first iteration tank temperature and desuperheater mode of operation
    8429        29484 :     if (FirstHVACIteration && !state.dataHVACGlobal->ShortenTimeStepSys && DesupHtr.FirstTimeThroughFlag) {
    8430              :         // Save conditions from end of previous system timestep
    8431              :         // Every iteration that does not advance time should reset to these values
    8432        13796 :         this->SavedTankTemp = this->TankTemp;
    8433        13796 :         this->SavedSourceOutletTemp = this->SourceOutletTemp;
    8434        13796 :         DesupHtr.SaveMode = DesupHtr.Mode;
    8435        13796 :         DesupHtr.FirstTimeThroughFlag = false;
    8436              :     }
    8437              : 
    8438        15688 :     else if (!FirstHVACIteration) {
    8439        14742 :         DesupHtr.FirstTimeThroughFlag = true;
    8440              :     }
    8441              : 
    8442              :     // initialize variables before invoking any RETURN statement
    8443        29484 :     this->SourceMassFlowRate = 0.0;
    8444              :     // reset tank inlet temp from previous time step
    8445        29484 :     this->SourceInletTemp = this->SavedSourceOutletTemp;
    8446        29484 :     DesupHtr.DesuperheaterPLR = 0.0;
    8447              : 
    8448        29484 :     state.dataLoopNodes->Node(WaterInletNode).MassFlowRate = 0.0;
    8449        29484 :     state.dataLoopNodes->Node(WaterOutletNode).MassFlowRate = 0.0;
    8450        29484 :     state.dataLoopNodes->Node(WaterOutletNode).Temp = this->SavedSourceOutletTemp;
    8451              : 
    8452        29484 :     DesupHtr.DesuperheaterPLR = 0.0;
    8453        29484 :     DesupHtr.OnCycParaFuelRate = 0.0;
    8454        29484 :     DesupHtr.OnCycParaFuelEnergy = 0.0;
    8455        29484 :     DesupHtr.OffCycParaFuelRate = 0.0;
    8456        29484 :     DesupHtr.OffCycParaFuelEnergy = 0.0;
    8457        29484 :     DesupHtr.HEffFTempOutput = 0.0;
    8458        29484 :     DesupHtr.HeaterRate = 0.0;
    8459        29484 :     DesupHtr.HeaterEnergy = 0.0;
    8460        29484 :     DesupHtr.PumpPower = 0.0;
    8461        29484 :     DesupHtr.PumpEnergy = 0.0;
    8462              : 
    8463              :     // simulate only the water heater tank if the desuperheater coil is scheduled off
    8464        29484 :     Real64 AvailSchedule = DesupHtr.availSched->getCurrentVal();
    8465        29484 :     if (AvailSchedule == 0.0) {
    8466            0 :         DesupHtr.Mode = TankOperatingMode::Floating;
    8467            0 :         this->CalcWaterThermalTank(state);
    8468        18199 :         return;
    8469              :     }
    8470              : 
    8471              :     // simulate only the water heater tank if the lowest temperature available from the desuperheater coil
    8472              :     // is less than water inlet temperature if the reclaim source is a refrigeration condenser
    8473        29484 :     if (DesupHtr.ValidSourceType) {
    8474        29484 :         int SourceID = DesupHtr.ReclaimHeatingSourceIndexNum;
    8475        29484 :         if (DesupHtr.ReclaimHeatingSource == ReclaimHeatObjectType::CondenserRefrigeration) {
    8476         4602 :             if (state.dataHeatBal->HeatReclaimRefrigCondenser(SourceID).AvailTemperature <= this->SourceInletTemp) {
    8477           24 :                 DesupHtr.Mode = TankOperatingMode::Floating;
    8478           24 :                 this->CalcWaterThermalTank(state);
    8479          168 :                 ShowRecurringWarningErrorAtEnd(state,
    8480           48 :                                                "WaterHeating:Desuperheater " + DesupHtr.Name +
    8481              :                                                    " - Waste heat source temperature was too low to be useful.",
    8482           24 :                                                DesupHtr.InsuffTemperatureWarn);
    8483           24 :                 return;
    8484              :             } // Temp too low
    8485              :         } // desuperheater source is condenser_refrigeration
    8486              :     } // validsourcetype
    8487              : 
    8488        29460 :     DesupHtr.OffCycParaFuelRate = DesupHtr.OffCycParaLoad;
    8489        29460 :     DesupHtr.OffCycParaFuelEnergy = DesupHtr.OffCycParaFuelRate * state.dataHVACGlobal->TimeStepSysSec;
    8490              : 
    8491              :     // check that water heater tank cut-in temp is greater than desuperheater cut-in temp
    8492        29460 :     Real64 desupHtrSetPointTemp = DesupHtr.SetPointTemp;
    8493        29460 :     Real64 DeadBandTempDiff = DesupHtr.DeadBandTempDiff;
    8494        29460 :     if ((desupHtrSetPointTemp - DeadBandTempDiff) <= this->SetPointTemp) {
    8495            4 :         if (!state.dataGlobal->WarmupFlag && !state.dataGlobal->DoingSizing && !state.dataGlobal->KickOffSimulation) {
    8496            0 :             Real64 MinTemp = desupHtrSetPointTemp - DeadBandTempDiff;
    8497            0 :             ++DesupHtr.SetPointError;
    8498            0 :             if (DesupHtr.SetPointError < 5) {
    8499            0 :                 ShowWarningError(state,
    8500            0 :                                  format("{} \"{}\":  Water heater tank set point temperature is greater than or equal to the cut-in temperature of "
    8501              :                                         "the desuperheater. Desuperheater will be disabled.",
    8502            0 :                                         DesupHtr.Type,
    8503            0 :                                         DesupHtr.Name));
    8504            0 :                 ShowContinueErrorTimeStamp(state, format(" ...Desuperheater cut-in temperature = {:.2R}", MinTemp));
    8505              :             } else {
    8506            0 :                 ShowRecurringWarningErrorAtEnd(state,
    8507            0 :                                                DesupHtr.Type + " \"" + DesupHtr.Name +
    8508              :                                                    "\":  Water heater tank set point temperature is greater than or equal to the cut-in "
    8509              :                                                    "temperature of the desuperheater. Desuperheater will be disabled warning continues...",
    8510            0 :                                                DesupHtr.SetPointErrIndex1,
    8511              :                                                MinTemp,
    8512              :                                                MinTemp);
    8513              :             }
    8514              :         }
    8515              : 
    8516              :         //   Simulate tank if desuperheater unavailable for water heating
    8517            4 :         this->CalcWaterThermalTank(state);
    8518            4 :         return;
    8519              :     }
    8520              : 
    8521        29456 :     Real64 Effic = DesupHtr.HeatReclaimRecoveryEff;
    8522              : 
    8523        29456 :     state.dataLoopNodes->Node(WaterInletNode).Temp = this->SavedSourceOutletTemp;
    8524        29456 :     DesupHtr.Mode = DesupHtr.SaveMode;
    8525              : 
    8526              :     Real64 HEffFTemp;
    8527        29456 :     if (DesupHtr.HEffFTemp > 0) {
    8528        29456 :         HEffFTemp = max(0.0, Curve::CurveValue(state, DesupHtr.HEffFTemp, this->SavedTankTemp, state.dataEnvrn->OutDryBulbTemp));
    8529              :     } else {
    8530            0 :         HEffFTemp = 1.0;
    8531              :     }
    8532              : 
    8533              :     // set limits on heat recovery efficiency
    8534        29456 :     if (DesupHtr.ReclaimHeatingSource == ReclaimHeatObjectType::CondenserRefrigeration) {
    8535         4578 :         if ((HEffFTemp * Effic) > 0.9) {
    8536            0 :             HEffFTemp = 0.9 / Effic;
    8537              :         }
    8538              :     } else { // max is 0.3 for all other sources
    8539        24878 :         if ((HEffFTemp * Effic) > 0.3) {
    8540            0 :             HEffFTemp = 0.3 / Effic;
    8541              :         }
    8542              :     } // setting limits on heat recovery efficiency
    8543              : 
    8544              :     // Access the appropriate structure to find the average heating capacity of the desuperheater heating coil
    8545        29456 :     Real64 AverageWasteHeat = 0.0;
    8546        29456 :     if (DesupHtr.ValidSourceType) {
    8547        29456 :         int SourceID = DesupHtr.ReclaimHeatingSourceIndexNum;
    8548        29456 :         if (DesupHtr.ReclaimHeatingSource == ReclaimHeatObjectType::CompressorRackRefrigeratedCase) {
    8549              :             // Refrigeration systems are solved outside the time step iteration, so the
    8550              :             //  appropriate decrement for other waste heat applications is handled differently
    8551            0 :             AverageWasteHeat = state.dataHeatBal->HeatReclaimRefrigeratedRack(SourceID).AvailCapacity -
    8552            0 :                                state.dataHeatBal->HeatReclaimRefrigeratedRack(SourceID).HVACDesuperheaterReclaimedHeatTotal;
    8553            0 :             DesupHtr.DXSysPLR = 1.0;
    8554        29456 :         } else if (DesupHtr.ReclaimHeatingSource == ReclaimHeatObjectType::CondenserRefrigeration) {
    8555         4578 :             AverageWasteHeat = state.dataHeatBal->HeatReclaimRefrigCondenser(SourceID).AvailCapacity -
    8556         4578 :                                state.dataHeatBal->HeatReclaimRefrigCondenser(SourceID).HVACDesuperheaterReclaimedHeatTotal;
    8557         4578 :             DesupHtr.DXSysPLR = 1.0;
    8558        24878 :         } else if (DesupHtr.ReclaimHeatingSource == ReclaimHeatObjectType::DXCooling ||
    8559        12978 :                    DesupHtr.ReclaimHeatingSource == ReclaimHeatObjectType::DXMultiSpeed ||
    8560        12978 :                    DesupHtr.ReclaimHeatingSource == ReclaimHeatObjectType::DXMultiMode) {
    8561        11900 :             AverageWasteHeat = state.dataHeatBal->HeatReclaimDXCoil(SourceID).AvailCapacity -
    8562        11900 :                                state.dataHeatBal->HeatReclaimDXCoil(SourceID).HVACDesuperheaterReclaimedHeatTotal;
    8563        11900 :             DesupHtr.DXSysPLR = state.dataDXCoils->DXCoil(SourceID).PartLoadRatio;
    8564        12978 :         } else if (DesupHtr.ReclaimHeatingSource == ReclaimHeatObjectType::DXVariableCooling ||
    8565         9196 :                    DesupHtr.ReclaimHeatingSource == ReclaimHeatObjectType::AirWaterHeatPumpVSEQ) {
    8566         3782 :             AverageWasteHeat = state.dataHeatBal->HeatReclaimVS_Coil(SourceID).AvailCapacity -
    8567         3782 :                                state.dataHeatBal->HeatReclaimVS_Coil(SourceID).HVACDesuperheaterReclaimedHeatTotal;
    8568         3782 :             DesupHtr.DXSysPLR = state.dataVariableSpeedCoils->VarSpeedCoil(SourceID).PartLoadRatio;
    8569         9196 :         } else if (DesupHtr.ReclaimHeatingSource == ReclaimHeatObjectType::AirWaterHeatPumpEQ) {
    8570         3246 :             AverageWasteHeat = state.dataHeatBal->HeatReclaimSimple_WAHPCoil(SourceID).AvailCapacity -
    8571         3246 :                                state.dataHeatBal->HeatReclaimSimple_WAHPCoil(SourceID).HVACDesuperheaterReclaimedHeatTotal;
    8572         3246 :             DesupHtr.DXSysPLR = state.dataWaterToAirHeatPumpSimple->SimpleWatertoAirHP(SourceID).PartLoadRatio;
    8573         5950 :         } else if (DesupHtr.ReclaimHeatingSource == ReclaimHeatObjectType::CoilCoolingDX) {
    8574         5950 :             AverageWasteHeat =
    8575         5950 :                 state.dataCoilCoolingDX->coilCoolingDXs[DesupHtr.ReclaimHeatingSourceIndexNum].reclaimHeat.AvailCapacity -
    8576         5950 :                 state.dataCoilCoolingDX->coilCoolingDXs[DesupHtr.ReclaimHeatingSourceIndexNum].reclaimHeat.HVACDesuperheaterReclaimedHeatTotal;
    8577         5950 :             DesupHtr.DXSysPLR = state.dataCoilCoolingDX->coilCoolingDXs[DesupHtr.ReclaimHeatingSourceIndexNum].partLoadRatioReport;
    8578              :         }
    8579              :     } else {
    8580            0 :         AverageWasteHeat = 0.0;
    8581              :     }
    8582              : 
    8583              :     // simulate only water heater tank if reclaim heating source is off
    8584        29456 :     if (DesupHtr.DXSysPLR == 0.0) {
    8585        18171 :         this->CalcWaterThermalTank(state);
    8586        18171 :         return;
    8587              :     }
    8588              : 
    8589              :     // If the set point is higher than the maximum water temp, reset both the set point and the dead band temperature difference
    8590        11285 :     if (desupHtrSetPointTemp > DesupHtr.MaxInletWaterTemp) {
    8591        11285 :         Real64 CutInTemp = desupHtrSetPointTemp - DeadBandTempDiff;
    8592        11285 :         desupHtrSetPointTemp = DesupHtr.MaxInletWaterTemp;
    8593        11285 :         DeadBandTempDiff = max(0.0, (desupHtrSetPointTemp - CutInTemp));
    8594              :     }
    8595              : 
    8596              :     Real64 Acc; // Accuracy of result from RegulaFalsi
    8597        11285 :     if (DesupHtr.TankTypeNum == DataPlant::PlantEquipmentType::WtrHeaterStratified) {
    8598          951 :         Acc = 0.001;
    8599              :     } else {
    8600        10334 :         Acc = 0.00001;
    8601              :     }
    8602              : 
    8603              :     // set the water-side mass flow rate
    8604        11285 :     Real64 CpWater = Psychrometrics::CPHW(state.dataLoopNodes->Node(WaterInletNode).Temp);
    8605        11285 :     Real64 MdotWater = DesupHtr.OperatingWaterFlowRate * Psychrometrics::RhoH2O(state.dataLoopNodes->Node(WaterInletNode).Temp);
    8606        11285 :     Real64 QHeatRate = 0.0;
    8607        11285 :     if (state.dataLoopNodes->Node(WaterInletNode).Temp <= DesupHtr.MaxInletWaterTemp + Acc) {
    8608        10099 :         QHeatRate = ((AverageWasteHeat * Effic * HEffFTemp) / DesupHtr.DXSysPLR) + (DesupHtr.PumpElecPower * DesupHtr.PumpFracToWater);
    8609              :     }
    8610              : 
    8611              :     // change to tanktypenum using parameters?
    8612        11285 :     Real64 partLoadRatio = 0.0;
    8613              :     Real64 NewTankTemp;
    8614              :     {
    8615        11285 :         DataPlant::PlantEquipmentType const TankType = DesupHtr.TankTypeNum;
    8616              : 
    8617        11285 :         if (TankType == DataPlant::PlantEquipmentType::WtrHeaterMixed || TankType == DataPlant::PlantEquipmentType::WtrHeaterStratified) {
    8618              : 
    8619        11285 :             DesupHtr.SaveWHMode = this->Mode;
    8620        11285 :             Real64 PreTankAvgTemp = this->TankTempAvg;
    8621        11285 :             Real64 NewTankAvgTemp = 0.0; // Initialization
    8622        11285 :             int max_count = 200;
    8623        11285 :             int count = 0;
    8624        11285 :             bool firstThrough = true;
    8625        11285 :             switch (DesupHtr.Mode) {
    8626        10391 :             case TankOperatingMode::Heating:
    8627              :                 // Calculate until consistency of desuperheater and tank source side energy transfer achieved
    8628        30514 :                 while ((std::abs(PreTankAvgTemp - NewTankAvgTemp) > HVAC::SmallTempDiff || firstThrough) && count < max_count) {
    8629        20123 :                     count++;
    8630        20123 :                     firstThrough = false;
    8631        20123 :                     PreTankAvgTemp = this->TankTempAvg;
    8632        20123 :                     partLoadRatio = DesupHtr.DXSysPLR;
    8633        20123 :                     if (MdotWater > 0.0) {
    8634        20123 :                         state.dataLoopNodes->Node(WaterOutletNode).Temp = this->SourceOutletTemp + QHeatRate / (MdotWater * CpWater);
    8635              :                     } else {
    8636            0 :                         state.dataLoopNodes->Node(WaterOutletNode).Temp = this->SourceOutletTemp;
    8637              :                     }
    8638              : 
    8639              :                     //         set the full load outlet temperature on the water heater source inlet node (init has already been called)
    8640        20123 :                     this->SourceInletTemp = state.dataLoopNodes->Node(WaterOutletNode).Temp;
    8641              : 
    8642              :                     //         set the source mass flow rate for the tank
    8643        20123 :                     this->SourceMassFlowRate = MdotWater * partLoadRatio;
    8644              : 
    8645        20123 :                     this->MaxCapacity = DesupHtr.BackupElementCapacity;
    8646        20123 :                     this->MinCapacity = DesupHtr.BackupElementCapacity;
    8647        20123 :                     DesupHtr.DesuperheaterPLR = partLoadRatio;
    8648        20123 :                     DesupHtr.HeaterRate = QHeatRate * partLoadRatio;
    8649        20123 :                     this->CalcWaterThermalTank(state);
    8650        20123 :                     Real64 NewTankTemp = this->TankTemp;
    8651              : 
    8652        20123 :                     if (NewTankTemp > desupHtrSetPointTemp) {
    8653              :                         //           Only revert to floating mode if the tank temperature is higher than the cut out temperature
    8654         6809 :                         if (NewTankTemp > DesupHtr.SetPointTemp) {
    8655            0 :                             DesupHtr.Mode = TankOperatingMode::Floating;
    8656              :                         }
    8657              :                         int SolFla;
    8658         6809 :                         std::string IterNum;
    8659        27227 :                         auto f = [&state, this, desupHtrSetPointTemp, &DesupHtr, MdotWater](Real64 const HPPartLoadRatio) {
    8660        27227 :                             this->Mode = DesupHtr.SaveWHMode;
    8661        27227 :                             this->SourceMassFlowRate = MdotWater * HPPartLoadRatio;
    8662        27227 :                             this->CalcWaterThermalTank(state);
    8663        27227 :                             Real64 NewTankTemp = this->TankTemp;
    8664        27227 :                             Real64 PLRResidualWaterThermalTank = desupHtrSetPointTemp - NewTankTemp;
    8665        27227 :                             return PLRResidualWaterThermalTank;
    8666         6809 :                         };
    8667         6809 :                         General::SolveRoot(state, Acc, MaxIte, SolFla, partLoadRatio, f, 0.0, DesupHtr.DXSysPLR);
    8668         6809 :                         if (SolFla == -1) {
    8669            0 :                             IterNum = fmt::to_string(MaxIte);
    8670            0 :                             if (!state.dataGlobal->WarmupFlag) {
    8671            0 :                                 ++DesupHtr.IterLimitExceededNum1;
    8672            0 :                                 if (DesupHtr.IterLimitExceededNum1 == 1) {
    8673            0 :                                     ShowWarningError(state, format("{} \"{}\"", DesupHtr.Type, DesupHtr.Name));
    8674            0 :                                     ShowContinueError(state,
    8675            0 :                                                       format("Iteration limit exceeded calculating desuperheater unit part-load ratio, "
    8676              :                                                              "maximum iterations = {}. Part-load ratio returned = {:.3R}",
    8677              :                                                              IterNum,
    8678              :                                                              partLoadRatio));
    8679            0 :                                     ShowContinueErrorTimeStamp(state, "This error occurred in heating mode.");
    8680              :                                 } else {
    8681            0 :                                     ShowRecurringWarningErrorAtEnd(state,
    8682            0 :                                                                    DesupHtr.Type + " \"" + DesupHtr.Name +
    8683              :                                                                        "\":  Iteration limit exceeded in heating mode warning continues. "
    8684              :                                                                        "Part-load ratio statistics follow.",
    8685            0 :                                                                    DesupHtr.IterLimitErrIndex1,
    8686              :                                                                    partLoadRatio,
    8687              :                                                                    partLoadRatio);
    8688              :                                 }
    8689              :                             }
    8690         6809 :                         } else if (SolFla == -2) {
    8691            0 :                             partLoadRatio =
    8692            0 :                                 max(0.0, min(DesupHtr.DXSysPLR, (desupHtrSetPointTemp - this->SavedTankTemp) / (NewTankTemp - this->SavedTankTemp)));
    8693            0 :                             this->SourceMassFlowRate = MdotWater * partLoadRatio;
    8694            0 :                             this->CalcWaterThermalTank(state);
    8695            0 :                             if (!state.dataGlobal->WarmupFlag) {
    8696            0 :                                 ++DesupHtr.RegulaFalsiFailedNum1;
    8697            0 :                                 if (DesupHtr.RegulaFalsiFailedNum1 == 1) {
    8698            0 :                                     ShowWarningError(state, format("{} \"{}\"", DesupHtr.Type, DesupHtr.Name));
    8699            0 :                                     ShowContinueError(state,
    8700            0 :                                                       format("Desuperheater unit part-load ratio calculation failed: PLR limits of 0 to 1 "
    8701              :                                                              "exceeded. Part-load ratio used = {:.3R}",
    8702              :                                                              partLoadRatio));
    8703            0 :                                     ShowContinueError(state, "Please send this information to the EnergyPlus support group.");
    8704            0 :                                     ShowContinueErrorTimeStamp(state, "This error occurred in heating mode.");
    8705              :                                 } else {
    8706            0 :                                     ShowRecurringWarningErrorAtEnd(state,
    8707            0 :                                                                    DesupHtr.Type + " \"" + DesupHtr.Name +
    8708              :                                                                        "\":  Part-load ratio calculation failed in heating mode warning "
    8709              :                                                                        "continues. Part-load ratio statistics follow.",
    8710            0 :                                                                    DesupHtr.RegulaFalsiFailedIndex1,
    8711              :                                                                    partLoadRatio,
    8712              :                                                                    partLoadRatio);
    8713              :                                 }
    8714              :                             }
    8715              :                         }
    8716         6809 :                     } else {
    8717        13314 :                         partLoadRatio = DesupHtr.DXSysPLR;
    8718              :                     }
    8719        20123 :                     NewTankAvgTemp = this->TankTempAvg;
    8720              :                 }
    8721        10391 :                 break;
    8722          894 :             case TankOperatingMode::Floating:
    8723          894 :                 if (MdotWater > 0.0) {
    8724          894 :                     state.dataLoopNodes->Node(WaterOutletNode).Temp =
    8725          894 :                         state.dataLoopNodes->Node(WaterInletNode).Temp + QHeatRate / (MdotWater * CpWater);
    8726              :                 } else {
    8727            0 :                     state.dataLoopNodes->Node(WaterOutletNode).Temp = state.dataLoopNodes->Node(WaterInletNode).Temp;
    8728              :                 }
    8729              :                 //         check tank temperature by setting source inlet mass flow rate to zero
    8730          894 :                 partLoadRatio = 0.0;
    8731              : 
    8732              :                 //         set the full load outlet temperature on the water heater source inlet node (init has already been called)
    8733          894 :                 this->SourceInletTemp = state.dataLoopNodes->Node(WaterOutletNode).Temp;
    8734              : 
    8735              :                 //         check tank temperature by setting source inlet mass flow rate to zero
    8736          894 :                 this->SourceMassFlowRate = 0.0;
    8737              : 
    8738              :                 //         disable the tank heater to find PLR of the HPWH
    8739          894 :                 this->MaxCapacity = 0.0;
    8740          894 :                 this->MinCapacity = 0.0;
    8741          894 :                 DesupHtr.DesuperheaterPLR = partLoadRatio;
    8742          894 :                 DesupHtr.HeaterRate = QHeatRate * partLoadRatio;
    8743          894 :                 this->CalcWaterThermalTank(state);
    8744          894 :                 NewTankTemp = this->TankTemp;
    8745              : 
    8746          894 :                 if (NewTankTemp <= (desupHtrSetPointTemp - DeadBandTempDiff)) {
    8747           44 :                     this->Mode = DesupHtr.SaveWHMode;
    8748           44 :                     if ((this->SavedTankTemp - NewTankTemp) != 0.0) {
    8749           44 :                         partLoadRatio =
    8750           44 :                             min(DesupHtr.DXSysPLR,
    8751           44 :                                 max(0.0, ((desupHtrSetPointTemp - DeadBandTempDiff) - NewTankTemp) / (this->SavedTankTemp - NewTankTemp)));
    8752              :                     } else {
    8753            0 :                         partLoadRatio = DesupHtr.DXSysPLR;
    8754              :                     }
    8755          201 :                     while ((std::abs(PreTankAvgTemp - NewTankAvgTemp) > HVAC::SmallTempDiff || firstThrough) && count < max_count) {
    8756          157 :                         count++;
    8757          157 :                         firstThrough = false;
    8758          157 :                         PreTankAvgTemp = this->TankTempAvg;
    8759          157 :                         DesupHtr.Mode = TankOperatingMode::Heating;
    8760          157 :                         if (MdotWater > 0.0) {
    8761          157 :                             state.dataLoopNodes->Node(WaterOutletNode).Temp = this->SourceOutletTemp + QHeatRate / (MdotWater * CpWater);
    8762              :                         } else {
    8763            0 :                             state.dataLoopNodes->Node(WaterOutletNode).Temp = this->SourceOutletTemp;
    8764              :                         }
    8765              : 
    8766              :                         //           set the full load outlet temperature on the water heater source inlet node
    8767          157 :                         this->SourceInletTemp = state.dataLoopNodes->Node(WaterOutletNode).Temp;
    8768              : 
    8769              :                         //           set the source mass flow rate for the tank and enable backup heating element
    8770          157 :                         this->SourceMassFlowRate = MdotWater * partLoadRatio;
    8771          157 :                         this->MaxCapacity = DesupHtr.BackupElementCapacity;
    8772          157 :                         this->MinCapacity = DesupHtr.BackupElementCapacity;
    8773          157 :                         DesupHtr.DesuperheaterPLR = partLoadRatio;
    8774          157 :                         DesupHtr.HeaterRate = QHeatRate * partLoadRatio;
    8775          157 :                         this->CalcWaterThermalTank(state);
    8776          157 :                         NewTankTemp = this->TankTemp;
    8777              : 
    8778          157 :                         if (NewTankTemp > desupHtrSetPointTemp) {
    8779              :                             //           Only revert to floating mode if the tank temperature is higher than the cut-out temperature
    8780            0 :                             if (NewTankTemp > DesupHtr.SetPointTemp) {
    8781            0 :                                 DesupHtr.Mode = TankOperatingMode::Floating;
    8782              :                             }
    8783              :                             int SolFla;
    8784            0 :                             std::string IterNum;
    8785            0 :                             auto f = [&state, this, desupHtrSetPointTemp, &DesupHtr, MdotWater](Real64 const HPPartLoadRatio) {
    8786            0 :                                 this->Mode = DesupHtr.SaveWHMode;
    8787            0 :                                 this->SourceMassFlowRate = MdotWater * HPPartLoadRatio;
    8788            0 :                                 this->CalcWaterThermalTank(state);
    8789            0 :                                 Real64 NewTankTemp = this->TankTemp;
    8790            0 :                                 Real64 PLRResidualWaterThermalTank = desupHtrSetPointTemp - NewTankTemp;
    8791            0 :                                 return PLRResidualWaterThermalTank;
    8792            0 :                             };
    8793            0 :                             General::SolveRoot(state, Acc, MaxIte, SolFla, partLoadRatio, f, 0.0, DesupHtr.DXSysPLR);
    8794            0 :                             if (SolFla == -1) {
    8795            0 :                                 IterNum = fmt::to_string(MaxIte);
    8796            0 :                                 if (!state.dataGlobal->WarmupFlag) {
    8797            0 :                                     ++DesupHtr.IterLimitExceededNum2;
    8798            0 :                                     if (DesupHtr.IterLimitExceededNum2 == 1) {
    8799            0 :                                         ShowWarningError(state, format("{} \"{}\"", DesupHtr.Type, DesupHtr.Name));
    8800            0 :                                         ShowContinueError(state,
    8801            0 :                                                           format("Iteration limit exceeded calculating desuperheater unit part-load ratio, "
    8802              :                                                                  "maximum iterations = {}. Part-load ratio returned = {:.3R}",
    8803              :                                                                  IterNum,
    8804              :                                                                  partLoadRatio));
    8805            0 :                                         ShowContinueErrorTimeStamp(state, "This error occurred in float mode.");
    8806              :                                     } else {
    8807            0 :                                         ShowRecurringWarningErrorAtEnd(state,
    8808            0 :                                                                        DesupHtr.Type + " \"" + DesupHtr.Name +
    8809              :                                                                            "\":  Iteration limit exceeded in float mode warning continues. "
    8810              :                                                                            "Part-load ratio statistics follow.",
    8811            0 :                                                                        DesupHtr.IterLimitErrIndex2,
    8812              :                                                                        partLoadRatio,
    8813              :                                                                        partLoadRatio);
    8814              :                                     }
    8815              :                                 }
    8816            0 :                             } else if (SolFla == -2) {
    8817            0 :                                 partLoadRatio = max(
    8818            0 :                                     0.0, min(DesupHtr.DXSysPLR, (desupHtrSetPointTemp - this->SavedTankTemp) / (NewTankTemp - this->SavedTankTemp)));
    8819            0 :                                 if (!state.dataGlobal->WarmupFlag) {
    8820            0 :                                     ++DesupHtr.RegulaFalsiFailedNum2;
    8821            0 :                                     if (DesupHtr.RegulaFalsiFailedNum2 == 1) {
    8822            0 :                                         ShowWarningError(state, format("{} \"{}\"", DesupHtr.Type, DesupHtr.Name));
    8823            0 :                                         ShowContinueError(state,
    8824            0 :                                                           format("Desuperheater unit part-load ratio calculation failed: PLR limits of 0 to "
    8825              :                                                                  "1 exceeded. Part-load ratio used = {:.3R}",
    8826              :                                                                  partLoadRatio));
    8827            0 :                                         ShowContinueError(state, "Please send this information to the EnergyPlus support group.");
    8828            0 :                                         ShowContinueErrorTimeStamp(state, "This error occurred in float mode.");
    8829              :                                     } else {
    8830            0 :                                         ShowRecurringWarningErrorAtEnd(
    8831              :                                             state,
    8832            0 :                                             DesupHtr.Type + " \"" + DesupHtr.Name +
    8833              :                                                 "\": Part-load ratio calculation failed in float mode warning "
    8834              :                                                 "continues. Part-load ratio statistics follow.",
    8835            0 :                                             state.dataWaterThermalTanks->WaterHeaterDesuperheater(DesuperheaterNum).RegulaFalsiFailedIndex2,
    8836              :                                             partLoadRatio,
    8837              :                                             partLoadRatio);
    8838              :                                     }
    8839              :                                 }
    8840              :                             }
    8841            0 :                         }
    8842          157 :                         NewTankAvgTemp = this->TankTempAvg;
    8843              :                     }
    8844              :                 } else {
    8845          850 :                     this->MaxCapacity = DesupHtr.BackupElementCapacity;
    8846          850 :                     this->MinCapacity = DesupHtr.BackupElementCapacity;
    8847              :                 }
    8848          894 :                 break;
    8849            0 :             default:
    8850            0 :                 break;
    8851              :             }
    8852              : 
    8853              :             //   should never get here, case is checked in GetWaterThermalTankInput
    8854        11285 :         } else {
    8855            0 :             ShowFatalError(state,
    8856            0 :                            format("Coil:WaterHeating:Desuperheater = {}:  invalid water heater tank type and name entered = {}, {}",
    8857            0 :                                   state.dataWaterThermalTanks->WaterHeaterDesuperheater(DesuperheaterNum).Name,
    8858            0 :                                   state.dataWaterThermalTanks->WaterHeaterDesuperheater(DesuperheaterNum).TankType,
    8859            0 :                                   state.dataWaterThermalTanks->WaterHeaterDesuperheater(DesuperheaterNum).TankName));
    8860              :         }
    8861              :     }
    8862              : 
    8863        11285 :     if (QHeatRate == 0) {
    8864         1186 :         partLoadRatio = 0.0;
    8865              :     }
    8866              : 
    8867        11285 :     state.dataLoopNodes->Node(WaterOutletNode).MassFlowRate = MdotWater * partLoadRatio;
    8868        11285 :     DesupHtr.HEffFTempOutput = HEffFTemp;
    8869        11285 :     DesupHtr.HeaterRate = QHeatRate * partLoadRatio;
    8870        11285 :     this->SourceMassFlowRate = MdotWater * partLoadRatio;
    8871              : 
    8872        11285 :     if (partLoadRatio == 0) {
    8873         1186 :         this->SourceInletTemp = this->SourceOutletTemp;
    8874         1186 :         state.dataLoopNodes->Node(WaterOutletNode).Temp = this->SourceOutletTemp;
    8875         1186 :         DesupHtr.HEffFTempOutput = 0.0;
    8876         1186 :         DesupHtr.HeaterRate = 0.0;
    8877              :     }
    8878              : 
    8879        11285 :     DesupHtr.HeaterEnergy = DesupHtr.HeaterRate * state.dataHVACGlobal->TimeStepSysSec;
    8880        11285 :     DesupHtr.DesuperheaterPLR = partLoadRatio;
    8881        11285 :     DesupHtr.OnCycParaFuelRate = DesupHtr.OnCycParaLoad * partLoadRatio;
    8882        11285 :     DesupHtr.OnCycParaFuelEnergy = DesupHtr.OnCycParaFuelRate * state.dataHVACGlobal->TimeStepSysSec;
    8883        11285 :     DesupHtr.OffCycParaFuelRate = DesupHtr.OffCycParaLoad * (1 - partLoadRatio);
    8884        11285 :     DesupHtr.OffCycParaFuelEnergy = DesupHtr.OffCycParaFuelRate * state.dataHVACGlobal->TimeStepSysSec;
    8885        11285 :     DesupHtr.PumpPower = DesupHtr.PumpElecPower * (partLoadRatio);
    8886        11285 :     DesupHtr.PumpEnergy = DesupHtr.PumpPower * state.dataHVACGlobal->TimeStepSysSec;
    8887              : 
    8888              :     // Update used waste heat (just in case multiple users of waste heat use same source)
    8889        11285 :     if (DesupHtr.ValidSourceType) {
    8890        11285 :         int SourceID = DesupHtr.ReclaimHeatingSourceIndexNum;
    8891        11285 :         if (DesupHtr.ReclaimHeatingSource == ReclaimHeatObjectType::CompressorRackRefrigeratedCase) {
    8892            0 :             state.dataHeatBal->HeatReclaimRefrigeratedRack(SourceID).WaterHeatingDesuperheaterReclaimedHeat(DesuperheaterNum) = DesupHtr.HeaterRate;
    8893            0 :             state.dataHeatBal->HeatReclaimRefrigeratedRack(SourceID).WaterHeatingDesuperheaterReclaimedHeatTotal = 0.0;
    8894            0 :             for (auto const &num : state.dataHeatBal->HeatReclaimRefrigeratedRack(SourceID).WaterHeatingDesuperheaterReclaimedHeat) {
    8895            0 :                 state.dataHeatBal->HeatReclaimRefrigeratedRack(SourceID).WaterHeatingDesuperheaterReclaimedHeatTotal += num;
    8896              :             }
    8897        11285 :         } else if (DesupHtr.ReclaimHeatingSource == ReclaimHeatObjectType::CondenserRefrigeration) {
    8898         4578 :             state.dataHeatBal->HeatReclaimRefrigCondenser(SourceID).WaterHeatingDesuperheaterReclaimedHeat(DesuperheaterNum) = DesupHtr.HeaterRate;
    8899         4578 :             state.dataHeatBal->HeatReclaimRefrigCondenser(SourceID).WaterHeatingDesuperheaterReclaimedHeatTotal = 0.0;
    8900         9156 :             for (auto const &num : state.dataHeatBal->HeatReclaimRefrigCondenser(SourceID).WaterHeatingDesuperheaterReclaimedHeat) {
    8901         4578 :                 state.dataHeatBal->HeatReclaimRefrigCondenser(SourceID).WaterHeatingDesuperheaterReclaimedHeatTotal += num;
    8902              :             }
    8903         6707 :         } else if (DesupHtr.ReclaimHeatingSource == ReclaimHeatObjectType::DXCooling ||
    8904         4467 :                    DesupHtr.ReclaimHeatingSource == ReclaimHeatObjectType::DXMultiSpeed ||
    8905         4467 :                    DesupHtr.ReclaimHeatingSource == ReclaimHeatObjectType::DXMultiMode) {
    8906         2240 :             state.dataHeatBal->HeatReclaimDXCoil(SourceID).WaterHeatingDesuperheaterReclaimedHeat(DesuperheaterNum) = DesupHtr.HeaterRate;
    8907         2240 :             state.dataHeatBal->HeatReclaimDXCoil(SourceID).WaterHeatingDesuperheaterReclaimedHeatTotal = 0.0;
    8908         4480 :             for (auto const &num : state.dataHeatBal->HeatReclaimDXCoil(SourceID).WaterHeatingDesuperheaterReclaimedHeat) {
    8909         2240 :                 state.dataHeatBal->HeatReclaimDXCoil(SourceID).WaterHeatingDesuperheaterReclaimedHeatTotal += num;
    8910              :             }
    8911         6707 :         } else if (DesupHtr.ReclaimHeatingSource == ReclaimHeatObjectType::DXVariableCooling ||
    8912         2071 :                    DesupHtr.ReclaimHeatingSource == ReclaimHeatObjectType::AirWaterHeatPumpVSEQ) {
    8913         2396 :             state.dataHeatBal->HeatReclaimVS_Coil(SourceID).WaterHeatingDesuperheaterReclaimedHeat(DesuperheaterNum) = DesupHtr.HeaterRate;
    8914         2396 :             state.dataHeatBal->HeatReclaimVS_Coil(SourceID).WaterHeatingDesuperheaterReclaimedHeatTotal = 0.0;
    8915         4792 :             for (auto const &num : state.dataHeatBal->HeatReclaimVS_Coil(SourceID).WaterHeatingDesuperheaterReclaimedHeat) {
    8916         2396 :                 state.dataHeatBal->HeatReclaimVS_Coil(SourceID).WaterHeatingDesuperheaterReclaimedHeatTotal += num;
    8917              :             }
    8918         4467 :         } else if (DesupHtr.ReclaimHeatingSource == ReclaimHeatObjectType::AirWaterHeatPumpEQ) {
    8919          951 :             state.dataHeatBal->HeatReclaimSimple_WAHPCoil(SourceID).WaterHeatingDesuperheaterReclaimedHeat(DesuperheaterNum) = DesupHtr.HeaterRate;
    8920          951 :             state.dataHeatBal->HeatReclaimSimple_WAHPCoil(SourceID).WaterHeatingDesuperheaterReclaimedHeatTotal = 0.0;
    8921         1902 :             for (auto const &num : state.dataHeatBal->HeatReclaimSimple_WAHPCoil(SourceID).WaterHeatingDesuperheaterReclaimedHeat) {
    8922          951 :                 state.dataHeatBal->HeatReclaimSimple_WAHPCoil(SourceID).WaterHeatingDesuperheaterReclaimedHeatTotal += num;
    8923              :             }
    8924         1120 :         } else if (DesupHtr.ReclaimHeatingSource == ReclaimHeatObjectType::CoilCoolingDX) {
    8925         1120 :             state.dataCoilCoolingDX->coilCoolingDXs[DesupHtr.ReclaimHeatingSourceIndexNum].reclaimHeat.WaterHeatingDesuperheaterReclaimedHeat(
    8926         1120 :                 DesuperheaterNum) = DesupHtr.HeaterRate;
    8927         1120 :             state.dataCoilCoolingDX->coilCoolingDXs[DesupHtr.ReclaimHeatingSourceIndexNum].reclaimHeat.WaterHeatingDesuperheaterReclaimedHeatTotal =
    8928              :                 0.0;
    8929         1120 :             for (auto const &num :
    8930         3360 :                  state.dataCoilCoolingDX->coilCoolingDXs[DesupHtr.ReclaimHeatingSourceIndexNum].reclaimHeat.WaterHeatingDesuperheaterReclaimedHeat) {
    8931         1120 :                 state.dataCoilCoolingDX->coilCoolingDXs[DesupHtr.ReclaimHeatingSourceIndexNum]
    8932         1120 :                     .reclaimHeat.WaterHeatingDesuperheaterReclaimedHeatTotal += num;
    8933              :             }
    8934              :         }
    8935              :     }
    8936              : }
    8937              : 
    8938       408468 : void WaterThermalTankData::CalcHeatPumpWaterHeater(EnergyPlusData &state, bool const FirstHVACIteration)
    8939              : {
    8940              : 
    8941              :     // SUBROUTINE INFORMATION:
    8942              :     //       AUTHOR         Richard Raustad
    8943              :     //       DATE WRITTEN   March 2005
    8944              :     //       MODIFIED       B. Griffith, Jan 2012 for stratified tank
    8945              :     //                        B. Shen 12/2014, add air-source variable-speed heat pump water heating
    8946              :     //       RE-ENGINEERED  na
    8947              : 
    8948              :     // PURPOSE OF THIS SUBROUTINE:
    8949              :     // Simulates a heat pump water heater
    8950              : 
    8951              :     // METHODOLOGY EMPLOYED:
    8952              :     // Simulate the water heater tank, DX coil, and fan to meet the water heating requirements.
    8953              : 
    8954       408468 :     int constexpr MaxIte(500);   // maximum number of iterations
    8955       408468 :     Real64 constexpr Acc(0.001); // Accuracy of result from RegulaFalsi
    8956              : 
    8957              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    8958              :     Real64 MdotWater;                                                                         // mass flow rate of condenser water, kg/s
    8959       408468 :     IntegratedHeatPump::IHPOperationMode IHPMode(IntegratedHeatPump::IHPOperationMode::Idle); // IHP working mode
    8960              : 
    8961              :     // References to objects used in this function
    8962       408468 :     HeatPumpWaterHeaterData &HeatPump = state.dataWaterThermalTanks->HPWaterHeater(this->HeatPumpNum);
    8963              : 
    8964              :     // initialize local variables
    8965       408468 :     int AvailSchedule = HeatPump.availSched->getCurrentVal();
    8966       408468 :     int HPAirInletNode = HeatPump.HeatPumpAirInletNode;
    8967       408468 :     int HPAirOutletNode = HeatPump.HeatPumpAirOutletNode;
    8968       408468 :     int OutdoorAirNode = HeatPump.OutsideAirNode;
    8969       408468 :     int ExhaustAirNode = HeatPump.ExhaustAirNode;
    8970       408468 :     int HPWaterInletNode = HeatPump.CondWaterInletNode;
    8971       408468 :     int HPWaterOutletNode = HeatPump.CondWaterOutletNode;
    8972       408468 :     int InletAirMixerNode = HeatPump.InletAirMixerNode;
    8973       408468 :     int OutletAirSplitterNode = HeatPump.OutletAirSplitterNode;
    8974       408468 :     int DXCoilAirInletNode = HeatPump.DXCoilAirInletNode;
    8975       408468 :     state.dataWaterThermalTanks->hpPartLoadRatio = 0.0;
    8976       408468 :     HVAC::CompressorOp compressorOp = HVAC::CompressorOp::Off; // DX compressor operation; 1=on, 0=off
    8977       408468 :     HeatPump.OnCycParaFuelRate = 0.0;
    8978       408468 :     HeatPump.OnCycParaFuelEnergy = 0.0;
    8979       408468 :     HeatPump.OffCycParaFuelRate = 0.0;
    8980       408468 :     HeatPump.OffCycParaFuelEnergy = 0.0;
    8981       408468 :     state.dataLoopNodes->Node(HPWaterOutletNode) = state.dataLoopNodes->Node(HPWaterInletNode);
    8982       408468 :     int MaxSpeedNum = HeatPump.NumofSpeed; // speed number of variable speed HPWH coil
    8983              : 
    8984              :     // assign set point temperature (cut-out) and dead band temp diff (cut-in = cut-out minus dead band temp diff)
    8985       408468 :     Real64 HPSetPointTemp = HeatPump.SetPointTemp;
    8986       408468 :     Real64 DeadBandTempDiff = HeatPump.DeadBandTempDiff;
    8987       408468 :     Real64 RhoWater = Psychrometrics::RhoH2O(HPSetPointTemp); // initialize
    8988              : 
    8989              :     // store first iteration tank temperature and HP mode of operation
    8990              :     // this code can be called more than once with FirstHVACIteration = .TRUE., use FirstTimeThroughFlag to control save
    8991       408468 :     if (FirstHVACIteration && !state.dataHVACGlobal->ShortenTimeStepSys && HeatPump.FirstTimeThroughFlag) {
    8992        55851 :         this->SavedTankTemp = this->TankTemp;
    8993        55851 :         HeatPump.SaveMode = HeatPump.Mode;
    8994        55851 :         HeatPump.SaveWHMode = this->Mode;
    8995        55851 :         HeatPump.FirstTimeThroughFlag = false;
    8996              :     }
    8997              : 
    8998       408468 :     if (!FirstHVACIteration) {
    8999       201940 :         HeatPump.FirstTimeThroughFlag = true;
    9000              :     }
    9001              : 
    9002              :     // check if HPWH is off for some reason and simulate HPWH air- and water-side mass flow rates of 0
    9003              :     // simulate only water heater tank if HP compressor is scheduled off
    9004              :     //   simulate only water heater tank if HP compressor cut-out temperature is lower than the tank's cut-in temperature
    9005              :     //    simulate only water heater tank if HP inlet air temperature is below minimum temperature for HP compressor operation
    9006              :     //    if the tank maximum temperature limit is less than the HPWH set point temp, disable HPWH
    9007       408468 :     if (AvailSchedule == 0.0 || (HPSetPointTemp - DeadBandTempDiff) <= this->SetPointTemp ||
    9008       408468 :         state.dataHVACGlobal->HPWHInletDBTemp < HeatPump.MinAirTempForHPOperation ||
    9009       328948 :         state.dataHVACGlobal->HPWHInletDBTemp > HeatPump.MaxAirTempForHPOperation || HPSetPointTemp >= this->TankTempLimit ||
    9010       328948 :         (!HeatPump.AllowHeatingElementAndHeatPumpToRunAtSameTime && this->WaterThermalTankType == DataPlant::PlantEquipmentType::WtrHeaterMixed &&
    9011       816936 :          this->SavedMode == TankOperatingMode::Heating) ||
    9012       328948 :         (!HeatPump.AllowHeatingElementAndHeatPumpToRunAtSameTime &&
    9013       103940 :          this->WaterThermalTankType == DataPlant::PlantEquipmentType::WtrHeaterStratified && (this->SavedHeaterOn1 || this->SavedHeaterOn2))) {
    9014              :         //   revert to float mode any time HPWH compressor is OFF
    9015        81640 :         HeatPump.Mode = TankOperatingMode::Floating;
    9016        81640 :         if (InletAirMixerNode > 0) {
    9017            0 :             state.dataLoopNodes->Node(InletAirMixerNode) = state.dataLoopNodes->Node(HPAirInletNode);
    9018              :         }
    9019              :         //   pass node info and simulate crankcase heater
    9020        81640 :         if (MaxSpeedNum > 0) {
    9021        25630 :             int VSCoilNum = HeatPump.DXCoilNum;
    9022              : 
    9023        25630 :             if (HeatPump.bIsIHP) {
    9024         4976 :                 VSCoilNum = state.dataIntegratedHP->IntegratedHeatPumps(VSCoilNum).SCWHCoilIndex;
    9025              :             }
    9026              :             // set the SCWH mode
    9027        25630 :             Real64 SpeedRatio = 1.0; // speed ratio for interpolating between two speed levels
    9028        25630 :             int SpeedNum = 1;
    9029        25630 :             if (HeatPump.fanPlace == HVAC::FanPlace::BlowThru) {
    9030        25630 :                 state.dataFans->fans(HeatPump.FanNum)->simulate(state, FirstHVACIteration, _, _);
    9031              : 
    9032        25630 :                 this->SetVSHPWHFlowRates(state, HeatPump, SpeedNum, SpeedRatio, RhoWater, MdotWater, FirstHVACIteration);
    9033        25630 :                 if (HeatPump.bIsIHP) {
    9034         4976 :                     VariableSpeedCoils::SimVariableSpeedCoils(state,
    9035              :                                                               "",
    9036              :                                                               VSCoilNum,
    9037              :                                                               HVAC::FanOp::Cycling,
    9038              :                                                               HVAC::CompressorOp::On,
    9039         4976 :                                                               state.dataWaterThermalTanks->hpPartLoadRatio,
    9040              :                                                               SpeedNum,
    9041              :                                                               SpeedRatio,
    9042              :                                                               0.0,
    9043              :                                                               0.0,
    9044              :                                                               1.0);
    9045              :                 } else {
    9046        20654 :                     VariableSpeedCoils::SimVariableSpeedCoils(state,
    9047              :                                                               HeatPump.DXCoilName,
    9048              :                                                               VSCoilNum,
    9049              :                                                               HVAC::FanOp::Cycling,
    9050              :                                                               HVAC::CompressorOp::On,
    9051        20654 :                                                               state.dataWaterThermalTanks->hpPartLoadRatio,
    9052              :                                                               SpeedNum,
    9053              :                                                               SpeedRatio,
    9054              :                                                               0.0,
    9055              :                                                               0.0,
    9056              :                                                               1.0);
    9057              :                 }
    9058              :             } else {
    9059            0 :                 this->SetVSHPWHFlowRates(state, HeatPump, SpeedNum, SpeedRatio, RhoWater, MdotWater, FirstHVACIteration);
    9060            0 :                 if (HeatPump.bIsIHP) {
    9061            0 :                     VariableSpeedCoils::SimVariableSpeedCoils(state,
    9062              :                                                               "",
    9063              :                                                               VSCoilNum,
    9064              :                                                               HVAC::FanOp::Cycling,
    9065              :                                                               HVAC::CompressorOp::On,
    9066            0 :                                                               state.dataWaterThermalTanks->hpPartLoadRatio,
    9067              :                                                               SpeedNum,
    9068              :                                                               SpeedRatio,
    9069              :                                                               0.0,
    9070              :                                                               0.0,
    9071              :                                                               1.0);
    9072              :                 } else {
    9073            0 :                     VariableSpeedCoils::SimVariableSpeedCoils(state,
    9074              :                                                               HeatPump.DXCoilName,
    9075              :                                                               VSCoilNum,
    9076              :                                                               HVAC::FanOp::Cycling,
    9077              :                                                               HVAC::CompressorOp::On,
    9078            0 :                                                               state.dataWaterThermalTanks->hpPartLoadRatio,
    9079              :                                                               SpeedNum,
    9080              :                                                               SpeedRatio,
    9081              :                                                               0.0,
    9082              :                                                               0.0,
    9083              :                                                               1.0);
    9084              :                 }
    9085            0 :                 state.dataFans->fans(HeatPump.FanNum)->simulate(state, FirstHVACIteration, _, _);
    9086              :             }
    9087              : 
    9088              :             // set the DWH mode
    9089        25630 :             if (HeatPump.bIsIHP) {
    9090         4976 :                 VSCoilNum = state.dataIntegratedHP->IntegratedHeatPumps(HeatPump.DXCoilNum).DWHCoilIndex;
    9091              : 
    9092         4976 :                 if (VSCoilNum > 0) // if DWH coil exists
    9093              :                 {
    9094         4976 :                     if (HeatPump.fanPlace == HVAC::FanPlace::BlowThru) {
    9095         4976 :                         state.dataFans->fans(HeatPump.FanNum)->simulate(state, FirstHVACIteration, _, _);
    9096              : 
    9097         4976 :                         this->SetVSHPWHFlowRates(state, HeatPump, SpeedNum, SpeedRatio, RhoWater, MdotWater, FirstHVACIteration);
    9098         4976 :                         VariableSpeedCoils::SimVariableSpeedCoils(state,
    9099              :                                                                   "",
    9100              :                                                                   VSCoilNum,
    9101              :                                                                   HVAC::FanOp::Cycling,
    9102              :                                                                   HVAC::CompressorOp::On,
    9103         4976 :                                                                   state.dataWaterThermalTanks->hpPartLoadRatio,
    9104              :                                                                   SpeedNum,
    9105              :                                                                   SpeedRatio,
    9106              :                                                                   0.0,
    9107              :                                                                   0.0,
    9108              :                                                                   1.0);
    9109              :                     } else {
    9110            0 :                         this->SetVSHPWHFlowRates(state, HeatPump, SpeedNum, SpeedRatio, RhoWater, MdotWater, FirstHVACIteration);
    9111            0 :                         VariableSpeedCoils::SimVariableSpeedCoils(state,
    9112              :                                                                   "",
    9113              :                                                                   VSCoilNum,
    9114              :                                                                   HVAC::FanOp::Cycling,
    9115              :                                                                   HVAC::CompressorOp::On,
    9116            0 :                                                                   state.dataWaterThermalTanks->hpPartLoadRatio,
    9117              :                                                                   SpeedNum,
    9118              :                                                                   SpeedRatio,
    9119              :                                                                   0.0,
    9120              :                                                                   0.0,
    9121              :                                                                   1.0);
    9122            0 :                         state.dataFans->fans(HeatPump.FanNum)->simulate(state, FirstHVACIteration, _, _);
    9123              :                     }
    9124              :                 }
    9125              :             }
    9126              : 
    9127              :         } else {
    9128        56010 :             if (HeatPump.fanPlace == HVAC::FanPlace::BlowThru) {
    9129        53890 :                 state.dataFans->fans(HeatPump.FanNum)->simulate(state, FirstHVACIteration, _, _);
    9130              : 
    9131       107780 :                 DXCoils::SimDXCoil(state,
    9132              :                                    HeatPump.DXCoilName,
    9133              :                                    compressorOp,
    9134              :                                    FirstHVACIteration,
    9135        53890 :                                    HeatPump.DXCoilNum,
    9136              :                                    HVAC::FanOp::Cycling,
    9137        53890 :                                    state.dataWaterThermalTanks->hpPartLoadRatio);
    9138              :             } else {
    9139         4240 :                 DXCoils::SimDXCoil(state,
    9140              :                                    HeatPump.DXCoilName,
    9141              :                                    compressorOp,
    9142              :                                    FirstHVACIteration,
    9143         2120 :                                    HeatPump.DXCoilNum,
    9144              :                                    HVAC::FanOp::Cycling,
    9145         2120 :                                    state.dataWaterThermalTanks->hpPartLoadRatio);
    9146         2120 :                 state.dataFans->fans(HeatPump.FanNum)->simulate(state, FirstHVACIteration, _, _);
    9147              :             }
    9148              :         }
    9149              : 
    9150        81640 :         if (OutletAirSplitterNode > 0) {
    9151            0 :             state.dataLoopNodes->Node(HPAirOutletNode) = state.dataLoopNodes->Node(OutletAirSplitterNode);
    9152              :         }
    9153              : 
    9154              :         //   Simulate tank if HP compressor unavailable for water heating
    9155        81640 :         this->CalcWaterThermalTank(state);
    9156              : 
    9157              :         //   If HPWH compressor is available and unit is off for another reason, off-cycle parasitics are calculated
    9158        81640 :         if (AvailSchedule != 0) {
    9159        81640 :             HeatPump.OffCycParaFuelRate = HeatPump.OffCycParaLoad * (1.0 - state.dataWaterThermalTanks->hpPartLoadRatio);
    9160        81640 :             HeatPump.OffCycParaFuelEnergy = HeatPump.OffCycParaFuelRate * state.dataHVACGlobal->TimeStepSysSec;
    9161              :         }
    9162              : 
    9163              :         //   Warn if HPWH compressor cut-in temperature is less than the water heater tank's set point temp
    9164        81640 :         if (!state.dataGlobal->WarmupFlag && !state.dataGlobal->DoingSizing && !state.dataGlobal->KickOffSimulation) {
    9165        13926 :             if ((HPSetPointTemp - DeadBandTempDiff) <= this->SetPointTemp) {
    9166            0 :                 Real64 HPMinTemp = HPSetPointTemp - DeadBandTempDiff;
    9167            0 :                 const std::string HPMinTempChar = fmt::to_string(HPMinTemp);
    9168            0 :                 ++HeatPump.HPSetPointError;
    9169              :                 //  add logic for warmup, DataGlobals::KickOffSimulation and doing sizing here
    9170            0 :                 if (HeatPump.HPSetPointError == 1) {
    9171            0 :                     ShowWarningError(state,
    9172            0 :                                      format("{} \"{}:  Water heater tank set point temperature is greater than or equal to the cut-in temperature of "
    9173              :                                             "the heat pump water heater. Heat Pump will be disabled and simulation continues.",
    9174            0 :                                             HeatPump.Type,
    9175            0 :                                             HeatPump.Name));
    9176            0 :                     ShowContinueErrorTimeStamp(state, format(" ...Heat Pump cut-in temperature={}", HPMinTempChar));
    9177              :                 } else {
    9178            0 :                     ShowRecurringWarningErrorAtEnd(state,
    9179            0 :                                                    HeatPump.Type + " \"" + HeatPump.Name +
    9180              :                                                        ":  Water heater tank set point temperature is greater than or equal to the cut-in "
    9181              :                                                        "temperature of the heat pump water heater. Heat Pump will be disabled error continues...",
    9182            0 :                                                    HeatPump.HPSetPointErrIndex1,
    9183              :                                                    HPMinTemp,
    9184              :                                                    HPMinTemp);
    9185              :                 }
    9186            0 :             }
    9187              :         }
    9188        81640 :         return;
    9189              :     }
    9190       326828 :     Real64 savedTankTemp = this->SavedTankTemp;
    9191       326828 :     HeatPump.Mode = HeatPump.SaveMode;
    9192              : 
    9193       326828 :     RhoWater = Psychrometrics::RhoH2O(savedTankTemp); // update water density using tank temp
    9194              : 
    9195              :     // set the heat pump air- and water-side mass flow rate
    9196       326828 :     MdotWater = HeatPump.OperatingWaterFlowRate * Psychrometrics::RhoH2O(savedTankTemp);
    9197              : 
    9198              :     // Select mode of operation (float mode or heat mode) from last iteration.
    9199              :     // Determine if heating will occur this iteration and get an estimate of the PLR
    9200       326828 :     if (HeatPump.Mode == TankOperatingMode::Heating) {
    9201              :         // HPWH was heating last iteration and will continue to heat until the set point is reached
    9202       108536 :         state.dataWaterThermalTanks->hpPartLoadRatio = 1.0;
    9203       108536 :         if (savedTankTemp > HPSetPointTemp) { // tank set point temp may have been reduced since last iteration and float mode may be needed
    9204          110 :             HeatPump.Mode = TankOperatingMode::Floating;
    9205          110 :             state.dataWaterThermalTanks->hpPartLoadRatio = 0.0;
    9206              :             // check to see if HP needs to operate
    9207              :             // set the condenser inlet node temperature and full mass flow rate prior to calling the HPWH DX coil
    9208          110 :             if (HeatPump.HPWHTankType == DataPlant::PlantEquipmentType::WtrHeaterMixed) {
    9209          110 :                 state.dataLoopNodes->Node(HPWaterInletNode).Temp = savedTankTemp;
    9210          110 :                 state.dataLoopNodes->Node(HPWaterOutletNode).Temp = savedTankTemp;
    9211            0 :             } else if (HeatPump.HPWHTankType == DataPlant::PlantEquipmentType::WtrHeaterStratified) {
    9212            0 :                 state.dataLoopNodes->Node(HPWaterInletNode).Temp = this->SourceOutletTemp;
    9213            0 :                 state.dataLoopNodes->Node(HPWaterOutletNode).Temp = this->SourceInletTemp;
    9214              :             }
    9215          110 :             state.dataLoopNodes->Node(HPWaterInletNode).MassFlowRate = 0.0;
    9216          110 :             state.dataLoopNodes->Node(HPWaterOutletNode).MassFlowRate = 0.0;
    9217              : 
    9218              :             // Check tank temperature by setting source inlet mass flow rate to zero.
    9219          110 :             state.dataWaterThermalTanks->hpPartLoadRatio = 0.0;
    9220              : 
    9221              :             // Set the full load outlet temperature on the water heater source inlet node (init has already been called).
    9222          110 :             this->SourceInletTemp = state.dataLoopNodes->Node(HPWaterOutletNode).Temp;
    9223              : 
    9224              :             // Disable the tank's internal heating element to find PLR of the HPWH using floating temperatures.
    9225          110 :             this->MaxCapacity = 0.0;
    9226          110 :             this->MinCapacity = 0.0;
    9227          110 :             this->SourceMassFlowRate = 0.0; // disables heat pump for mixed tanks
    9228          110 :             Real64 SourceEffectivenessBackup = this->SourceEffectiveness;
    9229          110 :             this->SourceEffectiveness = 0.0; // disables heat pump for stratified tanks
    9230          110 :             this->CalcWaterThermalTank(state);
    9231          110 :             this->SourceEffectiveness = SourceEffectivenessBackup;
    9232          110 :             Real64 NewTankTemp = this->GetHPWHSensedTankTemp(state);
    9233              : 
    9234              :             // Reset the tank's internal heating element capacity.
    9235          110 :             this->MaxCapacity = HeatPump.BackupElementCapacity;
    9236          110 :             this->MinCapacity = HeatPump.BackupElementCapacity;
    9237              : 
    9238              :             // Check to see if the tank drifts below set point if no heating happens.
    9239          110 :             if (NewTankTemp <= (HPSetPointTemp - DeadBandTempDiff)) {
    9240              : 
    9241              :                 // HPWH is now in heating mode
    9242           72 :                 HeatPump.Mode = TankOperatingMode::Heating;
    9243              : 
    9244              :                 // Reset the water heater's mode (call above may have changed modes)
    9245           72 :                 this->Mode = HeatPump.SaveWHMode;
    9246              : 
    9247           72 :                 state.dataWaterThermalTanks->hpPartLoadRatio = 1.0;
    9248              :             }
    9249              :         } else { // or use side nodes may meet set point without need for heat pump compressor operation
    9250              :                  // check to see if HP needs to operate
    9251       108426 :             if (HeatPump.HPWHTankType == DataPlant::PlantEquipmentType::WtrHeaterMixed) {
    9252        30832 :                 state.dataLoopNodes->Node(HPWaterInletNode).Temp = savedTankTemp;
    9253        30832 :                 state.dataLoopNodes->Node(HPWaterOutletNode).Temp = savedTankTemp;
    9254        77594 :             } else if (HeatPump.HPWHTankType == DataPlant::PlantEquipmentType::WtrHeaterStratified) {
    9255        77594 :                 state.dataLoopNodes->Node(HPWaterInletNode).Temp = this->SourceOutletTemp;
    9256        77594 :                 state.dataLoopNodes->Node(HPWaterOutletNode).Temp = this->SourceInletTemp;
    9257              :             }
    9258              :             // Check tank temperature by setting source inlet mass flow rate to zero.
    9259       108426 :             state.dataLoopNodes->Node(HPWaterInletNode).MassFlowRate = 0.0;
    9260       108426 :             state.dataLoopNodes->Node(HPWaterOutletNode).MassFlowRate = 0.0;
    9261              : 
    9262       108426 :             state.dataWaterThermalTanks->hpPartLoadRatio = 0.0;
    9263              : 
    9264              :             // Set the full load outlet temperature on the water heater source inlet node (init has already been called).
    9265       108426 :             this->SourceInletTemp = state.dataLoopNodes->Node(HPWaterOutletNode).Temp;
    9266              : 
    9267              :             // Disable the tank's internal heating element to find PLR of the HPWH using floating temperatures.
    9268       108426 :             this->MaxCapacity = 0.0;
    9269       108426 :             this->MinCapacity = 0.0;
    9270       108426 :             this->SourceMassFlowRate = 0.0; // disables heat pump for mixed tanks
    9271       108426 :             Real64 SourceEffectivenessBackup = this->SourceEffectiveness;
    9272       108426 :             this->SourceEffectiveness = 0.0; // disables heat pump for stratified tanks
    9273       108426 :             this->CalcWaterThermalTank(state);
    9274       108426 :             this->SourceEffectiveness = SourceEffectivenessBackup;
    9275       108426 :             Real64 NewTankTemp = this->GetHPWHSensedTankTemp(state);
    9276              : 
    9277              :             // Reset the tank's internal heating element capacity.
    9278       108426 :             this->MaxCapacity = HeatPump.BackupElementCapacity;
    9279       108426 :             this->MinCapacity = HeatPump.BackupElementCapacity;
    9280              : 
    9281              :             // Check to see if the tank meets set point if no heating happens.
    9282       108426 :             if (NewTankTemp > HPSetPointTemp) {
    9283              : 
    9284              :                 // HPWH is now in floating mode
    9285            0 :                 HeatPump.Mode = TankOperatingMode::Floating;
    9286              : 
    9287              :             } else {
    9288              : 
    9289              :                 // HPWH remains in heating mode
    9290       108426 :                 state.dataWaterThermalTanks->hpPartLoadRatio = 1.0;
    9291              :             }
    9292              : 
    9293              :             // Reset the water heater's mode (call above may have changed modes)
    9294       108426 :             this->Mode = HeatPump.SaveWHMode;
    9295              :         }
    9296              :     } else {
    9297       218292 :         assert(HeatPump.Mode == TankOperatingMode::Floating);
    9298              :         // HPWH was floating last iteration and will continue to float until the cut-in temperature is reached
    9299              : 
    9300              :         // set the condenser inlet node temperature and full mass flow rate prior to calling the HPWH DX coil
    9301       218292 :         if (HeatPump.HPWHTankType == DataPlant::PlantEquipmentType::WtrHeaterMixed) {
    9302        95996 :             state.dataLoopNodes->Node(HPWaterInletNode).Temp = savedTankTemp;
    9303        95996 :             state.dataLoopNodes->Node(HPWaterOutletNode).Temp = savedTankTemp;
    9304       122296 :         } else if (HeatPump.HPWHTankType == DataPlant::PlantEquipmentType::WtrHeaterStratified) {
    9305       122296 :             state.dataLoopNodes->Node(HPWaterInletNode).Temp = this->SourceOutletTemp;
    9306       122296 :             state.dataLoopNodes->Node(HPWaterOutletNode).Temp = this->SourceInletTemp;
    9307              :         }
    9308       218292 :         state.dataLoopNodes->Node(HPWaterInletNode).MassFlowRate = 0.0;
    9309       218292 :         state.dataLoopNodes->Node(HPWaterOutletNode).MassFlowRate = 0.0;
    9310              : 
    9311              :         // Check tank temperature by setting source inlet mass flow rate to zero.
    9312       218292 :         state.dataWaterThermalTanks->hpPartLoadRatio = 0.0;
    9313              : 
    9314              :         // Set the full load outlet temperature on the water heater source inlet node (init has already been called).
    9315       218292 :         this->SourceInletTemp = state.dataLoopNodes->Node(HPWaterOutletNode).Temp;
    9316              : 
    9317              :         // Disable the tank's internal heating element to find PLR of the HPWH using floating temperatures.
    9318       218292 :         this->MaxCapacity = 0.0;
    9319       218292 :         this->MinCapacity = 0.0;
    9320       218292 :         this->SourceMassFlowRate = 0.0; // disables heat pump for mixed tanks
    9321       218292 :         Real64 SourceEffectivenessBackup = this->SourceEffectiveness;
    9322       218292 :         this->SourceEffectiveness = 0.0; // disables heat pump for stratified tanks
    9323       218292 :         this->CalcWaterThermalTank(state);
    9324       218292 :         this->SourceEffectiveness = SourceEffectivenessBackup;
    9325       218292 :         Real64 NewTankTemp = this->GetHPWHSensedTankTemp(state);
    9326              : 
    9327              :         // Reset the tank's internal heating element capacity.
    9328       218292 :         this->MaxCapacity = HeatPump.BackupElementCapacity;
    9329       218292 :         this->MinCapacity = HeatPump.BackupElementCapacity;
    9330              : 
    9331              :         // Check to see if the tank drifts below set point if no heating happens.
    9332       218292 :         if (NewTankTemp <= (HPSetPointTemp - DeadBandTempDiff)) {
    9333              : 
    9334              :             // HPWH is now in heating mode
    9335        45808 :             HeatPump.Mode = TankOperatingMode::Heating;
    9336              : 
    9337              :             // Reset the water heater's mode (call above may have changed modes)
    9338        45808 :             this->Mode = HeatPump.SaveWHMode;
    9339              : 
    9340        45808 :             state.dataWaterThermalTanks->hpPartLoadRatio = 1.0;
    9341              :         }
    9342              :     }
    9343              : 
    9344       326828 :     if (HeatPump.bIsIHP) // mark the water heating call, if existing
    9345              :     {
    9346         5070 :         if (state.dataIntegratedHP->IntegratedHeatPumps(HeatPump.DXCoilNum).CheckWHCall) {
    9347         2534 :             if (HeatPump.Mode == TankOperatingMode::Heating) {
    9348         1258 :                 state.dataIntegratedHP->IntegratedHeatPumps(HeatPump.DXCoilNum).IsWHCallAvail = true;
    9349              :             } else {
    9350         1276 :                 state.dataIntegratedHP->IntegratedHeatPumps(HeatPump.DXCoilNum).IsWHCallAvail = false;
    9351              :             }
    9352              :         }
    9353              :     }
    9354              : 
    9355              :     // If the HPWH was in heating mode during the last DataGlobals::TimeStep or if it was determined that
    9356              :     // heating would be needed during this DataGlobals::TimeStep to maintain setpoint, do the heating calculation.
    9357       326828 :     int SpeedNum = 0;
    9358       326828 :     Real64 SpeedRatio = 0.0;
    9359       326828 :     if (HeatPump.Mode == TankOperatingMode::Heating) {
    9360              : 
    9361              :         // set up air flow on DX coil inlet node
    9362       154306 :         state.dataLoopNodes->Node(DXCoilAirInletNode).MassFlowRate =
    9363       154306 :             state.dataWaterThermalTanks->mdotAir * state.dataWaterThermalTanks->hpPartLoadRatio;
    9364              : 
    9365              :         // set the condenser inlet node mass flow rate prior to calling the DXCoils::CalcHPWHDXCoil
    9366       154306 :         state.dataLoopNodes->Node(HPWaterInletNode).MassFlowRate = MdotWater * state.dataWaterThermalTanks->hpPartLoadRatio;
    9367       154306 :         this->SourceMassFlowRate = MdotWater * state.dataWaterThermalTanks->hpPartLoadRatio;
    9368              : 
    9369              :         // Do the coil and tank calculations at full PLR to see if it overshoots setpoint.
    9370       154306 :         bool bIterSpeed = false;
    9371       154306 :         if (MaxSpeedNum > 0) { // lowest speed of VS HPWH coil
    9372        20581 :             SpeedRatio = 1.0;
    9373        20581 :             state.dataWaterThermalTanks->hpPartLoadRatio = 1.0;
    9374        20581 :             bIterSpeed = true; // prepare for iterating between speed levels
    9375        20581 :             SpeedNum = 1;
    9376        20581 :             this->SetVSHPWHFlowRates(state, HeatPump, SpeedNum, SpeedRatio, RhoWater, MdotWater, FirstHVACIteration);
    9377              : 
    9378        20581 :             if (HeatPump.bIsIHP) {
    9379         2517 :                 bIterSpeed = false; // don't iterate speed unless match conditions below
    9380         2517 :                 IHPMode = IntegratedHeatPump::GetCurWorkMode(state, HeatPump.DXCoilNum);
    9381              : 
    9382         2517 :                 if (state.dataIntegratedHP->IntegratedHeatPumps(HeatPump.DXCoilNum).CheckWHCall) {
    9383              :                     int VSCoilNum;
    9384         1258 :                     if (IntegratedHeatPump::IHPOperationMode::DedicatedWaterHtg == IHPMode) {
    9385           48 :                         VSCoilNum = state.dataIntegratedHP->IntegratedHeatPumps(HeatPump.DXCoilNum).DWHCoilIndex;
    9386           48 :                         state.dataIntegratedHP->IntegratedHeatPumps(HeatPump.DXCoilNum).CurMode =
    9387              :                             IntegratedHeatPump::IHPOperationMode::DedicatedWaterHtg;
    9388              :                     } else {
    9389         1210 :                         VSCoilNum = state.dataIntegratedHP->IntegratedHeatPumps(HeatPump.DXCoilNum).SCWHCoilIndex;
    9390         1210 :                         state.dataIntegratedHP->IntegratedHeatPumps(HeatPump.DXCoilNum).CurMode = IntegratedHeatPump::IHPOperationMode::SCWHMatchWH;
    9391              :                     }
    9392              : 
    9393         1258 :                     this->SetVSHPWHFlowRates(state, HeatPump, SpeedNum, SpeedRatio, RhoWater, MdotWater, FirstHVACIteration);
    9394              : 
    9395         1258 :                     VariableSpeedCoils::SimVariableSpeedCoils(state,
    9396              :                                                               "",
    9397              :                                                               VSCoilNum,
    9398              :                                                               HVAC::FanOp::Cycling,
    9399              :                                                               HVAC::CompressorOp::On,
    9400         1258 :                                                               state.dataWaterThermalTanks->hpPartLoadRatio,
    9401              :                                                               SpeedNum,
    9402              :                                                               SpeedRatio,
    9403              :                                                               0.0,
    9404              :                                                               0.0,
    9405              :                                                               1.0);
    9406              : 
    9407         1258 :                     state.dataIntegratedHP->IntegratedHeatPumps(HeatPump.DXCoilNum).CurMode = IHPMode;
    9408         1258 :                     this->SetVSHPWHFlowRates(state, HeatPump, SpeedNum, SpeedRatio, RhoWater, MdotWater, FirstHVACIteration);
    9409              :                 } else {
    9410         1259 :                     SpeedNum = IntegratedHeatPump::GetLowSpeedNumIHP(state, HeatPump.DXCoilNum);
    9411              : 
    9412         1259 :                     this->SetVSHPWHFlowRates(state, HeatPump, SpeedNum, SpeedRatio, RhoWater, MdotWater, FirstHVACIteration);
    9413         1259 :                     IntegratedHeatPump::SimIHP(state,
    9414              :                                                HeatPump.DXCoilName,
    9415         1259 :                                                HeatPump.DXCoilNum,
    9416              :                                                HVAC::FanOp::Cycling,
    9417              :                                                HVAC::CompressorOp::On,
    9418         1259 :                                                state.dataWaterThermalTanks->hpPartLoadRatio,
    9419              :                                                SpeedNum,
    9420              :                                                SpeedRatio,
    9421              :                                                0.0,
    9422              :                                                0.0,
    9423              :                                                true,
    9424              :                                                false,
    9425         1259 :                                                1.0);
    9426              : 
    9427         1259 :                     if ((IntegratedHeatPump::IHPOperationMode::SCWHMatchWH == IHPMode) ||
    9428              :                         (IntegratedHeatPump::IHPOperationMode::DedicatedWaterHtg == IHPMode)) {
    9429          112 :                         bIterSpeed = true;
    9430              :                     } else {
    9431         1147 :                         this->SourceMassFlowRate = state.dataIntegratedHP->IntegratedHeatPumps(HeatPump.DXCoilNum).TankSourceWaterMassFlowRate;
    9432         1147 :                         MdotWater = this->SourceMassFlowRate;
    9433              :                     }
    9434              : 
    9435         1259 :                     if (IntegratedHeatPump::IHPOperationMode::SHDWHElecHeatOff == IHPMode) // turn off heater element
    9436              :                     {
    9437            0 :                         this->MaxCapacity = 0.0;
    9438            0 :                         this->MinCapacity = 0.0;
    9439              :                     }
    9440              :                 }
    9441              :             } else {
    9442        18064 :                 VariableSpeedCoils::SimVariableSpeedCoils(state,
    9443              :                                                           HeatPump.DXCoilName,
    9444        18064 :                                                           HeatPump.DXCoilNum,
    9445              :                                                           HVAC::FanOp::Cycling,
    9446              :                                                           HVAC::CompressorOp::On,
    9447        18064 :                                                           state.dataWaterThermalTanks->hpPartLoadRatio,
    9448              :                                                           SpeedNum,
    9449              :                                                           SpeedRatio,
    9450              :                                                           0.0,
    9451              :                                                           0.0,
    9452              :                                                           1.0);
    9453              :             }
    9454              : 
    9455        20581 :             this->CalcWaterThermalTank(state);
    9456              :         } else {
    9457       133725 :             this->ConvergeSingleSpeedHPWHCoilAndTank(state, state.dataWaterThermalTanks->hpPartLoadRatio);
    9458              :         }
    9459              : 
    9460       154306 :         Real64 NewTankTemp = this->GetHPWHSensedTankTemp(state);
    9461       154306 :         Real64 LowSpeedTankTemp = NewTankTemp;
    9462       154306 :         Real64 HPWHCondInletNodeLast = state.dataLoopNodes->Node(HPWaterInletNode).Temp;
    9463              : 
    9464       154306 :         if (NewTankTemp > HPSetPointTemp) {
    9465        11261 :             HeatPump.Mode = TankOperatingMode::Floating;
    9466        11261 :             TankOperatingMode tmpMode = HeatPump.SaveWHMode;
    9467        55028 :             auto f = [&state, this, HPSetPointTemp, tmpMode, MdotWater](Real64 const HPPartLoadRatio) {
    9468        55028 :                 return this->PLRResidualHPWH(state, HPPartLoadRatio, HPSetPointTemp, tmpMode, MdotWater);
    9469        11261 :             };
    9470        11261 :             Real64 zeroResidual = 1.0;
    9471        11261 :             if (MaxSpeedNum > 0) {
    9472              :                 // square the solving, and avoid warning
    9473              :                 // due to very small capacity at lowest speed of VSHPWH coil
    9474          931 :                 if (bIterSpeed) {
    9475          915 :                     zeroResidual = this->PLRResidualHPWH(state, 0.0, HPSetPointTemp, tmpMode, MdotWater);
    9476              :                 } else {
    9477           16 :                     zeroResidual = -1.0;
    9478              :                 }
    9479              :             }
    9480              : 
    9481        11261 :             if (zeroResidual > 0.0) { // then iteration
    9482              :                 int SolFla;
    9483        10888 :                 General::SolveRoot(state, Acc, MaxIte, SolFla, state.dataWaterThermalTanks->hpPartLoadRatio, f, 0.0, 1.0);
    9484        10888 :                 if (SolFla == -1) {
    9485            0 :                     std::string IterNum;
    9486            0 :                     IterNum = fmt::to_string(MaxIte);
    9487            0 :                     if (!state.dataGlobal->WarmupFlag) {
    9488            0 :                         ++HeatPump.IterLimitExceededNum2;
    9489            0 :                         if (HeatPump.IterLimitExceededNum2 == 1) {
    9490            0 :                             ShowWarningError(state, format("{} \"{}\"", HeatPump.Type, HeatPump.Name));
    9491            0 :                             ShowContinueError(state,
    9492            0 :                                               format("Iteration limit exceeded calculating heat pump water heater compressor part-load ratio, "
    9493              :                                                      "maximum iterations = {}. Part-load ratio returned = {:.3R}",
    9494              :                                                      IterNum,
    9495            0 :                                                      state.dataWaterThermalTanks->hpPartLoadRatio));
    9496            0 :                             ShowContinueErrorTimeStamp(state, "This error occurred in float mode.");
    9497              :                         } else {
    9498            0 :                             ShowRecurringWarningErrorAtEnd(
    9499              :                                 state,
    9500            0 :                                 HeatPump.Type + " \"" + HeatPump.Name +
    9501              :                                     "\":  Iteration limit exceeded in float mode warning continues. Part-load ratio statistics follow.",
    9502            0 :                                 HeatPump.IterLimitErrIndex2,
    9503            0 :                                 state.dataWaterThermalTanks->hpPartLoadRatio,
    9504            0 :                                 state.dataWaterThermalTanks->hpPartLoadRatio);
    9505              :                         }
    9506              :                     }
    9507        10888 :                 } else if (SolFla == -2) {
    9508          304 :                     state.dataWaterThermalTanks->hpPartLoadRatio =
    9509          304 :                         max(0.0, min(1.0, (HPSetPointTemp - savedTankTemp) / (NewTankTemp - savedTankTemp)));
    9510          304 :                     if (!state.dataGlobal->WarmupFlag) {
    9511          152 :                         ++HeatPump.RegulaFalsiFailedNum2;
    9512          152 :                         if (HeatPump.RegulaFalsiFailedNum2 == 1) {
    9513            1 :                             ShowWarningError(state, format("{} \"{}\"", HeatPump.Type, HeatPump.Name));
    9514            2 :                             ShowContinueError(state,
    9515            2 :                                               format("Heat pump water heater compressor part-load ratio calculation failed: PLR limits of 0 to 1 "
    9516              :                                                      "exceeded. Part-load ratio used = {:.3R}",
    9517            1 :                                                      state.dataWaterThermalTanks->hpPartLoadRatio));
    9518            2 :                             ShowContinueError(state, "Please send this information to the EnergyPlus support group.");
    9519            3 :                             ShowContinueErrorTimeStamp(state, "This error occurred in float mode.");
    9520              :                         } else {
    9521         1208 :                             ShowRecurringWarningErrorAtEnd(
    9522              :                                 state,
    9523          302 :                                 HeatPump.Type + " \"" + HeatPump.Name +
    9524              :                                     "\": Part-load ratio calculation failed in float mode warning continues. Part-load ratio statistics follow.",
    9525          151 :                                 HeatPump.RegulaFalsiFailedIndex2,
    9526          151 :                                 state.dataWaterThermalTanks->hpPartLoadRatio,
    9527          151 :                                 state.dataWaterThermalTanks->hpPartLoadRatio);
    9528              :                         }
    9529              :                     }
    9530              :                 }
    9531              :             } else {
    9532          373 :                 state.dataWaterThermalTanks->hpPartLoadRatio = 0.0;
    9533              :             }
    9534              : 
    9535              :             // Re-calculate the HPWH Coil to get the correct heat transfer rate.
    9536        11261 :             state.dataLoopNodes->Node(HPWaterInletNode).Temp = this->SourceOutletTemp;
    9537        11261 :             if (MaxSpeedNum > 0) {
    9538          931 :                 SpeedRatio = 1.0;
    9539          931 :                 SpeedNum = 1;
    9540              : 
    9541          931 :                 this->SetVSHPWHFlowRates(state, HeatPump, SpeedNum, SpeedRatio, RhoWater, MdotWater, FirstHVACIteration);
    9542              : 
    9543          931 :                 if (HeatPump.bIsIHP) {
    9544           32 :                     if (bIterSpeed) {
    9545           16 :                         IntegratedHeatPump::SimIHP(state,
    9546              :                                                    HeatPump.DXCoilName,
    9547           16 :                                                    HeatPump.DXCoilNum,
    9548              :                                                    HVAC::FanOp::Cycling,
    9549              :                                                    HVAC::CompressorOp::On,
    9550           16 :                                                    state.dataWaterThermalTanks->hpPartLoadRatio,
    9551              :                                                    SpeedNum,
    9552              :                                                    SpeedRatio,
    9553              :                                                    0.0,
    9554              :                                                    0.0,
    9555              :                                                    true,
    9556              :                                                    false,
    9557           32 :                                                    1.0);
    9558              :                     }
    9559              :                 } else {
    9560          899 :                     VariableSpeedCoils::SimVariableSpeedCoils(state,
    9561              :                                                               HeatPump.DXCoilName,
    9562          899 :                                                               HeatPump.DXCoilNum,
    9563              :                                                               HVAC::FanOp::Cycling,
    9564              :                                                               HVAC::CompressorOp::On,
    9565          899 :                                                               state.dataWaterThermalTanks->hpPartLoadRatio,
    9566              :                                                               SpeedNum,
    9567              :                                                               SpeedRatio,
    9568              :                                                               0.0,
    9569              :                                                               0.0,
    9570              :                                                               1.0);
    9571              :                 }
    9572              : 
    9573              :             } else {
    9574        10330 :                 DXCoils::CalcHPWHDXCoil(state, HeatPump.DXCoilNum, state.dataWaterThermalTanks->hpPartLoadRatio);
    9575              :             }
    9576       143045 :         } else if (bIterSpeed) {
    9577        43656 :             for (int loopIter = 1; loopIter <= 4; ++loopIter) {
    9578        43656 :                 HeatPump.Mode = TankOperatingMode::Heating; // modHeatMode is important for system convergence
    9579        43656 :                 state.dataWaterThermalTanks->hpPartLoadRatio = 1.0;
    9580        43656 :                 SpeedRatio = 1.0;
    9581        43656 :                 int LowSpeedNum = 2;
    9582        43656 :                 if (HeatPump.bIsIHP) {
    9583          272 :                     LowSpeedNum = IntegratedHeatPump::GetLowSpeedNumIHP(state, HeatPump.DXCoilNum);
    9584          272 :                     MaxSpeedNum = IntegratedHeatPump::GetMaxSpeedNumIHP(state, HeatPump.DXCoilNum);
    9585              :                 }
    9586              : 
    9587       351730 :                 for (int i = LowSpeedNum; i <= MaxSpeedNum; ++i) {
    9588       319936 :                     SpeedNum = i;
    9589       319936 :                     this->SetVSHPWHFlowRates(state, HeatPump, SpeedNum, SpeedRatio, RhoWater, MdotWater, FirstHVACIteration);
    9590       319936 :                     if (HeatPump.bIsIHP) {
    9591         2624 :                         IntegratedHeatPump::SimIHP(state,
    9592              :                                                    HeatPump.DXCoilName,
    9593         2624 :                                                    HeatPump.DXCoilNum,
    9594              :                                                    HVAC::FanOp::Cycling,
    9595              :                                                    HVAC::CompressorOp::On,
    9596         2624 :                                                    state.dataWaterThermalTanks->hpPartLoadRatio,
    9597              :                                                    SpeedNum,
    9598              :                                                    SpeedRatio,
    9599              :                                                    0.0,
    9600              :                                                    0.0,
    9601              :                                                    true,
    9602              :                                                    false,
    9603         5248 :                                                    1.0);
    9604              :                     } else {
    9605       317312 :                         VariableSpeedCoils::SimVariableSpeedCoils(state,
    9606              :                                                                   HeatPump.DXCoilName,
    9607       317312 :                                                                   HeatPump.DXCoilNum,
    9608              :                                                                   HVAC::FanOp::Cycling,
    9609              :                                                                   HVAC::CompressorOp::On,
    9610       317312 :                                                                   state.dataWaterThermalTanks->hpPartLoadRatio,
    9611              :                                                                   SpeedNum,
    9612              :                                                                   SpeedRatio,
    9613              :                                                                   0.0,
    9614              :                                                                   0.0,
    9615              :                                                                   1.0);
    9616              :                     }
    9617              : 
    9618              :                     // HPWH condenser water temperature difference
    9619       319936 :                     Real64 CondenserDeltaT = state.dataLoopNodes->Node(HPWaterOutletNode).Temp - state.dataLoopNodes->Node(HPWaterInletNode).Temp;
    9620              : 
    9621              :                     //           move the full load outlet temperature rate to the water heater structure variables
    9622              :                     //           (water heaters source inlet node temperature/mdot are set in Init, set it here after DXCoils::CalcHPWHDXCoil has
    9623              :                     //           been called)
    9624       319936 :                     this->SourceInletTemp = state.dataLoopNodes->Node(HPWaterInletNode).Temp + CondenserDeltaT;
    9625              :                     //           this CALL does not update node temps, must use WaterThermalTank variables
    9626              :                     // select tank type
    9627       319936 :                     if (HeatPump.HPWHTankType == DataPlant::PlantEquipmentType::WtrHeaterMixed) {
    9628       312974 :                         this->CalcWaterThermalTankMixed(state);
    9629       312974 :                         NewTankTemp = this->TankTemp;
    9630         6962 :                     } else if (HeatPump.HPWHTankType == DataPlant::PlantEquipmentType::WtrHeaterStratified) {
    9631         6962 :                         this->CalcWaterThermalTankStratified(state);
    9632         6962 :                         NewTankTemp = this->FindStratifiedTankSensedTemp(state);
    9633              :                     }
    9634              : 
    9635       319936 :                     if (NewTankTemp > HPSetPointTemp) {
    9636        11862 :                         SpeedNum = i;
    9637        11862 :                         break;
    9638              :                     } else {
    9639       308074 :                         LowSpeedTankTemp = NewTankTemp;
    9640              :                     }
    9641              :                 }
    9642              : 
    9643        43656 :                 if (NewTankTemp > HPSetPointTemp) {
    9644              :                     int SolFla;
    9645        11862 :                     std::string IterNum;
    9646        76295 :                     auto f = [&state, this, SpeedNum, HPWaterInletNode, HPWaterOutletNode, RhoWater, HPSetPointTemp, &HeatPump, FirstHVACIteration](
    9647              :                                  Real64 const SpeedRatio) {
    9648       152590 :                         return this->PLRResidualIterSpeed(state,
    9649              :                                                           SpeedRatio,
    9650        76295 :                                                           this->HeatPumpNum,
    9651              :                                                           SpeedNum,
    9652              :                                                           HPWaterInletNode,
    9653              :                                                           HPWaterOutletNode,
    9654              :                                                           RhoWater,
    9655              :                                                           HPSetPointTemp,
    9656        76295 :                                                           HeatPump.SaveWHMode,
    9657        76295 :                                                           FirstHVACIteration);
    9658        11862 :                     };
    9659        11862 :                     General::SolveRoot(state, Acc, MaxIte, SolFla, SpeedRatio, f, 1.0e-10, 1.0);
    9660              : 
    9661        11862 :                     if (SolFla == -1) {
    9662            0 :                         IterNum = fmt::to_string(MaxIte);
    9663            0 :                         if (!state.dataGlobal->WarmupFlag) {
    9664            0 :                             ++HeatPump.IterLimitExceededNum1;
    9665            0 :                             if (HeatPump.IterLimitExceededNum1 == 1) {
    9666            0 :                                 ShowWarningError(state, format("{} \"{}\"", HeatPump.Type, HeatPump.Name));
    9667            0 :                                 ShowContinueError(state,
    9668            0 :                                                   format("Iteration limit exceeded calculating heat pump water heater speed speed ratio ratio, "
    9669              :                                                          "maximum iterations = {}. speed ratio returned = {:.3R}",
    9670              :                                                          IterNum,
    9671              :                                                          SpeedRatio));
    9672            0 :                                 ShowContinueErrorTimeStamp(state, "This error occurred in heating mode.");
    9673              :                             } else {
    9674            0 :                                 ShowRecurringWarningErrorAtEnd(
    9675              :                                     state,
    9676            0 :                                     HeatPump.Type + " \"" + HeatPump.Name +
    9677              :                                         "\":  Iteration limit exceeded in heating mode warning continues. speed ratio statistics follow.",
    9678            0 :                                     HeatPump.IterLimitErrIndex1,
    9679              :                                     SpeedRatio,
    9680              :                                     SpeedRatio);
    9681              :                             }
    9682              :                         }
    9683        11862 :                     } else if (SolFla == -2) {
    9684            0 :                         SpeedRatio = max(0.0, min(1.0, (HPSetPointTemp - LowSpeedTankTemp) / (NewTankTemp - LowSpeedTankTemp)));
    9685            0 :                         if (!state.dataGlobal->WarmupFlag) {
    9686            0 :                             ++HeatPump.RegulaFalsiFailedNum1;
    9687            0 :                             if (HeatPump.RegulaFalsiFailedNum1 == 1) {
    9688            0 :                                 ShowWarningError(state, format("{} \"{}\"", HeatPump.Type, HeatPump.Name));
    9689            0 :                                 ShowContinueError(state,
    9690            0 :                                                   format("Heat pump water heater speed ratio calculation failed: speed ratio limits of 0 to 1 "
    9691              :                                                          "exceeded. speed ratio used = {:.3R}",
    9692              :                                                          SpeedRatio));
    9693            0 :                                 ShowContinueError(state, "Please send this information to the EnergyPlus support group.");
    9694            0 :                                 ShowContinueErrorTimeStamp(state, "This error occurred in heating mode.");
    9695              :                             } else {
    9696            0 :                                 ShowRecurringWarningErrorAtEnd(
    9697              :                                     state,
    9698            0 :                                     HeatPump.Type + " \"" + HeatPump.Name +
    9699              :                                         "\":  Speed ratio calculation failed in heating mode warning continues. Speed ratio statistics follow.",
    9700            0 :                                     HeatPump.RegulaFalsiFailedIndex1,
    9701              :                                     SpeedRatio,
    9702              :                                     SpeedRatio);
    9703              :                             }
    9704              :                         }
    9705              :                     }
    9706        11862 :                 } else {
    9707        31794 :                     SpeedNum = MaxSpeedNum;
    9708        31794 :                     SpeedRatio = 1.0;
    9709              :                 }
    9710              : 
    9711        43656 :                 state.dataWaterThermalTanks->hpPartLoadRatio = 1.0;
    9712        43656 :                 this->SetVSHPWHFlowRates(state, HeatPump, SpeedNum, SpeedRatio, RhoWater, MdotWater, FirstHVACIteration);
    9713              : 
    9714        43656 :                 if (HeatPump.bIsIHP) {
    9715          272 :                     IntegratedHeatPump::SimIHP(state,
    9716              :                                                HeatPump.DXCoilName,
    9717          272 :                                                HeatPump.DXCoilNum,
    9718              :                                                HVAC::FanOp::Cycling,
    9719              :                                                HVAC::CompressorOp::On,
    9720          272 :                                                state.dataWaterThermalTanks->hpPartLoadRatio,
    9721              :                                                SpeedNum,
    9722              :                                                SpeedRatio,
    9723              :                                                0.0,
    9724              :                                                0.0,
    9725              :                                                true,
    9726              :                                                false,
    9727          544 :                                                1.0);
    9728              :                 } else {
    9729        43384 :                     VariableSpeedCoils::SimVariableSpeedCoils(state,
    9730              :                                                               HeatPump.DXCoilName,
    9731        43384 :                                                               HeatPump.DXCoilNum,
    9732              :                                                               HVAC::FanOp::Cycling,
    9733              :                                                               HVAC::CompressorOp::On,
    9734        43384 :                                                               state.dataWaterThermalTanks->hpPartLoadRatio,
    9735              :                                                               SpeedNum,
    9736              :                                                               SpeedRatio,
    9737              :                                                               0.0,
    9738              :                                                               0.0,
    9739              :                                                               1.0);
    9740              :                 }
    9741              : 
    9742              :                 // HPWH condenser water temperature difference
    9743        43656 :                 Real64 CondenserDeltaT = state.dataLoopNodes->Node(HPWaterOutletNode).Temp - state.dataLoopNodes->Node(HPWaterInletNode).Temp;
    9744              : 
    9745              :                 //           move the full load outlet temperature rate to the water heater structure variables
    9746              :                 //           (water heaters source inlet node temperature/mdot are set in Init, set it here after DXCoils::CalcHPWHDXCoil has been
    9747              :                 //           called)
    9748        43656 :                 this->SourceInletTemp = state.dataLoopNodes->Node(HPWaterInletNode).Temp + CondenserDeltaT;
    9749              :                 //           this CALL does not update node temps, must use WaterThermalTank variables
    9750              :                 // select tank type
    9751        43656 :                 if (HeatPump.HPWHTankType == DataPlant::PlantEquipmentType::WtrHeaterMixed) {
    9752        40175 :                     this->CalcWaterThermalTankMixed(state);
    9753        40175 :                     NewTankTemp = this->TankTemp;
    9754         3481 :                 } else if (HeatPump.HPWHTankType == DataPlant::PlantEquipmentType::WtrHeaterStratified) {
    9755         3481 :                     this->CalcWaterThermalTankStratified(state);
    9756         3481 :                     NewTankTemp = this->FindStratifiedTankSensedTemp(state);
    9757              :                 }
    9758              :                 // update inlet temp
    9759        43656 :                 state.dataLoopNodes->Node(HPWaterInletNode).Temp = this->SourceOutletTemp;
    9760        43656 :                 if (std::abs(state.dataLoopNodes->Node(HPWaterInletNode).Temp - HPWHCondInletNodeLast) < HVAC::SmallTempDiff) {
    9761        17261 :                     break;
    9762              :                 }
    9763        26395 :                 HPWHCondInletNodeLast = state.dataLoopNodes->Node(HPWaterInletNode).Temp;
    9764              :             }
    9765              : 
    9766              :         } else {
    9767              :             // Set the PLR to 1 if we're not going to reach setpoint during this DataGlobals::TimeStep.
    9768       125784 :             state.dataWaterThermalTanks->hpPartLoadRatio = 1.0;
    9769              :         }
    9770              :     }
    9771              : 
    9772       326828 :     if (HeatPump.bIsIHP) {
    9773         5070 :         if (state.dataIntegratedHP->IntegratedHeatPumps(HeatPump.DXCoilNum).CheckWHCall) {
    9774         2534 :             IntegratedHeatPump::ClearCoils(state, HeatPump.DXCoilNum); // clear node info when checking the heating load
    9775              :         }
    9776              :     }
    9777              : 
    9778              :     // set air-side mass flow rate for final calculation
    9779       326828 :     if (InletAirMixerNode > 0) {
    9780        16038 :         state.dataLoopNodes->Node(InletAirMixerNode).MassFlowRate =
    9781        16038 :             state.dataWaterThermalTanks->mdotAir * state.dataWaterThermalTanks->hpPartLoadRatio;
    9782        32076 :         state.dataLoopNodes->Node(HPAirInletNode).MassFlowRate = state.dataWaterThermalTanks->mdotAir * state.dataWaterThermalTanks->hpPartLoadRatio *
    9783        16038 :                                                                  (1.0 - state.dataWaterThermalTanks->mixerInletAirSchedule);
    9784        16038 :         state.dataLoopNodes->Node(OutdoorAirNode).MassFlowRate =
    9785        16038 :             state.dataWaterThermalTanks->mdotAir * state.dataWaterThermalTanks->hpPartLoadRatio * state.dataWaterThermalTanks->mixerInletAirSchedule;
    9786              :         //   IF HPWH is off, pass zone node conditions through HPWH air-side
    9787        16038 :         if (state.dataWaterThermalTanks->hpPartLoadRatio == 0) {
    9788        11931 :             state.dataLoopNodes->Node(InletAirMixerNode) = state.dataLoopNodes->Node(HPAirInletNode);
    9789              :         }
    9790              :     } else {
    9791       310790 :         if (OutdoorAirNode == 0) {
    9792       183482 :             state.dataLoopNodes->Node(HPAirInletNode).MassFlowRate =
    9793       183482 :                 state.dataWaterThermalTanks->mdotAir * state.dataWaterThermalTanks->hpPartLoadRatio;
    9794              :         } else {
    9795       127308 :             state.dataLoopNodes->Node(OutdoorAirNode).MassFlowRate =
    9796       127308 :                 state.dataWaterThermalTanks->mdotAir * state.dataWaterThermalTanks->hpPartLoadRatio;
    9797              :         }
    9798              :     }
    9799       326828 :     if (state.dataWaterThermalTanks->hpPartLoadRatio == 0) {
    9800       172911 :         this->SourceInletTemp = this->SourceOutletTemp;
    9801              :     }
    9802              : 
    9803              :     // set water-side mass flow rate for final calculation
    9804       326828 :     state.dataLoopNodes->Node(HPWaterInletNode).MassFlowRate = MdotWater * state.dataWaterThermalTanks->hpPartLoadRatio;
    9805              : 
    9806       326828 :     if (MaxSpeedNum > 0) {
    9807              : 
    9808              :         // it is important to use mdotAir to reset the notes, otherwise, could fail to converge
    9809        39684 :         if (InletAirMixerNode > 0) {
    9810         4250 :             state.dataLoopNodes->Node(InletAirMixerNode).MassFlowRateMax = state.dataWaterThermalTanks->mdotAir;
    9811         4250 :             state.dataLoopNodes->Node(InletAirMixerNode).MassFlowRateMaxAvail = state.dataWaterThermalTanks->mdotAir;
    9812              :         } else {
    9813        35434 :             if (OutdoorAirNode == 0) {
    9814         8454 :                 state.dataLoopNodes->Node(HPAirInletNode).MassFlowRateMax = state.dataWaterThermalTanks->mdotAir;
    9815         8454 :                 state.dataLoopNodes->Node(HPAirInletNode).MassFlowRateMaxAvail = state.dataWaterThermalTanks->mdotAir;
    9816              :             } else {
    9817        26980 :                 state.dataLoopNodes->Node(OutdoorAirNode).MassFlowRateMax = state.dataWaterThermalTanks->mdotAir;
    9818        26980 :                 state.dataLoopNodes->Node(OutdoorAirNode).MassFlowRateMaxAvail = state.dataWaterThermalTanks->mdotAir;
    9819              :             }
    9820              :         }
    9821              : 
    9822              :         //   set the max mass flow rate for outdoor fans
    9823        39684 :         state.dataLoopNodes->Node(HeatPump.FanOutletNode).MassFlowRateMax = state.dataWaterThermalTanks->mdotAir;
    9824              : 
    9825        39684 :         if (HeatPump.bIsIHP) {
    9826              :             // pass node information using resulting PLR
    9827         5070 :             if (HeatPump.fanPlace == HVAC::FanPlace::BlowThru) {
    9828              :                 //   simulate fan and DX coil twice to pass PLF (OnOffFanPartLoadFraction) to fan
    9829         5070 :                 state.dataFans->fans(HeatPump.FanNum)->simulate(state, FirstHVACIteration, _, _);
    9830              : 
    9831         5070 :                 IntegratedHeatPump::SimIHP(state,
    9832              :                                            HeatPump.DXCoilName,
    9833         5070 :                                            HeatPump.DXCoilNum,
    9834              :                                            HVAC::FanOp::Cycling,
    9835              :                                            compressorOp,
    9836         5070 :                                            state.dataWaterThermalTanks->hpPartLoadRatio,
    9837              :                                            SpeedNum,
    9838              :                                            SpeedRatio,
    9839              :                                            0.0,
    9840              :                                            0.0,
    9841              :                                            true,
    9842              :                                            false,
    9843         5070 :                                            1.0);
    9844         5070 :                 state.dataFans->fans(HeatPump.FanNum)->simulate(state, FirstHVACIteration, _, _);
    9845              : 
    9846         5070 :                 IntegratedHeatPump::SimIHP(state,
    9847              :                                            HeatPump.DXCoilName,
    9848         5070 :                                            HeatPump.DXCoilNum,
    9849              :                                            HVAC::FanOp::Cycling,
    9850              :                                            compressorOp,
    9851         5070 :                                            state.dataWaterThermalTanks->hpPartLoadRatio,
    9852              :                                            SpeedNum,
    9853              :                                            SpeedRatio,
    9854              :                                            0.0,
    9855              :                                            0.0,
    9856              :                                            true,
    9857              :                                            false,
    9858        10140 :                                            1.0);
    9859              :             } else {
    9860              :                 //   simulate DX coil and fan twice to pass fan power (FanElecPower) to DX coil
    9861            0 :                 IntegratedHeatPump::SimIHP(state,
    9862              :                                            HeatPump.DXCoilName,
    9863            0 :                                            HeatPump.DXCoilNum,
    9864              :                                            HVAC::FanOp::Cycling,
    9865              :                                            compressorOp,
    9866            0 :                                            state.dataWaterThermalTanks->hpPartLoadRatio,
    9867              :                                            SpeedNum,
    9868              :                                            SpeedRatio,
    9869              :                                            0.0,
    9870              :                                            0.0,
    9871              :                                            true,
    9872              :                                            false,
    9873            0 :                                            1.0);
    9874            0 :                 state.dataFans->fans(HeatPump.FanNum)->simulate(state, FirstHVACIteration, _, _);
    9875              : 
    9876            0 :                 IntegratedHeatPump::SimIHP(state,
    9877              :                                            HeatPump.DXCoilName,
    9878            0 :                                            HeatPump.DXCoilNum,
    9879              :                                            HVAC::FanOp::Cycling,
    9880              :                                            compressorOp,
    9881            0 :                                            state.dataWaterThermalTanks->hpPartLoadRatio,
    9882              :                                            SpeedNum,
    9883              :                                            SpeedRatio,
    9884              :                                            0.0,
    9885              :                                            0.0,
    9886              :                                            true,
    9887              :                                            false,
    9888            0 :                                            1.0);
    9889            0 :                 state.dataFans->fans(HeatPump.FanNum)->simulate(state, FirstHVACIteration, _, _);
    9890              :             }
    9891              :         } else {
    9892              :             // pass node information using resulting PLR
    9893        34614 :             if (HeatPump.fanPlace == HVAC::FanPlace::BlowThru) {
    9894              :                 //   simulate fan and DX coil twice to pass PLF (OnOffFanPartLoadFraction) to fan
    9895        26114 :                 state.dataFans->fans(HeatPump.FanNum)->simulate(state, FirstHVACIteration, _, _);
    9896              : 
    9897        26114 :                 VariableSpeedCoils::SimVariableSpeedCoils(state,
    9898              :                                                           HeatPump.DXCoilName,
    9899        26114 :                                                           HeatPump.DXCoilNum,
    9900              :                                                           HVAC::FanOp::Cycling,
    9901              :                                                           compressorOp,
    9902        26114 :                                                           state.dataWaterThermalTanks->hpPartLoadRatio,
    9903              :                                                           SpeedNum,
    9904              :                                                           SpeedRatio,
    9905              :                                                           0.0,
    9906              :                                                           0.0,
    9907              :                                                           1.0);
    9908              : 
    9909        26114 :                 state.dataFans->fans(HeatPump.FanNum)->simulate(state, FirstHVACIteration, _, _);
    9910              : 
    9911        26114 :                 VariableSpeedCoils::SimVariableSpeedCoils(state,
    9912              :                                                           HeatPump.DXCoilName,
    9913        26114 :                                                           HeatPump.DXCoilNum,
    9914              :                                                           HVAC::FanOp::Cycling,
    9915              :                                                           compressorOp,
    9916        26114 :                                                           state.dataWaterThermalTanks->hpPartLoadRatio,
    9917              :                                                           SpeedNum,
    9918              :                                                           SpeedRatio,
    9919              :                                                           0.0,
    9920              :                                                           0.0,
    9921              :                                                           1.0);
    9922              :             } else {
    9923              :                 //   simulate DX coil and fan twice to pass fan power (FanElecPower) to DX coil
    9924         8500 :                 VariableSpeedCoils::SimVariableSpeedCoils(state,
    9925              :                                                           HeatPump.DXCoilName,
    9926         8500 :                                                           HeatPump.DXCoilNum,
    9927              :                                                           HVAC::FanOp::Cycling,
    9928              :                                                           compressorOp,
    9929         8500 :                                                           state.dataWaterThermalTanks->hpPartLoadRatio,
    9930              :                                                           SpeedNum,
    9931              :                                                           SpeedRatio,
    9932              :                                                           0.0,
    9933              :                                                           0.0,
    9934              :                                                           1.0);
    9935              : 
    9936         8500 :                 state.dataFans->fans(HeatPump.FanNum)->simulate(state, FirstHVACIteration, _, _);
    9937              : 
    9938         8500 :                 VariableSpeedCoils::SimVariableSpeedCoils(state,
    9939              :                                                           HeatPump.DXCoilName,
    9940         8500 :                                                           HeatPump.DXCoilNum,
    9941              :                                                           HVAC::FanOp::Cycling,
    9942              :                                                           compressorOp,
    9943         8500 :                                                           state.dataWaterThermalTanks->hpPartLoadRatio,
    9944              :                                                           SpeedNum,
    9945              :                                                           SpeedRatio,
    9946              :                                                           0.0,
    9947              :                                                           0.0,
    9948              :                                                           1.0);
    9949              : 
    9950         8500 :                 state.dataFans->fans(HeatPump.FanNum)->simulate(state, FirstHVACIteration, _, _);
    9951              :             }
    9952              :         }
    9953              :     } else { // single speed
    9954              : 
    9955              :         // pass node information using resulting PLR
    9956       287144 :         if (HeatPump.fanPlace == HVAC::FanPlace::BlowThru) {
    9957              :             //   simulate fan and DX coil twice to pass PLF (OnOffFanPartLoadFraction) to fan
    9958        67992 :             state.dataFans->fans(HeatPump.FanNum)->simulate(state, FirstHVACIteration, _, _);
    9959              : 
    9960       135984 :             DXCoils::SimDXCoil(state,
    9961              :                                HeatPump.DXCoilName,
    9962              :                                compressorOp,
    9963              :                                FirstHVACIteration,
    9964        67992 :                                HeatPump.DXCoilNum,
    9965              :                                HVAC::FanOp::Cycling,
    9966        67992 :                                state.dataWaterThermalTanks->hpPartLoadRatio);
    9967              : 
    9968        67992 :             state.dataFans->fans(HeatPump.FanNum)->simulate(state, FirstHVACIteration, _, _);
    9969              : 
    9970       135984 :             DXCoils::SimDXCoil(state,
    9971              :                                HeatPump.DXCoilName,
    9972              :                                compressorOp,
    9973              :                                FirstHVACIteration,
    9974        67992 :                                HeatPump.DXCoilNum,
    9975              :                                HVAC::FanOp::Cycling,
    9976        67992 :                                state.dataWaterThermalTanks->hpPartLoadRatio);
    9977              :         } else {
    9978              :             //   simulate DX coil and fan twice to pass fan power (FanElecPower) to DX coil
    9979       438304 :             DXCoils::SimDXCoil(state,
    9980              :                                HeatPump.DXCoilName,
    9981              :                                compressorOp,
    9982              :                                FirstHVACIteration,
    9983       219152 :                                HeatPump.DXCoilNum,
    9984              :                                HVAC::FanOp::Cycling,
    9985       219152 :                                state.dataWaterThermalTanks->hpPartLoadRatio);
    9986              : 
    9987       219152 :             state.dataFans->fans(HeatPump.FanNum)->simulate(state, FirstHVACIteration, _, _);
    9988              : 
    9989       438304 :             DXCoils::SimDXCoil(state,
    9990              :                                HeatPump.DXCoilName,
    9991              :                                compressorOp,
    9992              :                                FirstHVACIteration,
    9993       219152 :                                HeatPump.DXCoilNum,
    9994              :                                HVAC::FanOp::Cycling,
    9995       219152 :                                state.dataWaterThermalTanks->hpPartLoadRatio);
    9996              : 
    9997       219152 :             state.dataFans->fans(HeatPump.FanNum)->simulate(state, FirstHVACIteration, _, _);
    9998              :         }
    9999              :     }
   10000              : 
   10001              :     // Call the tank one more time with the final PLR
   10002       326828 :     if (HeatPump.HPWHTankType == DataPlant::PlantEquipmentType::WtrHeaterMixed) {
   10003       126938 :         this->CalcWaterThermalTankMixed(state);
   10004       199890 :     } else if (HeatPump.HPWHTankType == DataPlant::PlantEquipmentType::WtrHeaterStratified) {
   10005       199890 :         this->CalcWaterThermalTankStratified(state);
   10006              :     } else {
   10007            0 :         assert(0);
   10008              :     }
   10009              : 
   10010              :     // set HPWH outlet node equal to the outlet air splitter node conditions if outlet air splitter node exists
   10011       326828 :     if (OutletAirSplitterNode > 0) {
   10012        16038 :         state.dataLoopNodes->Node(HPAirOutletNode) = state.dataLoopNodes->Node(OutletAirSplitterNode);
   10013        16038 :         state.dataLoopNodes->Node(ExhaustAirNode) = state.dataLoopNodes->Node(OutletAirSplitterNode);
   10014              :     }
   10015              : 
   10016              :     // Check schedule to divert air-side cooling to outdoors.
   10017       326828 :     if (HeatPump.outletAirSplitterSched != nullptr) {
   10018        16038 :         Real64 OutletAirSplitterSch = HeatPump.outletAirSplitterSched->getCurrentVal();
   10019        16038 :         state.dataLoopNodes->Node(HPAirOutletNode).MassFlowRate =
   10020        16038 :             state.dataWaterThermalTanks->mdotAir * state.dataWaterThermalTanks->hpPartLoadRatio * (1.0 - OutletAirSplitterSch);
   10021        16038 :         state.dataLoopNodes->Node(ExhaustAirNode).MassFlowRate =
   10022        16038 :             state.dataWaterThermalTanks->mdotAir * state.dataWaterThermalTanks->hpPartLoadRatio * OutletAirSplitterSch;
   10023              :     }
   10024              : 
   10025       326828 :     HeatPump.HeatingPLR = state.dataWaterThermalTanks->hpPartLoadRatio;
   10026       326828 :     HeatPump.OnCycParaFuelRate = HeatPump.OnCycParaLoad * state.dataWaterThermalTanks->hpPartLoadRatio;
   10027       326828 :     HeatPump.OnCycParaFuelEnergy = HeatPump.OnCycParaFuelRate * state.dataHVACGlobal->TimeStepSysSec;
   10028       326828 :     HeatPump.OffCycParaFuelRate = HeatPump.OffCycParaLoad * (1.0 - state.dataWaterThermalTanks->hpPartLoadRatio);
   10029       326828 :     HeatPump.OffCycParaFuelEnergy = HeatPump.OffCycParaFuelRate * state.dataHVACGlobal->TimeStepSysSec;
   10030       326828 :     if (HeatPump.HPWHTankType == DataPlant::PlantEquipmentType::WtrHeaterMixed) {
   10031       126938 :         HeatPump.ControlTempAvg = this->TankTempAvg;
   10032       126938 :         HeatPump.ControlTempFinal = this->TankTemp;
   10033       199890 :     } else if (HeatPump.HPWHTankType == DataPlant::PlantEquipmentType::WtrHeaterStratified) {
   10034       199890 :         HeatPump.ControlTempAvg = this->FindStratifiedTankSensedTemp(state, true);
   10035       199890 :         HeatPump.ControlTempFinal = this->FindStratifiedTankSensedTemp(state);
   10036              :     } else {
   10037            0 :         assert(0);
   10038              :     }
   10039              : 
   10040       326828 :     switch (HeatPump.InletAirConfiguration) {
   10041              : 
   10042              :     //   no sensible capacity to zone for outdoor and scheduled HPWH
   10043       143224 :     case WTTAmbientTemp::OutsideAir:
   10044              :     case WTTAmbientTemp::Schedule: {
   10045       143224 :         HeatPump.HPWaterHeaterSensibleCapacity = 0.0;
   10046       143224 :         HeatPump.HPWaterHeaterLatentCapacity = 0.0;
   10047              : 
   10048              :         //   calculate sensible capacity to zone for inlet air configuration equals Zone Only or Zone And Outdoor Air configurations
   10049       143224 :         break;
   10050              :     }
   10051       183604 :     default:
   10052              : 
   10053       183604 :         Real64 CpAir = Psychrometrics::PsyCpAirFnW(state.dataLoopNodes->Node(HPAirInletNode).HumRat);
   10054              : 
   10055              :         //     add parasitics to zone heat balance if parasitic heat load is to zone otherwise neglect parasitics
   10056       183604 :         if (HeatPump.ParasiticTempIndicator == WTTAmbientTemp::TempZone) {
   10057       125832 :             HeatPump.HPWaterHeaterSensibleCapacity =
   10058       125832 :                 (state.dataLoopNodes->Node(HPAirOutletNode).MassFlowRate * CpAir *
   10059       125832 :                  (state.dataLoopNodes->Node(HPAirOutletNode).Temp - state.dataLoopNodes->Node(HPAirInletNode).Temp)) +
   10060       125832 :                 HeatPump.OnCycParaFuelRate + HeatPump.OffCycParaFuelRate;
   10061              :         } else {
   10062        57772 :             HeatPump.HPWaterHeaterSensibleCapacity =
   10063        57772 :                 state.dataLoopNodes->Node(HPAirOutletNode).MassFlowRate * CpAir *
   10064        57772 :                 (state.dataLoopNodes->Node(HPAirOutletNode).Temp - state.dataLoopNodes->Node(HPAirInletNode).Temp);
   10065              :         }
   10066              : 
   10067       183604 :         HeatPump.HPWaterHeaterLatentCapacity = state.dataLoopNodes->Node(HPAirOutletNode).MassFlowRate *
   10068       183604 :                                                (state.dataLoopNodes->Node(HPAirOutletNode).HumRat - state.dataLoopNodes->Node(HPAirInletNode).HumRat);
   10069       183604 :         break;
   10070              :     }
   10071              : }
   10072              : 
   10073       953359 : void WaterThermalTankData::CalcWaterThermalTank(EnergyPlusData &state)
   10074              : {
   10075       953359 :     switch (this->WaterThermalTankType) {
   10076       345378 :     case DataPlant::PlantEquipmentType::WtrHeaterMixed:
   10077       345378 :         this->CalcWaterThermalTankMixed(state);
   10078       345378 :         break;
   10079       607981 :     case DataPlant::PlantEquipmentType::WtrHeaterStratified:
   10080       607981 :         this->CalcWaterThermalTankStratified(state);
   10081       607981 :         break;
   10082            0 :     default:
   10083            0 :         assert(false);
   10084              :     }
   10085       953359 : }
   10086              : 
   10087       537077 : Real64 WaterThermalTankData::GetHPWHSensedTankTemp(EnergyPlusData &state)
   10088              : {
   10089       537077 :     switch (this->WaterThermalTankType) {
   10090       197018 :     case DataPlant::PlantEquipmentType::WtrHeaterMixed:
   10091       197018 :         return this->TankTemp;
   10092              :         break;
   10093       340059 :     case DataPlant::PlantEquipmentType::WtrHeaterStratified:
   10094       340059 :         return this->FindStratifiedTankSensedTemp(state);
   10095              :         break;
   10096            0 :     default:
   10097            0 :         assert(false);
   10098              :         return 0.0; // silence compiler
   10099              :     }
   10100              : }
   10101              : 
   10102       133725 : void WaterThermalTankData::ConvergeSingleSpeedHPWHCoilAndTank(EnergyPlusData &state, Real64 const partLoadRatio)
   10103              : {
   10104       133725 :     HeatPumpWaterHeaterData &HPWH = state.dataWaterThermalTanks->HPWaterHeater(this->HeatPumpNum);
   10105       133725 :     DXCoils::DXCoilData &Coil = state.dataDXCoils->DXCoil(HPWH.DXCoilNum);
   10106              : 
   10107       133725 :     Real64 PrevTankTemp = this->SourceOutletTemp;
   10108       457710 :     for (int i = 1; i <= 10; ++i) {
   10109              : 
   10110       457710 :         DXCoils::CalcHPWHDXCoil(state, HPWH.DXCoilNum, partLoadRatio);
   10111       457710 :         this->SourceInletTemp = state.dataLoopNodes->Node(HPWH.CondWaterOutletNode).Temp;
   10112              : 
   10113       457710 :         this->CalcWaterThermalTank(state);
   10114       457710 :         state.dataLoopNodes->Node(Coil.WaterInNode).Temp = this->SourceOutletTemp;
   10115              : 
   10116       457710 :         if (std::abs(this->SourceOutletTemp - PrevTankTemp) < HVAC::SmallTempDiff) {
   10117       133725 :             break;
   10118              :         }
   10119              : 
   10120       323985 :         PrevTankTemp = this->SourceOutletTemp;
   10121              :     }
   10122       133725 : }
   10123              : 
   10124       496548 : void WaterThermalTankData::SetVSHPWHFlowRates(EnergyPlusData &state,
   10125              :                                               HeatPumpWaterHeaterData &HPWH, // heat pump coil
   10126              :                                               int const SpeedNum,            // upper speed number
   10127              :                                               Real64 const SpeedRatio,       // interpolation ration between upper and lower speed
   10128              :                                               Real64 const WaterDens,        // tank water density
   10129              :                                               Real64 &MdotWater,             // water flow rate
   10130              :                                               bool const FirstHVACIteration)
   10131              : {
   10132              :     // FUNCTION INFORMATION:
   10133              :     //       AUTHOR         B.Shen, ORNL, 12/2014
   10134              :     //       DATE WRITTEN   May 2005
   10135              :     //       MODIFIED
   10136              :     //       RE-ENGINEERED
   10137              : 
   10138              :     // PURPOSE OF THIS FUNCTION:
   10139              :     //  set water and air flow rates driven by the variable-speed HPWH coil
   10140              :     //  calculate resultant HPWH coil output
   10141              : 
   10142       496548 :     int SpeedLow = SpeedNum - 1;
   10143       496548 :     if (SpeedLow < 1) {
   10144        56165 :         SpeedLow = 1;
   10145              :     }
   10146              : 
   10147       496548 :     int HPWaterInletNode = HPWH.CondWaterInletNode;
   10148       496548 :     int DXCoilAirInletNode = HPWH.DXCoilAirInletNode;
   10149       496548 :     if (HPWH.bIsIHP) {
   10150        19412 :         HPWH.OperatingWaterFlowRate = IntegratedHeatPump::GetWaterVolFlowRateIHP(state, HPWH.DXCoilNum, SpeedNum, SpeedRatio);
   10151        19412 :         state.dataWaterThermalTanks->mdotAir = IntegratedHeatPump::GetAirMassFlowRateIHP(state, HPWH.DXCoilNum, SpeedNum, SpeedRatio, true);
   10152        19412 :         HPWH.OperatingAirFlowRate = IntegratedHeatPump::GetAirVolFlowRateIHP(state, HPWH.DXCoilNum, SpeedNum, SpeedRatio, true);
   10153        19412 :         state.dataLoopNodes->Node(DXCoilAirInletNode).MassFlowRate = state.dataWaterThermalTanks->mdotAir;
   10154        19412 :         state.dataLoopNodes->Node(DXCoilAirInletNode).MassFlowRateMaxAvail = state.dataWaterThermalTanks->mdotAir;
   10155        19412 :         state.dataLoopNodes->Node(DXCoilAirInletNode).MassFlowRateMax = state.dataWaterThermalTanks->mdotAir;
   10156              :     } else {
   10157       477136 :         HPWH.OperatingWaterFlowRate = HPWH.HPWHWaterVolFlowRate(SpeedNum) * SpeedRatio + HPWH.HPWHWaterVolFlowRate(SpeedLow) * (1.0 - SpeedRatio);
   10158       477136 :         HPWH.OperatingAirFlowRate = HPWH.HPWHAirVolFlowRate(SpeedNum) * SpeedRatio + HPWH.HPWHAirVolFlowRate(SpeedLow) * (1.0 - SpeedRatio);
   10159       477136 :         state.dataWaterThermalTanks->mdotAir =
   10160       477136 :             HPWH.HPWHAirMassFlowRate(SpeedNum) * SpeedRatio + HPWH.HPWHAirMassFlowRate(SpeedLow) * (1.0 - SpeedRatio);
   10161              :     }
   10162              : 
   10163       496548 :     MdotWater = HPWH.OperatingWaterFlowRate * WaterDens;
   10164       496548 :     this->SourceMassFlowRate = MdotWater;
   10165              : 
   10166       496548 :     state.dataLoopNodes->Node(DXCoilAirInletNode).MassFlowRate = state.dataWaterThermalTanks->mdotAir;
   10167       496548 :     state.dataLoopNodes->Node(HPWaterInletNode).MassFlowRate = MdotWater;
   10168       496548 :     this->SourceMassFlowRate = MdotWater;
   10169              : 
   10170       496548 :     if (HPWH.InletAirMixerNode > 0) {
   10171        18681 :         state.dataLoopNodes->Node(HPWH.InletAirMixerNode).MassFlowRate = state.dataWaterThermalTanks->mdotAir;
   10172        18681 :         state.dataLoopNodes->Node(HPWH.InletAirMixerNode).MassFlowRateMaxAvail = state.dataWaterThermalTanks->mdotAir;
   10173              :     } else {
   10174       477867 :         if (HPWH.OutsideAirNode == 0) {
   10175        26652 :             state.dataLoopNodes->Node(HPWH.HeatPumpAirInletNode).MassFlowRate = state.dataWaterThermalTanks->mdotAir;
   10176        26652 :             state.dataLoopNodes->Node(HPWH.HeatPumpAirInletNode).MassFlowRateMaxAvail = state.dataWaterThermalTanks->mdotAir;
   10177              :         } else {
   10178       451215 :             state.dataLoopNodes->Node(HPWH.OutsideAirNode).MassFlowRate = state.dataWaterThermalTanks->mdotAir;
   10179       451215 :             state.dataLoopNodes->Node(HPWH.OutsideAirNode).MassFlowRateMaxAvail = state.dataWaterThermalTanks->mdotAir;
   10180              :         }
   10181              :     }
   10182              : 
   10183              :     // put fan component first, regardless placement, to calculate fan power
   10184       496548 :     int FanInNode = state.dataFans->fans(HPWH.FanNum)->inletNodeNum;
   10185              : 
   10186       496548 :     state.dataLoopNodes->Node(FanInNode).MassFlowRate = state.dataWaterThermalTanks->mdotAir;
   10187       496548 :     state.dataLoopNodes->Node(FanInNode).MassFlowRateMaxAvail = state.dataWaterThermalTanks->mdotAir;
   10188       496548 :     state.dataLoopNodes->Node(FanInNode).MassFlowRateMax = state.dataWaterThermalTanks->mdotAir;
   10189       496548 :     if (HPWH.fanType != HVAC::FanType::SystemModel) {
   10190        84846 :         state.dataFans->fans(HPWH.FanNum)->massFlowRateMaxAvail = state.dataWaterThermalTanks->mdotAir;
   10191              :     } // system fan will use the inlet node max avail.
   10192              : 
   10193       496548 :     state.dataFans->fans(HPWH.FanNum)->simulate(state, FirstHVACIteration, _, _);
   10194       496548 : }
   10195              : 
   10196        76295 : Real64 WaterThermalTankData::PLRResidualIterSpeed(EnergyPlusData &state,
   10197              :                                                   Real64 const SpeedRatio, // speed ratio between two speed levels
   10198              :                                                   int const HPNum,
   10199              :                                                   int const SpeedNum,
   10200              :                                                   int const HPWaterInletNode,
   10201              :                                                   int const HPWaterOutletNode,
   10202              :                                                   Real64 const RhoWater,
   10203              :                                                   Real64 const desTankTemp,
   10204              :                                                   TankOperatingMode const mode,
   10205              :                                                   bool const FirstHVACIteration)
   10206              : {
   10207              :     // FUNCTION INFORMATION:
   10208              :     //       AUTHOR         B.Shen, ORNL, 12/2014
   10209              :     //       MODIFIED
   10210              :     //       RE-ENGINEERED
   10211              : 
   10212              :     // PURPOSE OF THIS FUNCTION:
   10213              :     //  Calculates residual function (desired tank temp - actual tank temp), when iterating speed ration between two speed levels
   10214              :     //  HP water heater output depends on the speed ratio which is being varied to zero the residual.
   10215              : 
   10216              :     // METHODOLOGY EMPLOYED:
   10217              :     //  Calls residuals to get tank temperature at the given speed ratio between a lower and an upper speed levels
   10218              :     //  and calculates the residual as defined respectively for DataPlant::PlantEquipmentType::WtrHeaterMixed or
   10219              :     //  DataPlant::PlantEquipmentType::WtrHeaterStratified
   10220              : 
   10221        76295 :     this->Mode = mode;
   10222        76295 :     state.dataWaterThermalTanks->hpPartLoadRatio = 1.0;
   10223        76295 :     Real64 MdotWater = 0.0;
   10224              : 
   10225        76295 :     auto &HPWH = state.dataWaterThermalTanks->HPWaterHeater(HPNum);
   10226              : 
   10227        76295 :     this->SetVSHPWHFlowRates(state, HPWH, SpeedNum, SpeedRatio, RhoWater, MdotWater, FirstHVACIteration);
   10228              : 
   10229        76295 :     if (state.dataWaterThermalTanks->HPWaterHeater(HPNum).bIsIHP) {
   10230           96 :         IntegratedHeatPump::SimIHP(state,
   10231           96 :                                    state.dataWaterThermalTanks->HPWaterHeater(HPNum).DXCoilName,
   10232           96 :                                    state.dataWaterThermalTanks->HPWaterHeater(HPNum).DXCoilNum,
   10233              :                                    HVAC::FanOp::Cycling,
   10234              :                                    HVAC::CompressorOp::On,
   10235           96 :                                    state.dataWaterThermalTanks->hpPartLoadRatio,
   10236              :                                    SpeedNum,
   10237              :                                    SpeedRatio,
   10238              :                                    0.0,
   10239              :                                    0.0,
   10240              :                                    true,
   10241              :                                    false,
   10242          192 :                                    1.0);
   10243              :     } else {
   10244        76199 :         VariableSpeedCoils::SimVariableSpeedCoils(state,
   10245        76199 :                                                   state.dataWaterThermalTanks->HPWaterHeater(HPNum).DXCoilName,
   10246        76199 :                                                   state.dataWaterThermalTanks->HPWaterHeater(HPNum).DXCoilNum,
   10247              :                                                   HVAC::FanOp::Cycling,
   10248              :                                                   HVAC::CompressorOp::On,
   10249        76199 :                                                   state.dataWaterThermalTanks->hpPartLoadRatio,
   10250              :                                                   SpeedNum,
   10251              :                                                   SpeedRatio,
   10252              :                                                   0.0,
   10253              :                                                   0.0,
   10254              :                                                   1.0);
   10255              :     }
   10256              : 
   10257              :     Real64 CondenserDeltaT;
   10258        76295 :     CondenserDeltaT = state.dataLoopNodes->Node(HPWaterOutletNode).Temp - state.dataLoopNodes->Node(HPWaterInletNode).Temp;
   10259              : 
   10260              :     //           move the full load outlet temperature rate to the water heater structure variables
   10261              :     //           (water heaters source inlet node temperature/mdot are set in Init, set it here after DXCoils::CalcHPWHDXCoil has been called)
   10262        76295 :     this->SourceInletTemp = state.dataLoopNodes->Node(HPWaterInletNode).Temp + CondenserDeltaT;
   10263              : 
   10264              :     //           this CALL does not update node temps, must use WaterThermalTank variables
   10265              :     // select tank type
   10266        76295 :     Real64 NewTankTemp = 0.0;
   10267        76295 :     if (state.dataWaterThermalTanks->HPWaterHeater(HPNum).HPWHTankType == DataPlant::PlantEquipmentType::WtrHeaterMixed) {
   10268        25143 :         this->CalcWaterThermalTankMixed(state);
   10269        25143 :         NewTankTemp = this->TankTemp;
   10270        51152 :     } else if (state.dataWaterThermalTanks->HPWaterHeater(HPNum).HPWHTankType == DataPlant::PlantEquipmentType::WtrHeaterStratified) {
   10271        51152 :         this->CalcWaterThermalTankStratified(state);
   10272        51152 :         NewTankTemp = this->FindStratifiedTankSensedTemp(state);
   10273              :     }
   10274              : 
   10275        76295 :     return desTankTemp - NewTankTemp;
   10276              : }
   10277              : 
   10278        55943 : Real64 WaterThermalTankData::PLRResidualHPWH(
   10279              :     EnergyPlusData &state, Real64 const HPPartLoadRatio, Real64 const desTankTemp, TankOperatingMode const mode, Real64 const mDotWater)
   10280              : {
   10281              :     // FUNCTION INFORMATION:
   10282              :     //       AUTHOR         B.Griffith,  Richard Raustad
   10283              :     //       DATE WRITTEN   Jan 2012
   10284              :     //       MODIFIED
   10285              :     //       RE-ENGINEERED  Noel Merket, Oct 2015
   10286              : 
   10287              :     // PURPOSE OF THIS FUNCTION:
   10288              :     //  Calculates residual function (desired tank temp - actual tank temp)
   10289              :     //  HP water heater output depends on the part load ratio which is being varied to zero the residual.
   10290              : 
   10291              :     // METHODOLOGY EMPLOYED:
   10292              :     //  Calls with CalcWaterThermalTankMixed or CalcWaterThermalTankStratified to get tank temperature at the given part load ratio (source water
   10293              :     //  mass flow rate) and calculates the residual as defined above
   10294              : 
   10295        55943 :     HeatPumpWaterHeaterData &HeatPump = state.dataWaterThermalTanks->HPWaterHeater(this->HeatPumpNum);
   10296        55943 :     bool const isVariableSpeed = (HeatPump.NumofSpeed > 0);
   10297        55943 :     this->Mode = mode;
   10298              :     // Apply the PLR
   10299        55943 :     if (this->WaterThermalTankType == DataPlant::PlantEquipmentType::WtrHeaterMixed) {
   10300              :         // For a mixed tank, the PLR is applied to the source mass flow rate.
   10301        21133 :         this->SourceMassFlowRate = mDotWater * HPPartLoadRatio;
   10302        21133 :         this->CalcWaterThermalTankMixed(state);
   10303              :     } else {
   10304        34810 :         assert(this->WaterThermalTankType == DataPlant::PlantEquipmentType::WtrHeaterStratified);
   10305              :         // For a stratified tank, the PLR is applied to the Coil.TotalHeatingEnergyRate
   10306              :         // whether that's a VarSpeedCoil or DXCoils::DXCoil.
   10307              :         // Here we create a pointer to the TotalHeatingEnergyRate for the appropriate coil type.
   10308              :         Real64 *CoilTotalHeatingEnergyRatePtr;
   10309        34810 :         if (isVariableSpeed) {
   10310          621 :             if (HeatPump.bIsIHP) {
   10311            0 :                 CoilTotalHeatingEnergyRatePtr = &state.dataIntegratedHP->IntegratedHeatPumps(HeatPump.DXCoilNum).TotalWaterHeatingRate;
   10312              :             } else {
   10313          621 :                 CoilTotalHeatingEnergyRatePtr = &state.dataVariableSpeedCoils->VarSpeedCoil(HeatPump.DXCoilNum).TotalHeatingEnergyRate;
   10314              :             }
   10315              :         } else {
   10316        34189 :             CoilTotalHeatingEnergyRatePtr = &state.dataDXCoils->DXCoil(HeatPump.DXCoilNum).TotalHeatingEnergyRate;
   10317              :         }
   10318              :         // Copy the value of the total heating energy rate
   10319        34810 :         Real64 const CoilTotalHeatingEnergyRateBackup = *CoilTotalHeatingEnergyRatePtr;
   10320              :         // Apply the PLR
   10321        34810 :         *CoilTotalHeatingEnergyRatePtr *= HPPartLoadRatio;
   10322              :         // Tank Calculation
   10323        34810 :         this->CalcWaterThermalTankStratified(state);
   10324              :         // Restore the original value
   10325        34810 :         *CoilTotalHeatingEnergyRatePtr = CoilTotalHeatingEnergyRateBackup;
   10326              :     }
   10327        55943 :     Real64 NewTankTemp = this->GetHPWHSensedTankTemp(state);
   10328        55943 :     return desTankTemp - NewTankTemp;
   10329              : }
   10330              : 
   10331      1362856 : bool WaterThermalTankData::SourceHeatNeed([[maybe_unused]] EnergyPlusData &state,
   10332              :                                           Real64 const OutletTemp,
   10333              :                                           Real64 const DeadBandTemp,
   10334              :                                           Real64 const SetPointTemp_loc)
   10335              : {
   10336              :     // FUNCTION INFORMATION:
   10337              :     //       AUTHOR         Yueyue Zhou
   10338              :     //       DATE WRITTEN   May 2019
   10339              :     //       MODIFIED       na
   10340              :     //       RE-ENGINEERED  na
   10341              : 
   10342              :     // PURPOSE OF THIS FUNCTION:
   10343              :     // Determine by tank type, tank temperature and control mode if source side flow is needed
   10344              : 
   10345              :     // return value initialization
   10346      1362856 :     bool NeedsHeatOrCool = false;
   10347              : 
   10348      1362856 :     if (!this->IsChilledWaterTank) {
   10349       952840 :         if (this->SourceSideControlMode == SourceSideControl::IndirectHeatPrimarySetpoint) {
   10350       952840 :             if (OutletTemp < DeadBandTemp) {
   10351       143302 :                 NeedsHeatOrCool = true;
   10352       809538 :             } else if ((OutletTemp >= DeadBandTemp) && (OutletTemp < SetPointTemp_loc)) {
   10353              :                 // inside the deadband, use saved mode from water heater calcs
   10354       378433 :                 if (this->SavedMode == TankOperatingMode::Heating) {
   10355        88317 :                     NeedsHeatOrCool = true;
   10356       290116 :                 } else if (this->SavedMode == TankOperatingMode::Floating) {
   10357       290116 :                     NeedsHeatOrCool = false;
   10358              :                 }
   10359              : 
   10360       431105 :             } else if (OutletTemp >= SetPointTemp_loc) {
   10361       431105 :                 NeedsHeatOrCool = false;
   10362              :             }
   10363            0 :         } else if (this->SourceSideControlMode == SourceSideControl::IndirectHeatAltSetpoint) {
   10364              :             // get alternate setpoint
   10365            0 :             Real64 const AltSetpointTemp = this->sourceSideAltSetpointSched->getCurrentVal();
   10366            0 :             Real64 const AltDeadBandTemp = AltSetpointTemp - this->DeadBandDeltaTemp;
   10367            0 :             if (OutletTemp < AltDeadBandTemp) {
   10368            0 :                 NeedsHeatOrCool = true;
   10369            0 :             } else if ((OutletTemp >= AltDeadBandTemp) && (OutletTemp < AltSetpointTemp)) {
   10370              :                 // inside the deadband, use saved mode from water heater calcs
   10371            0 :                 if (this->SavedMode == TankOperatingMode::Heating) {
   10372            0 :                     NeedsHeatOrCool = true;
   10373            0 :                 } else if (this->SavedMode == TankOperatingMode::Floating) {
   10374            0 :                     NeedsHeatOrCool = false;
   10375              :                 }
   10376              : 
   10377            0 :             } else if (OutletTemp >= AltSetpointTemp) {
   10378            0 :                 NeedsHeatOrCool = false;
   10379              :             }
   10380            0 :         } else if (this->SourceSideControlMode == SourceSideControl::StorageTank) {
   10381            0 :             if (OutletTemp < this->TankTempLimit) {
   10382            0 :                 NeedsHeatOrCool = true;
   10383              :             } else {
   10384            0 :                 NeedsHeatOrCool = false;
   10385              :             }
   10386              :         }
   10387              :     } else { // is a chilled water tank so flip logic
   10388       410016 :         if (OutletTemp > DeadBandTemp) {
   10389        10312 :             NeedsHeatOrCool = true;
   10390       399704 :         } else if ((OutletTemp <= DeadBandTemp) && (OutletTemp > SetPointTemp_loc)) {
   10391              :             // inside the deadband, use saved mode from water thermal tank calcs (modes only for mixed)
   10392       290876 :             if (this->WaterThermalTankType == DataPlant::PlantEquipmentType::ChilledWaterTankMixed) {
   10393       263303 :                 if (this->SavedMode == TankOperatingMode::Cooling) {
   10394        49160 :                     NeedsHeatOrCool = true;
   10395       214143 :                 } else if (this->SavedMode == TankOperatingMode::Floating) {
   10396       214143 :                     NeedsHeatOrCool = false;
   10397              :                 }
   10398        27573 :             } else if (this->WaterThermalTankType == DataPlant::PlantEquipmentType::ChilledWaterTankStratified) {
   10399        27573 :                 NeedsHeatOrCool = true;
   10400              :             }
   10401              : 
   10402       108828 :         } else if (OutletTemp <= SetPointTemp_loc) {
   10403       108828 :             NeedsHeatOrCool = false;
   10404              :         }
   10405              :     }
   10406      1362856 :     return NeedsHeatOrCool;
   10407              : }
   10408              : 
   10409      7735682 : Real64 WaterThermalTankData::PlantMassFlowRatesFunc(EnergyPlusData &state,
   10410              :                                                     int const InNodeNum,
   10411              :                                                     bool const FirstHVACIteration,
   10412              :                                                     WaterHeaterSide const WaterThermalTankSide,
   10413              :                                                     const DataPlant::LoopSideLocation PlantLoopSide,
   10414              :                                                     [[maybe_unused]] bool const PlumbedInSeries,
   10415              :                                                     DataBranchAirLoopPlant::ControlType const BranchControlType,
   10416              :                                                     Real64 const OutletTemp,
   10417              :                                                     Real64 const DeadBandTemp,
   10418              :                                                     Real64 const SetPointTemp_loc)
   10419              : {
   10420              : 
   10421              :     // FUNCTION INFORMATION:
   10422              :     //       AUTHOR         Brent Griffith
   10423              :     //       DATE WRITTEN   October 2007
   10424              :     //       MODIFIED       na
   10425              :     //       RE-ENGINEERED  na
   10426              : 
   10427              :     // PURPOSE OF THIS FUNCTION:
   10428              :     // collect routines for setting flow rates for Water heaters
   10429              :     // with plant connections.
   10430              : 
   10431              :     // determine current mode.  there are three possible
   10432              :     //  1.  passing thru what was given to inlet node
   10433              :     //  2.  potentially making a flow request
   10434              :     //  3.  throttling flow in response to Plant's restrictions (MassFlowRateMaxAvail)
   10435              :     // init default mode changed to Unassigned
   10436      7735682 :     FlowMode CurrentMode = FlowMode::Invalid; // default
   10437              : 
   10438      7735682 :     if (PlantLoopSide == DataPlant::LoopSideLocation::Invalid) {
   10439       438002 :         CurrentMode = FlowMode::PassingFlowThru;
   10440      7297680 :     } else if (PlantLoopSide == DataPlant::LoopSideLocation::Supply) {
   10441              :         // If FlowLock is False (0), the tank sets the plant loop mdot
   10442              :         // If FlowLock is True (1),  the new resolved plant loop mdot is used
   10443      6746468 :         if (this->UseCurrentFlowLock == DataPlant::FlowLock::Unlocked) {
   10444      2819155 :             CurrentMode = FlowMode::PassingFlowThru;
   10445      2819155 :             if ((this->UseSideLoadRequested > 0.0) && (WaterThermalTankSide == WaterHeaterSide::Use)) {
   10446      2143609 :                 CurrentMode = FlowMode::MaybeRequestingFlow;
   10447              :             }
   10448              :         } else {
   10449      3927313 :             CurrentMode = FlowMode::PassingFlowThru;
   10450              :         }
   10451      6746468 :         if (WaterThermalTankSide == WaterHeaterSide::Source) {
   10452       811644 :             CurrentMode = FlowMode::MaybeRequestingFlow;
   10453              :         }
   10454       551212 :     } else if (PlantLoopSide == DataPlant::LoopSideLocation::Demand) {
   10455              : 
   10456              :         //  2.  Might be Requesting Flow.
   10457       551212 :         if (FirstHVACIteration) {
   10458       275364 :             if (BranchControlType == DataBranchAirLoopPlant::ControlType::Bypass) {
   10459            0 :                 CurrentMode = FlowMode::PassingFlowThru;
   10460              :             } else {
   10461       275364 :                 CurrentMode = FlowMode::MaybeRequestingFlow;
   10462              :             }
   10463              :         } else {
   10464       275848 :             if (BranchControlType == DataBranchAirLoopPlant::ControlType::Bypass) {
   10465            0 :                 CurrentMode = FlowMode::PassingFlowThru;
   10466              :             } else {
   10467       275848 :                 CurrentMode = FlowMode::ThrottlingFlow;
   10468              :             }
   10469              :         }
   10470              :     }
   10471              : 
   10472              :     // evaluate Availability schedule,
   10473      7735682 :     bool ScheduledAvail = true;
   10474      7735682 :     if (WaterThermalTankSide == WaterHeaterSide::Use) {
   10475      5934824 :         if (this->useSideAvailSched->getCurrentVal() == 0.0) {
   10476            0 :             ScheduledAvail = false;
   10477              :         }
   10478      1800858 :     } else if (WaterThermalTankSide == WaterHeaterSide::Source) {
   10479      1800858 :         if (this->sourceSideAvailSched->getCurrentVal() == 0.0) {
   10480        59744 :             ScheduledAvail = false;
   10481              :         }
   10482              :     }
   10483              : 
   10484              :     // now act based on current mode
   10485      7735682 :     Real64 FlowResult = 0.0;
   10486      7735682 :     switch (CurrentMode) {
   10487              : 
   10488      4229217 :     case FlowMode::PassingFlowThru: {
   10489      4229217 :         if (!ScheduledAvail) {
   10490            0 :             FlowResult = 0.0;
   10491              :         } else {
   10492      4229217 :             FlowResult = state.dataLoopNodes->Node(InNodeNum).MassFlowRate;
   10493              :         }
   10494              : 
   10495      4229217 :         break;
   10496              :     }
   10497       275848 :     case FlowMode::ThrottlingFlow: {
   10498              :         // first determine what mass flow would be if it is to requested
   10499       275848 :         Real64 MassFlowRequest = 0.0;
   10500       275848 :         if (!ScheduledAvail) {
   10501        29872 :             MassFlowRequest = 0.0;
   10502              :         } else {
   10503       245976 :             if (WaterThermalTankSide == WaterHeaterSide::Use) {
   10504            0 :                 MassFlowRequest = this->PlantUseMassFlowRateMax;
   10505       245976 :             } else if (WaterThermalTankSide == WaterHeaterSide::Source) {
   10506       245976 :                 MassFlowRequest = this->PlantSourceMassFlowRateMax;
   10507              :             } else {
   10508            0 :                 assert(false);
   10509              :             }
   10510              :         }
   10511              : 
   10512              :         // next determine if tank temperature is such that source side flow might be requested
   10513       275848 :         bool NeedsHeatOrCool = this->SourceHeatNeed(state, OutletTemp, DeadBandTemp, SetPointTemp_loc);
   10514              : 
   10515       275848 :         if (MassFlowRequest > 0.0) {
   10516       245976 :             if (WaterThermalTankSide == WaterHeaterSide::Use) {
   10517            0 :                 FlowResult = MassFlowRequest;
   10518       245976 :             } else if (WaterThermalTankSide == WaterHeaterSide::Source) {
   10519       245976 :                 if (NeedsHeatOrCool) {
   10520        61996 :                     FlowResult = MassFlowRequest;
   10521              :                 } else {
   10522       183980 :                     FlowResult = 0.0;
   10523              :                 }
   10524              :             } else {
   10525            0 :                 assert(false);
   10526              :             }
   10527              :         } else {
   10528        29872 :             FlowResult = 0.0;
   10529              :         }
   10530              : 
   10531              :         // now throttle against MassFlowRateMaxAvail, MassFlowRateMinAvail, MassFlowRateMax, and MassFlowRateMin
   10532              :         // see notes about reverse dd compliance (specifically 5ZoneWaterSystems file)
   10533       275848 :         FlowResult = max(state.dataLoopNodes->Node(InNodeNum).MassFlowRateMinAvail, FlowResult); // okay for compliance (reverse dd)
   10534       275848 :         FlowResult = max(state.dataLoopNodes->Node(InNodeNum).MassFlowRateMin, FlowResult);      // okay for compliance (reverse dd)
   10535       275848 :         FlowResult = min(state.dataLoopNodes->Node(InNodeNum).MassFlowRateMaxAvail, FlowResult);
   10536              :         //=> following might take out of reverse dd compliance
   10537       275848 :         FlowResult = min(state.dataLoopNodes->Node(InNodeNum).MassFlowRateMax, FlowResult);
   10538              : 
   10539       275848 :         break;
   10540              :     }
   10541      3230617 :     case FlowMode::MaybeRequestingFlow: {
   10542              : 
   10543              :         // first determine what mass flow would be if it is to requested
   10544      3230617 :         Real64 MassFlowRequest = 0.0;
   10545      3230617 :         if (!ScheduledAvail) {
   10546        29872 :             MassFlowRequest = 0.0;
   10547              :         } else {
   10548      3200745 :             if (WaterThermalTankSide == WaterHeaterSide::Use) {
   10549      2143609 :                 if ((this->IsChilledWaterTank) && (this->UseSideLoadRequested > 0.0)) {
   10550        27591 :                     MassFlowRequest = this->PlantUseMassFlowRateMax;
   10551      2116018 :                 } else if ((this->IsChilledWaterTank) && (this->UseSideLoadRequested == 0.0)) {
   10552            0 :                     MassFlowRequest = 0.0;
   10553              :                 } else {
   10554      2116018 :                     MassFlowRequest = this->PlantUseMassFlowRateMax;
   10555              :                 }
   10556              : 
   10557      1057136 :             } else if (WaterThermalTankSide == WaterHeaterSide::Source) {
   10558      1057136 :                 MassFlowRequest = this->PlantSourceMassFlowRateMax;
   10559              :             }
   10560              :         }
   10561              : 
   10562      3230617 :         if (WaterThermalTankSide == WaterHeaterSide::Source) { // temperature dependent controls for indirect heating/cooling
   10563      1087008 :             bool NeedsHeatOrCool = this->SourceHeatNeed(state, OutletTemp, DeadBandTemp, SetPointTemp_loc);
   10564      1087008 :             if (MassFlowRequest > 0.0) {
   10565      1057115 :                 if (NeedsHeatOrCool) {
   10566       237847 :                     FlowResult = MassFlowRequest;
   10567              :                 } else {
   10568       819268 :                     FlowResult = 0.0;
   10569              :                 }
   10570              :             } else {
   10571        29893 :                 FlowResult = 0.0;
   10572              :             }
   10573              :         } else { // end source side, begin use side
   10574      2143609 :             if (MassFlowRequest > 0.0) {
   10575      2143609 :                 FlowResult = MassFlowRequest;
   10576              :             } else {
   10577            0 :                 FlowResult = 0.0;
   10578              :             }
   10579              :         }
   10580      3230617 :         break;
   10581              :     }
   10582            0 :     default:
   10583            0 :         break;
   10584              :     }
   10585              : 
   10586      7735682 :     if (FlowResult < HVAC::VerySmallMassFlow) {
   10587      2410436 :         FlowResult = 0.0; // Catch underflow problems
   10588              :     }
   10589              : 
   10590      7735682 :     return FlowResult;
   10591              : }
   10592              : 
   10593          992 : void WaterThermalTankData::MinePlantStructForInfo(EnergyPlusData &state)
   10594              : {
   10595              : 
   10596              :     // SUBROUTINE INFORMATION:
   10597              :     //       AUTHOR         Brent Griffith
   10598              :     //       DATE WRITTEN   October 2007
   10599              :     //       MODIFIED       na
   10600              :     //       RE-ENGINEERED  na
   10601              : 
   10602              :     // PURPOSE OF THIS SUBROUTINE:
   10603              :     // get information from plant loop data structure
   10604              :     // check what we can learn from plant structure against user inputs
   10605              : 
   10606          992 :     bool ErrorsFound = false;
   10607              : 
   10608          992 :     if (allocated(state.dataPlnt->PlantLoop) && this->UseSidePlantLoc.loopNum > 0) {
   10609              : 
   10610              :         // check plant structure for useful data.
   10611              : 
   10612          919 :         int PlantLoopNum = this->UseSidePlantLoc.loopNum;
   10613          919 :         DataPlant::LoopSideLocation LoopSideNum = this->UseSidePlantLoc.loopSideNum;
   10614              : 
   10615          919 :         if ((this->UseDesignVolFlowRateWasAutoSized) && (this->UseSidePlantSizNum == 0)) {
   10616            0 :             ShowSevereError(state,
   10617            0 :                             format("Water heater = {} for autosizing Use side flow rate, did not find Sizing:Plant object {}",
   10618            0 :                                    this->Name,
   10619            0 :                                    state.dataPlnt->PlantLoop(PlantLoopNum).Name));
   10620            0 :             ErrorsFound = true;
   10621              :         }
   10622              :         // Is this wh Use side plumbed in series (default) or are there other branches in parallel?
   10623          919 :         if (state.dataPlnt->PlantLoop(PlantLoopNum).LoopSide(LoopSideNum).Splitter.Exists) {
   10624          919 :             if (any_eq(state.dataPlnt->PlantLoop(PlantLoopNum).LoopSide(LoopSideNum).Splitter.NodeNumOut,
   10625          919 :                        this->UseInletNode)) { // this wh is on the splitter
   10626          884 :                 if (state.dataPlnt->PlantLoop(PlantLoopNum).LoopSide(LoopSideNum).Splitter.TotalOutletNodes > 1) {
   10627          808 :                     this->UseSideSeries = false;
   10628              :                 }
   10629              :             }
   10630              :         }
   10631              :     }
   10632              : 
   10633          992 :     if (allocated(state.dataPlnt->PlantLoop) && this->SrcSidePlantLoc.loopNum > 0) {
   10634              :         // was user's input correct for plant loop name?
   10635          231 :         if ((this->SourceDesignVolFlowRateWasAutoSized) && (this->SourceSidePlantSizNum == 0) && (this->DesuperheaterNum == 0) &&
   10636            0 :             (this->HeatPumpNum == 0)) {
   10637            0 :             ShowSevereError(state,
   10638            0 :                             format("Water heater = {}for autosizing Source side flow rate, did not find Sizing:Plant object {}",
   10639            0 :                                    this->Name,
   10640            0 :                                    state.dataPlnt->PlantLoop(this->SrcSidePlantLoc.loopNum).Name));
   10641            0 :             ErrorsFound = true;
   10642              :         }
   10643              :         // Is this wh Source side plumbed in series (default) or are there other branches in parallel?
   10644          231 :         if (state.dataPlnt->PlantLoop(this->SrcSidePlantLoc.loopNum).LoopSide(this->SrcSidePlantLoc.loopSideNum).Splitter.Exists) {
   10645          231 :             if (any_eq(state.dataPlnt->PlantLoop(this->SrcSidePlantLoc.loopNum).LoopSide(this->SrcSidePlantLoc.loopSideNum).Splitter.NodeNumOut,
   10646          231 :                        this->SourceInletNode)) { // this wh is on the splitter
   10647          231 :                 if (state.dataPlnt->PlantLoop(this->SrcSidePlantLoc.loopNum).LoopSide(this->SrcSidePlantLoc.loopSideNum).Splitter.TotalOutletNodes >
   10648              :                     1) {
   10649           77 :                     this->SourceSideSeries = false;
   10650              :                 }
   10651              :             }
   10652              :         }
   10653              :     }
   10654              : 
   10655          992 :     if (ErrorsFound) {
   10656            0 :         ShowFatalError(state, "Preceding water heater input errors cause program termination");
   10657              :     }
   10658          992 : }
   10659              : 
   10660          786 : void WaterThermalTankData::SizeSupplySidePlantConnections(EnergyPlusData &state, const int loopNum)
   10661              : {
   10662              : 
   10663              :     // SUBROUTINE INFORMATION:
   10664              :     //       AUTHOR         Brent Griffith
   10665              :     //       DATE WRITTEN   October 2007
   10666              :     //       MODIFIED       na
   10667              :     //       RE-ENGINEERED  na
   10668              : 
   10669              :     // PURPOSE OF THIS SUBROUTINE:
   10670              :     // This subroutine is for sizing water heater plant connection flow rates
   10671              :     // on the supply that have not been specified in the input.
   10672              : 
   10673              :     // METHODOLOGY EMPLOYED:
   10674              :     // This routine is called later in the simulation than the sizing routine for the demand side
   10675              :     //  because the simulation needs to be further along before the needed data are available.
   10676              :     // For water heaters sides on Supply LoopSide, obtains hot water flow rate from the plant sizing array
   10677              :     //  (adapted approach from boiler sizing routines)
   10678              : 
   10679              :     static constexpr std::string_view RoutineName("SizeSupplySidePlantConnections");
   10680              : 
   10681          786 :     auto &PlantSizData = state.dataSize->PlantSizData;
   10682              : 
   10683          786 :     Real64 tmpUseDesignVolFlowRate = this->UseDesignVolFlowRate;
   10684          786 :     Real64 tmpSourceDesignVolFlowRate = this->SourceDesignVolFlowRate;
   10685              : 
   10686          786 :     if ((this->UseInletNode > 0) && (loopNum == this->UseSidePlantLoc.loopNum)) {
   10687          681 :         if (this->UseDesignVolFlowRateWasAutoSized) {
   10688          651 :             int PltSizNum = this->UseSidePlantSizNum;
   10689          651 :             if (PltSizNum > 0) { // we have a Plant Sizing Object
   10690          651 :                 if (this->UseSidePlantLoc.loopSideNum == DataPlant::LoopSideLocation::Supply) {
   10691          651 :                     if (PlantSizData(PltSizNum).DesVolFlowRate >= HVAC::SmallWaterVolFlow) {
   10692          524 :                         if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
   10693          143 :                             this->UseDesignVolFlowRate = PlantSizData(PltSizNum).DesVolFlowRate;
   10694              :                         } else {
   10695          381 :                             tmpUseDesignVolFlowRate = PlantSizData(PltSizNum).DesVolFlowRate;
   10696              :                         }
   10697              :                     } else {
   10698          127 :                         if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
   10699            0 :                             this->UseDesignVolFlowRate = 0.0;
   10700              :                         } else {
   10701          127 :                             tmpUseDesignVolFlowRate = 0.0;
   10702              :                         }
   10703              :                     }
   10704          651 :                     if (state.dataPlnt->PlantFinalSizesOkayToReport) {
   10705          127 :                         BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Use Side Design Flow Rate [m3/s]", this->UseDesignVolFlowRate);
   10706              :                     }
   10707          651 :                     if (state.dataPlnt->PlantFirstSizesOkayToReport) {
   10708            8 :                         BaseSizer::reportSizerOutput(
   10709              :                             state, this->Type, this->Name, "Initial Use Side Design Flow Rate [m3/s]", this->UseDesignVolFlowRate);
   10710              :                     }
   10711          651 :                     if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
   10712          143 :                         PlantUtilities::RegisterPlantCompDesignFlow(state, this->UseInletNode, this->UseDesignVolFlowRate);
   10713              :                     } else {
   10714          508 :                         PlantUtilities::RegisterPlantCompDesignFlow(state, this->UseInletNode, tmpUseDesignVolFlowRate);
   10715              :                     }
   10716              : 
   10717              :                     Real64 rho =
   10718          651 :                         state.dataPlnt->PlantLoop(this->UseSidePlantLoc.loopNum).glycol->getDensity(state, Constant::InitConvTemp, RoutineName);
   10719          651 :                     if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
   10720          143 :                         this->PlantUseMassFlowRateMax = this->UseDesignVolFlowRate * rho;
   10721              :                     } else {
   10722          508 :                         this->PlantUseMassFlowRateMax = tmpUseDesignVolFlowRate * rho;
   10723              :                     }
   10724              :                 }
   10725              :             } else {
   10726              :                 // do nothing
   10727              :             } // plant sizing object
   10728              :         } else {
   10729           30 :             PlantUtilities::RegisterPlantCompDesignFlow(state, this->UseInletNode, this->UseDesignVolFlowRate);
   10730              :             Real64 rho;
   10731           30 :             if (this->UseSidePlantLoc.loopNum > 0) {
   10732           30 :                 rho = state.dataPlnt->PlantLoop(this->UseSidePlantLoc.loopNum).glycol->getDensity(state, Constant::InitConvTemp, RoutineName);
   10733              :             } else {
   10734            0 :                 rho = this->water->getDensity(state, Constant::InitConvTemp, RoutineName);
   10735              :             }
   10736              : 
   10737           30 :             this->PlantUseMassFlowRateMax = this->UseDesignVolFlowRate * rho;
   10738              : 
   10739              :         } // autosizing needed.
   10740              :     } // connected to plant
   10741              : 
   10742          786 :     if ((this->SourceInletNode > 0) && (loopNum == this->SrcSidePlantLoc.loopNum)) {
   10743          105 :         if (this->SourceDesignVolFlowRateWasAutoSized) {
   10744           55 :             int PltSizNum = this->SourceSidePlantSizNum;
   10745           55 :             if (PltSizNum > 0) {
   10746           55 :                 if (this->SrcSidePlantLoc.loopSideNum == DataPlant::LoopSideLocation::Supply) {
   10747           25 :                     if (PlantSizData(PltSizNum).DesVolFlowRate >= HVAC::SmallWaterVolFlow) {
   10748           18 :                         if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
   10749            5 :                             this->SourceDesignVolFlowRate = PlantSizData(PltSizNum).DesVolFlowRate;
   10750              :                         } else {
   10751           13 :                             tmpSourceDesignVolFlowRate = PlantSizData(PltSizNum).DesVolFlowRate;
   10752              :                         }
   10753              :                     } else {
   10754            7 :                         if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
   10755            0 :                             this->SourceDesignVolFlowRate = 0.0;
   10756              :                         } else {
   10757            7 :                             tmpSourceDesignVolFlowRate = 0.0;
   10758              :                         }
   10759              :                     }
   10760           25 :                     if (state.dataPlnt->PlantFinalSizesOkayToReport) {
   10761            5 :                         BaseSizer::reportSizerOutput(
   10762              :                             state, this->Type, this->Name, "Source Side Design Flow Rate [m3/s]", this->SourceDesignVolFlowRate);
   10763              :                     }
   10764           25 :                     if (state.dataPlnt->PlantFirstSizesOkayToReport) {
   10765            0 :                         BaseSizer::reportSizerOutput(
   10766              :                             state, this->Type, this->Name, "Initial Source Side Design Flow Rate [m3/s]", this->SourceDesignVolFlowRate);
   10767              :                     }
   10768           25 :                     if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
   10769            5 :                         PlantUtilities::RegisterPlantCompDesignFlow(state, this->SourceInletNode, this->SourceDesignVolFlowRate);
   10770              :                     } else {
   10771           20 :                         PlantUtilities::RegisterPlantCompDesignFlow(state, this->SourceInletNode, tmpSourceDesignVolFlowRate);
   10772              :                     }
   10773              :                     Real64 rho =
   10774           25 :                         state.dataPlnt->PlantLoop(this->SrcSidePlantLoc.loopNum).glycol->getDensity(state, Constant::InitConvTemp, RoutineName);
   10775           25 :                     if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
   10776            5 :                         this->PlantSourceMassFlowRateMax = this->SourceDesignVolFlowRate * rho;
   10777              :                     } else {
   10778           20 :                         this->PlantSourceMassFlowRateMax = tmpSourceDesignVolFlowRate * rho;
   10779              :                     }
   10780              :                 } // plant loop allocation
   10781              :             } else {
   10782              :                 // do nothing
   10783              :             } // plant sizing object
   10784              :         } else {
   10785           50 :             if (this->SrcSidePlantLoc.loopSideNum == DataPlant::LoopSideLocation::Supply) {
   10786           45 :                 PlantUtilities::RegisterPlantCompDesignFlow(state, this->SourceInletNode, this->SourceDesignVolFlowRate);
   10787              :                 Real64 rho;
   10788           45 :                 if (this->SrcSidePlantLoc.loopNum > 0) {
   10789           45 :                     rho = state.dataPlnt->PlantLoop(this->SrcSidePlantLoc.loopNum).glycol->getDensity(state, Constant::InitConvTemp, RoutineName);
   10790              :                 } else {
   10791            0 :                     rho = this->water->getDensity(state, Constant::InitConvTemp, RoutineName);
   10792              :                 }
   10793           45 :                 this->PlantSourceMassFlowRateMax = this->SourceDesignVolFlowRate * rho;
   10794              :             }
   10795              :         } // autosizing needed.
   10796              :     } // connected to plant
   10797          786 : }
   10798              : 
   10799          786 : void WaterThermalTankData::SizeTankForDemandSide(EnergyPlusData &state)
   10800              : {
   10801              : 
   10802              :     // SUBROUTINE INFORMATION:
   10803              :     //       AUTHOR         Brent Griffith
   10804              :     //       DATE WRITTEN   February 2008
   10805              :     //       MODIFIED       na
   10806              :     //       RE-ENGINEERED  na
   10807              : 
   10808              :     // PURPOSE OF THIS SUBROUTINE:
   10809              :     // This subroutine is for sizing water heater tank volume and heater
   10810              :     //  as best we can at this point in simulation. (prior to demand side
   10811              :     //  sizing that needs volume).
   10812              : 
   10813              :     // METHODOLOGY EMPLOYED:
   10814              :     //  depending on the sizing design mode...
   10815              : 
   10816              :     // REFERENCES:
   10817              :     // BA benchmark report for residential design mode
   10818              : 
   10819              :     // SUBROUTINE PARAMETER DEFINITIONS:
   10820              :     static constexpr std::string_view RoutineName("SizeTankForDemandSide");
   10821          786 :     Real64 constexpr GalTocubicMeters(0.0037854);
   10822          786 :     Real64 constexpr kBtuPerHrToWatts(293.1);
   10823              : 
   10824          786 :     Real64 Tstart = 14.44;
   10825          786 :     Real64 Tfinish = 57.22;
   10826              : 
   10827          786 :     Real64 tmpTankVolume = this->Volume;
   10828          786 :     Real64 tmpMaxCapacity = this->MaxCapacity;
   10829              : 
   10830          786 :     switch (this->Sizing.DesignMode) {
   10831              : 
   10832          771 :     case SizingMode::Invalid:
   10833              :     case SizingMode::PeakDraw: {
   10834              : 
   10835          771 :         break;
   10836              :     }
   10837           15 :     case SizingMode::ResidentialMin: {
   10838              : 
   10839              :         // assume can propagate rules for gas to other fuels.
   10840           15 :         bool FuelTypeIsLikeGas = false;
   10841           15 :         switch (this->FuelType) {
   10842            0 :         case Constant::eFuel::NaturalGas:
   10843              :         case Constant::eFuel::Diesel:
   10844              :         case Constant::eFuel::Gasoline:
   10845              :         case Constant::eFuel::Coal:
   10846              :         case Constant::eFuel::FuelOilNo1:
   10847              :         case Constant::eFuel::FuelOilNo2:
   10848              :         case Constant::eFuel::Propane:
   10849              :         case Constant::eFuel::OtherFuel1:
   10850              :         case Constant::eFuel::OtherFuel2:
   10851              :         case Constant::eFuel::DistrictHeatingWater:
   10852              :         case Constant::eFuel::DistrictHeatingSteam:
   10853            0 :             FuelTypeIsLikeGas = true;
   10854            0 :             break;
   10855           15 :         default: // FuelTypeIsLikeGas stays false
   10856           15 :             break;
   10857              :         }
   10858              : 
   10859           15 :         if (this->Sizing.NumberOfBedrooms == 1) {
   10860            0 :             if (this->FuelType == Constant::eFuel::Electricity) {
   10861            0 :                 if (this->VolumeWasAutoSized) {
   10862            0 :                     tmpTankVolume = 20.0 * GalTocubicMeters;
   10863              :                 }
   10864            0 :                 if (this->MaxCapacityWasAutoSized) {
   10865            0 :                     tmpMaxCapacity = 2.5 * 1000.0; // 2.5 kW
   10866              :                 }
   10867            0 :             } else if (FuelTypeIsLikeGas) {
   10868            0 :                 if (this->VolumeWasAutoSized) {
   10869            0 :                     tmpTankVolume = 20.0 * GalTocubicMeters;
   10870              :                 }
   10871            0 :                 if (this->MaxCapacityWasAutoSized) {
   10872            0 :                     tmpMaxCapacity = 27.0 * kBtuPerHrToWatts; // 27kBtu/hr
   10873              :                 }
   10874              :             }
   10875              : 
   10876           15 :         } else if (this->Sizing.NumberOfBedrooms == 2) {
   10877            0 :             if (this->Sizing.NumberOfBathrooms <= 1.5) {
   10878            0 :                 if (this->FuelType == Constant::eFuel::Electricity) {
   10879            0 :                     if (this->VolumeWasAutoSized) {
   10880            0 :                         tmpTankVolume = 30.0 * GalTocubicMeters;
   10881              :                     }
   10882            0 :                     if (this->MaxCapacityWasAutoSized) {
   10883            0 :                         tmpMaxCapacity = 3.5 * 1000.0; // 3.5 kW
   10884              :                     }
   10885            0 :                 } else if (FuelTypeIsLikeGas) {
   10886            0 :                     if (this->VolumeWasAutoSized) {
   10887            0 :                         tmpTankVolume = 30.0 * GalTocubicMeters;
   10888              :                     }
   10889            0 :                     if (this->MaxCapacityWasAutoSized) {
   10890            0 :                         tmpMaxCapacity = 36.0 * kBtuPerHrToWatts; // 36 kBtu/hr
   10891              :                     }
   10892              :                 }
   10893            0 :             } else if ((this->Sizing.NumberOfBathrooms > 1.5) && (this->Sizing.NumberOfBathrooms < 3.0)) {
   10894            0 :                 if (this->FuelType == Constant::eFuel::Electricity) {
   10895            0 :                     if (this->VolumeWasAutoSized) {
   10896            0 :                         tmpTankVolume = 40.0 * GalTocubicMeters;
   10897              :                     }
   10898            0 :                     if (this->MaxCapacityWasAutoSized) {
   10899            0 :                         tmpMaxCapacity = 4.5 * 1000.0; // 4.5 kW
   10900              :                     }
   10901            0 :                 } else if (FuelTypeIsLikeGas) {
   10902            0 :                     if (this->VolumeWasAutoSized) {
   10903            0 :                         tmpTankVolume = 30.0 * GalTocubicMeters;
   10904              :                     }
   10905            0 :                     if (this->MaxCapacityWasAutoSized) {
   10906            0 :                         tmpMaxCapacity = 36.0 * kBtuPerHrToWatts; // 36 kBtu/hr
   10907              :                     }
   10908              :                 }
   10909            0 :             } else if (this->Sizing.NumberOfBathrooms >= 3.0) {
   10910            0 :                 if (this->FuelType == Constant::eFuel::Electricity) {
   10911            0 :                     if (this->VolumeWasAutoSized) {
   10912            0 :                         tmpTankVolume = 50.0 * GalTocubicMeters;
   10913              :                     }
   10914            0 :                     if (this->MaxCapacityWasAutoSized) {
   10915            0 :                         tmpMaxCapacity = 5.5 * 1000.0; // 5.5 kW
   10916              :                     }
   10917            0 :                 } else if (FuelTypeIsLikeGas) {
   10918            0 :                     if (this->VolumeWasAutoSized) {
   10919            0 :                         tmpTankVolume = 40.0 * GalTocubicMeters;
   10920              :                     }
   10921            0 :                     if (this->MaxCapacityWasAutoSized) {
   10922            0 :                         tmpMaxCapacity = 36.0 * kBtuPerHrToWatts; // 36 kBtu/hr
   10923              :                     }
   10924              :                 }
   10925              :             }
   10926           15 :         } else if (this->Sizing.NumberOfBedrooms == 3) {
   10927           15 :             if (this->Sizing.NumberOfBathrooms <= 1.5) {
   10928            0 :                 if (this->FuelType == Constant::eFuel::Electricity) {
   10929            0 :                     if (this->VolumeWasAutoSized) {
   10930            0 :                         tmpTankVolume = 40.0 * GalTocubicMeters;
   10931              :                     }
   10932            0 :                     if (this->MaxCapacityWasAutoSized) {
   10933            0 :                         tmpMaxCapacity = 4.5 * 1000.0; // 4.5 kW
   10934              :                     }
   10935            0 :                 } else if (FuelTypeIsLikeGas) {
   10936            0 :                     if (this->VolumeWasAutoSized) {
   10937            0 :                         tmpTankVolume = 30.0 * GalTocubicMeters;
   10938              :                     }
   10939            0 :                     if (this->MaxCapacityWasAutoSized) {
   10940            0 :                         tmpMaxCapacity = 36.0 * kBtuPerHrToWatts; // 36 kBtu/hr
   10941              :                     }
   10942              :                 }
   10943           15 :             } else if ((this->Sizing.NumberOfBathrooms > 1.5) && (this->Sizing.NumberOfBathrooms < 3.0)) {
   10944            0 :                 if (this->FuelType == Constant::eFuel::Electricity) {
   10945            0 :                     if (this->VolumeWasAutoSized) {
   10946            0 :                         tmpTankVolume = 50.0 * GalTocubicMeters;
   10947              :                     }
   10948            0 :                     if (this->MaxCapacityWasAutoSized) {
   10949            0 :                         tmpMaxCapacity = 5.5 * 1000.0; // 5.5 kW
   10950              :                     }
   10951            0 :                 } else if (FuelTypeIsLikeGas) {
   10952            0 :                     if (this->VolumeWasAutoSized) {
   10953            0 :                         tmpTankVolume = 40.0 * GalTocubicMeters;
   10954              :                     }
   10955            0 :                     if (this->MaxCapacityWasAutoSized) {
   10956            0 :                         tmpMaxCapacity = 36.0 * kBtuPerHrToWatts; // 36 kBtu/hr
   10957              :                     }
   10958              :                 }
   10959           15 :             } else if (this->Sizing.NumberOfBathrooms >= 3.0) {
   10960           15 :                 if (this->FuelType == Constant::eFuel::Electricity) {
   10961           15 :                     if (this->VolumeWasAutoSized) {
   10962            0 :                         tmpTankVolume = 50.0 * GalTocubicMeters;
   10963              :                     }
   10964           15 :                     if (this->MaxCapacityWasAutoSized) {
   10965           15 :                         tmpMaxCapacity = 5.5 * 1000.0; // 5.5 kW
   10966              :                     }
   10967            0 :                 } else if (FuelTypeIsLikeGas) {
   10968            0 :                     if (this->VolumeWasAutoSized) {
   10969            0 :                         tmpTankVolume = 40.0 * GalTocubicMeters;
   10970              :                     }
   10971            0 :                     if (this->MaxCapacityWasAutoSized) {
   10972            0 :                         tmpMaxCapacity = 38.0 * kBtuPerHrToWatts; // 38 kBtu/hr
   10973              :                     }
   10974              :                 }
   10975              :             }
   10976            0 :         } else if (this->Sizing.NumberOfBedrooms == 4) {
   10977            0 :             if (this->Sizing.NumberOfBathrooms <= 1.5) {
   10978            0 :                 if (this->FuelType == Constant::eFuel::Electricity) {
   10979            0 :                     if (this->VolumeWasAutoSized) {
   10980            0 :                         tmpTankVolume = 50.0 * GalTocubicMeters;
   10981              :                     }
   10982            0 :                     if (this->MaxCapacityWasAutoSized) {
   10983            0 :                         tmpMaxCapacity = 5.5 * 1000.0; // 5.5 kW
   10984              :                     }
   10985            0 :                 } else if (FuelTypeIsLikeGas) {
   10986            0 :                     if (this->VolumeWasAutoSized) {
   10987            0 :                         tmpTankVolume = 40.0 * GalTocubicMeters;
   10988              :                     }
   10989            0 :                     if (this->MaxCapacityWasAutoSized) {
   10990            0 :                         tmpMaxCapacity = 36.0 * kBtuPerHrToWatts; // 36 kBtu/hr
   10991              :                     }
   10992              :                 }
   10993            0 :             } else if ((this->Sizing.NumberOfBathrooms > 1.5) && (this->Sizing.NumberOfBathrooms < 3.0)) {
   10994            0 :                 if (this->FuelType == Constant::eFuel::Electricity) {
   10995            0 :                     if (this->VolumeWasAutoSized) {
   10996            0 :                         tmpTankVolume = 50.0 * GalTocubicMeters;
   10997              :                     }
   10998            0 :                     if (this->MaxCapacityWasAutoSized) {
   10999            0 :                         tmpMaxCapacity = 5.5 * 1000.0; // 5.5 kW
   11000              :                     }
   11001            0 :                 } else if (FuelTypeIsLikeGas) {
   11002            0 :                     if (this->VolumeWasAutoSized) {
   11003            0 :                         tmpTankVolume = 40.0 * GalTocubicMeters;
   11004              :                     }
   11005            0 :                     if (this->MaxCapacityWasAutoSized) {
   11006            0 :                         tmpMaxCapacity = 38.0 * kBtuPerHrToWatts; // 38 kBtu/hr
   11007              :                     }
   11008              :                 }
   11009            0 :             } else if (this->Sizing.NumberOfBathrooms >= 3.0) {
   11010            0 :                 if (this->FuelType == Constant::eFuel::Electricity) {
   11011            0 :                     if (this->VolumeWasAutoSized) {
   11012            0 :                         tmpTankVolume = 66.0 * GalTocubicMeters;
   11013              :                     }
   11014            0 :                     if (this->MaxCapacityWasAutoSized) {
   11015            0 :                         tmpMaxCapacity = 5.5 * 1000.0; // 5.5 kW
   11016              :                     }
   11017            0 :                 } else if (FuelTypeIsLikeGas) {
   11018            0 :                     if (this->VolumeWasAutoSized) {
   11019            0 :                         tmpTankVolume = 50.0 * GalTocubicMeters;
   11020              :                     }
   11021            0 :                     if (this->MaxCapacityWasAutoSized) {
   11022            0 :                         tmpMaxCapacity = 38.0 * kBtuPerHrToWatts; // 38 kBtu/hr
   11023              :                     }
   11024              :                 }
   11025              :             }
   11026            0 :         } else if (this->Sizing.NumberOfBedrooms == 5) {
   11027            0 :             if (this->FuelType == Constant::eFuel::Electricity) {
   11028            0 :                 if (this->VolumeWasAutoSized) {
   11029            0 :                     tmpTankVolume = 66.0 * GalTocubicMeters;
   11030              :                 }
   11031            0 :                 if (this->MaxCapacityWasAutoSized) {
   11032            0 :                     tmpMaxCapacity = 5.5 * 1000.0; // 5.5 kW
   11033              :                 }
   11034            0 :             } else if (FuelTypeIsLikeGas) {
   11035            0 :                 if (this->VolumeWasAutoSized) {
   11036            0 :                     tmpTankVolume = 50.0 * GalTocubicMeters;
   11037              :                 }
   11038            0 :                 if (this->MaxCapacityWasAutoSized) {
   11039            0 :                     tmpMaxCapacity = 47.0 * kBtuPerHrToWatts; // 47 kBtu/hr
   11040              :                 }
   11041              :             }
   11042            0 :         } else if (this->Sizing.NumberOfBedrooms >= 6) {
   11043            0 :             if (this->FuelType == Constant::eFuel::Electricity) {
   11044            0 :                 if (this->VolumeWasAutoSized) {
   11045            0 :                     tmpTankVolume = 66.0 * GalTocubicMeters;
   11046              :                 }
   11047            0 :                 if (this->MaxCapacityWasAutoSized) {
   11048            0 :                     tmpMaxCapacity = 5.5 * 1000.0; // 5.5 kW
   11049              :                 }
   11050            0 :             } else if (FuelTypeIsLikeGas) {
   11051            0 :                 if (this->VolumeWasAutoSized) {
   11052            0 :                     tmpTankVolume = 50.0 * GalTocubicMeters;
   11053              :                 }
   11054            0 :                 if (this->MaxCapacityWasAutoSized) {
   11055            0 :                     tmpMaxCapacity = 50.0 * kBtuPerHrToWatts; // 50 kBtu/hr
   11056              :                 }
   11057              :             }
   11058              :         }
   11059              : 
   11060           15 :         if (this->VolumeWasAutoSized && state.dataPlnt->PlantFirstSizesOkayToFinalize) {
   11061            0 :             this->Volume = tmpTankVolume;
   11062            0 :             if (state.dataPlnt->PlantFinalSizesOkayToReport) {
   11063            0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Tank Volume [m3]", this->Volume);
   11064              :             }
   11065            0 :             if (state.dataPlnt->PlantFirstSizesOkayToReport) {
   11066            0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Initial Tank Volume [m3]", this->Volume);
   11067              :             }
   11068              :         }
   11069           15 :         if (this->MaxCapacityWasAutoSized && state.dataPlnt->PlantFirstSizesOkayToFinalize) {
   11070            3 :             this->MaxCapacity = tmpMaxCapacity;
   11071            3 :             if (state.dataPlnt->PlantFinalSizesOkayToReport) {
   11072            3 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Maximum Heater Capacity [W]", this->MaxCapacity);
   11073              :             }
   11074            3 :             if (state.dataPlnt->PlantFirstSizesOkayToReport) {
   11075            0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Initial Maximum Heater Capacity [W]", this->MaxCapacity);
   11076              :             }
   11077              :         }
   11078           15 :         break;
   11079              :     }
   11080            0 :     case SizingMode::PerPerson: {
   11081              :         // how to get number of people?
   11082              : 
   11083              :         // MJW TODO: this won't compile now: Real64 SumPeopleAllZones = sum(state.dataHeatBal->Zone, &DataHeatBalance::ZoneData::TotOccupants);
   11084            0 :         Real64 SumPeopleAllZones = 0.0;
   11085            0 :         for (auto const &thisZone : state.dataHeatBal->Zone) {
   11086            0 :             SumPeopleAllZones += thisZone.TotOccupants;
   11087            0 :         }
   11088            0 :         if (this->VolumeWasAutoSized) {
   11089            0 :             tmpTankVolume = this->Sizing.TankCapacityPerPerson * SumPeopleAllZones;
   11090              :         }
   11091              : 
   11092            0 :         if (this->MaxCapacityWasAutoSized) {
   11093              :             Real64 rho;
   11094              :             Real64 Cp;
   11095            0 :             if (this->UseSidePlantLoc.loopNum > 0) {
   11096            0 :                 rho = state.dataPlnt->PlantLoop(this->UseSidePlantLoc.loopNum).glycol->getDensity(state, ((Tfinish + Tstart) / 2.0), RoutineName);
   11097            0 :                 Cp = state.dataPlnt->PlantLoop(this->UseSidePlantLoc.loopNum).glycol->getSpecificHeat(state, ((Tfinish + Tstart) / 2.0), RoutineName);
   11098              :             } else {
   11099            0 :                 rho = this->water->getDensity(state, ((Tfinish + Tstart) / 2.0), RoutineName);
   11100            0 :                 Cp = this->water->getSpecificHeat(state, ((Tfinish + Tstart) / 2.0), RoutineName);
   11101              :             }
   11102              : 
   11103            0 :             tmpMaxCapacity = SumPeopleAllZones * this->Sizing.RecoveryCapacityPerPerson * (Tfinish - Tstart) * (1.0 / Constant::rSecsInHour) * rho *
   11104              :                              Cp; // m3/hr/person | delta T  in K | 1 hr/ 3600 s | kg/m3 | J/Kg/k
   11105              :         }
   11106              : 
   11107            0 :         if (this->VolumeWasAutoSized && state.dataPlnt->PlantFirstSizesOkayToFinalize) {
   11108            0 :             this->Volume = tmpTankVolume;
   11109            0 :             if (state.dataPlnt->PlantFinalSizesOkayToReport) {
   11110            0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Tank Volume [m3]", this->Volume);
   11111              :             }
   11112            0 :             if (state.dataPlnt->PlantFirstSizesOkayToReport) {
   11113            0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Initial Tank Volume [m3]", this->Volume);
   11114              :             }
   11115              :         }
   11116            0 :         if (this->MaxCapacityWasAutoSized && state.dataPlnt->PlantFirstSizesOkayToFinalize) {
   11117            0 :             this->MaxCapacity = tmpMaxCapacity;
   11118            0 :             if (state.dataPlnt->PlantFinalSizesOkayToReport) {
   11119            0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Maximum Heater Capacity [W]", this->MaxCapacity);
   11120              :             }
   11121            0 :             if (state.dataPlnt->PlantFirstSizesOkayToReport) {
   11122            0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Initial Maximum Heater Capacity [W]", this->MaxCapacity);
   11123              :             }
   11124              :         }
   11125            0 :         break;
   11126              :     }
   11127            0 :     case SizingMode::PerFloorArea: {
   11128              : 
   11129              :         // MJW TODO: this won't compile now: Real64 SumFloorAreaAllZones = sum(state.dataHeatBal->Zone, &DataHeatBalance::ZoneData::FloorArea);
   11130            0 :         Real64 SumFloorAreaAllZones = 0.0;
   11131            0 :         for (auto const &thisZone : state.dataHeatBal->Zone) {
   11132            0 :             SumFloorAreaAllZones += thisZone.FloorArea;
   11133            0 :         }
   11134            0 :         if (this->VolumeWasAutoSized) {
   11135            0 :             tmpTankVolume = this->Sizing.TankCapacityPerArea * SumFloorAreaAllZones;
   11136              :         }
   11137            0 :         if (this->MaxCapacityWasAutoSized) {
   11138              :             Real64 rho;
   11139              :             Real64 Cp;
   11140            0 :             if (this->UseSidePlantLoc.loopNum > 0) {
   11141            0 :                 rho = state.dataPlnt->PlantLoop(this->UseSidePlantLoc.loopNum).glycol->getDensity(state, ((Tfinish + Tstart) / 2.0), RoutineName);
   11142            0 :                 Cp = state.dataPlnt->PlantLoop(this->UseSidePlantLoc.loopNum).glycol->getSpecificHeat(state, ((Tfinish + Tstart) / 2.0), RoutineName);
   11143              :             } else {
   11144            0 :                 rho = this->water->getDensity(state, ((Tfinish + Tstart) / 2.0), RoutineName);
   11145            0 :                 Cp = this->water->getSpecificHeat(state, ((Tfinish + Tstart) / 2.0), RoutineName);
   11146              :             }
   11147            0 :             tmpMaxCapacity = SumFloorAreaAllZones * this->Sizing.RecoveryCapacityPerArea * (Tfinish - Tstart) * (1.0 / Constant::rSecsInHour) * rho *
   11148              :                              Cp; // m2 | m3/hr/m2 | delta T  in K | 1 hr/ 3600 s | kg/m3 | J/Kg/k
   11149              :         }
   11150            0 :         if (this->VolumeWasAutoSized && state.dataPlnt->PlantFirstSizesOkayToFinalize) {
   11151            0 :             this->Volume = tmpTankVolume;
   11152            0 :             if (state.dataPlnt->PlantFinalSizesOkayToReport) {
   11153            0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Tank Volume [m3]", this->Volume);
   11154              :             }
   11155            0 :             if (state.dataPlnt->PlantFirstSizesOkayToReport) {
   11156            0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Initial Tank Volume [m3]", this->Volume);
   11157              :             }
   11158              :         }
   11159            0 :         if (this->MaxCapacityWasAutoSized && state.dataPlnt->PlantFirstSizesOkayToFinalize) {
   11160            0 :             this->MaxCapacity = tmpMaxCapacity;
   11161            0 :             if (state.dataPlnt->PlantFinalSizesOkayToReport) {
   11162            0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Maximum Heater Capacity [W]", this->MaxCapacity);
   11163              :             }
   11164            0 :             if (state.dataPlnt->PlantFirstSizesOkayToReport) {
   11165            0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Initial Maximum Heater Capacity [W]", this->MaxCapacity);
   11166              :             }
   11167              :         }
   11168            0 :         break;
   11169              :     }
   11170            0 :     case SizingMode::PerUnit: {
   11171              : 
   11172            0 :         if (this->VolumeWasAutoSized) {
   11173            0 :             tmpTankVolume = this->Sizing.TankCapacityPerUnit * this->Sizing.NumberOfUnits;
   11174              :         }
   11175              : 
   11176            0 :         if (this->MaxCapacityWasAutoSized) {
   11177              :             Real64 rho;
   11178              :             Real64 Cp;
   11179            0 :             if (this->UseSidePlantLoc.loopNum > 0) {
   11180            0 :                 rho = state.dataPlnt->PlantLoop(this->UseSidePlantLoc.loopNum).glycol->getDensity(state, ((Tfinish + Tstart) / 2.0), RoutineName);
   11181            0 :                 Cp = state.dataPlnt->PlantLoop(this->UseSidePlantLoc.loopNum).glycol->getSpecificHeat(state, ((Tfinish + Tstart) / 2.0), RoutineName);
   11182              :             } else {
   11183            0 :                 rho = this->water->getDensity(state, ((Tfinish + Tstart) / 2.0), RoutineName);
   11184            0 :                 Cp = this->water->getSpecificHeat(state, ((Tfinish + Tstart) / 2.0), RoutineName);
   11185              :             }
   11186            0 :             tmpMaxCapacity = this->Sizing.NumberOfUnits * this->Sizing.RecoveryCapacityPerUnit * (Tfinish - Tstart) * (1.0 / Constant::rSecsInHour) *
   11187              :                              rho * Cp; // m3/hr/ea | delta T  in K | 1 hr/ 3600 s | kg/m3 | J/Kg/k
   11188              :         }
   11189              : 
   11190            0 :         if (this->VolumeWasAutoSized && state.dataPlnt->PlantFirstSizesOkayToFinalize) {
   11191            0 :             this->Volume = tmpTankVolume;
   11192            0 :             if (state.dataPlnt->PlantFinalSizesOkayToReport) {
   11193            0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Tank Volume [m3]", this->Volume);
   11194              :             }
   11195            0 :             if (state.dataPlnt->PlantFirstSizesOkayToReport) {
   11196            0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Initial Tank Volume [m3]", this->Volume);
   11197              :             }
   11198              :         }
   11199            0 :         if (this->MaxCapacityWasAutoSized && state.dataPlnt->PlantFirstSizesOkayToFinalize) {
   11200            0 :             this->MaxCapacity = tmpMaxCapacity;
   11201            0 :             if (state.dataPlnt->PlantFinalSizesOkayToReport) {
   11202            0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Maximum Heater Capacity [W]", this->MaxCapacity);
   11203              :             }
   11204            0 :             if (state.dataPlnt->PlantFirstSizesOkayToReport) {
   11205            0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Initial Maximum Heater Capacity [W]", this->MaxCapacity);
   11206              :             }
   11207              :         }
   11208            0 :         break;
   11209              :     }
   11210            0 :     case SizingMode::PerSolarColArea: {
   11211            0 :         break;
   11212              :     }
   11213            0 :     default:
   11214            0 :         break;
   11215              :     }
   11216              : 
   11217          786 :     if (this->MaxCapacityWasAutoSized) {
   11218           15 :         this->setBackupElementCapacity(state);
   11219              :     }
   11220              : 
   11221              :     // if stratified, might set height.
   11222          786 :     if ((this->VolumeWasAutoSized) && (this->WaterThermalTankType == DataPlant::PlantEquipmentType::WtrHeaterStratified) &&
   11223            0 :         state.dataPlnt->PlantFirstSizesOkayToFinalize) { // might set height
   11224            0 :         if ((this->HeightWasAutoSized) && (!this->VolumeWasAutoSized)) {
   11225            0 :             this->Height = std::pow((4.0 * this->Volume * pow_2(this->Sizing.HeightAspectRatio)) / Constant::Pi, 0.3333333333333333);
   11226            0 :             if (state.dataPlnt->PlantFinalSizesOkayToReport) {
   11227            0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Tank Height [m]", this->Height);
   11228              :             }
   11229            0 :             if (state.dataPlnt->PlantFirstSizesOkayToReport) {
   11230            0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Initial Tank Height [m]", this->Height);
   11231              :             }
   11232              :             // check if Constant::AutoCalculate() Use outlet and source inlet are still set to autosize by earlier
   11233            0 :             if (this->UseOutletHeightWasAutoSized) {
   11234            0 :                 this->UseOutletHeight = this->Height;
   11235              :             }
   11236            0 :             if (this->SourceInletHeightWasAutoSized) {
   11237            0 :                 this->SourceInletHeight = this->Height;
   11238              :             }
   11239              :         }
   11240              :     }
   11241          786 : }
   11242              : 
   11243          786 : void WaterThermalTankData::SizeTankForSupplySide(EnergyPlusData &state)
   11244              : {
   11245              : 
   11246              :     // SUBROUTINE INFORMATION:
   11247              :     //       AUTHOR         Brent Griffith
   11248              :     //       DATE WRITTEN   February 2008
   11249              :     //       MODIFIED       na
   11250              :     //       RE-ENGINEERED  na
   11251              : 
   11252              :     // PURPOSE OF THIS SUBROUTINE:
   11253              :     // This subroutine is for sizing water heater tank volume and heater
   11254              :     //   at a later point in the simulation when more of the plant is ready.
   11255              : 
   11256              :     // METHODOLOGY EMPLOYED:
   11257              :     //  depending on the sizing design mode...
   11258              : 
   11259              :     // REFERENCES:
   11260              :     // BA benchmark report for residential design mode
   11261              : 
   11262              :     static constexpr std::string_view RoutineName("SizeTankForSupplySide");
   11263              : 
   11264          786 :     Real64 tmpTankVolume = this->Volume;
   11265          786 :     Real64 tmpMaxCapacity = this->MaxCapacity;
   11266              : 
   11267          786 :     if (this->Sizing.DesignMode == SizingMode::PeakDraw) {
   11268           30 :         if (this->VolumeWasAutoSized) {
   11269           20 :             tmpTankVolume = this->Sizing.TankDrawTime * this->UseDesignVolFlowRate * Constant::rSecsInHour; // hours | m3/s | (3600 s/1 hour)
   11270              :         }
   11271           30 :         if (this->VolumeWasAutoSized && state.dataPlnt->PlantFirstSizesOkayToFinalize) {
   11272            4 :             this->Volume = tmpTankVolume;
   11273            4 :             if (state.dataPlnt->PlantFinalSizesOkayToReport) {
   11274            4 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Tank Volume [m3]", this->Volume);
   11275              :             }
   11276            4 :             if (state.dataPlnt->PlantFirstSizesOkayToReport) {
   11277            0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Initial Tank Volume [m3]", this->Volume);
   11278              :             }
   11279              :         }
   11280           30 :         if (this->MaxCapacityWasAutoSized) {
   11281            0 :             if (this->Sizing.RecoveryTime > 0.0) {
   11282            0 :                 Real64 rho = 0.0;
   11283            0 :                 Real64 Cp = 0.0;
   11284            0 :                 constexpr Real64 Tstart = 14.44;
   11285            0 :                 constexpr Real64 Tfinish = 57.22;
   11286              : 
   11287            0 :                 if (this->SrcSidePlantLoc.loopNum > 0) {
   11288            0 :                     rho = state.dataPlnt->PlantLoop(this->SrcSidePlantLoc.loopNum).glycol->getDensity(state, ((Tfinish + Tstart) / 2.0), RoutineName);
   11289            0 :                     Cp = state.dataPlnt->PlantLoop(this->SrcSidePlantLoc.loopNum)
   11290            0 :                              .glycol->getSpecificHeat(state, ((Tfinish + Tstart) / 2.0), RoutineName);
   11291              :                 } else {
   11292            0 :                     rho = this->water->getDensity(state, ((Tfinish + Tstart) / 2.0), RoutineName);
   11293            0 :                     Cp = this->water->getSpecificHeat(state, ((Tfinish + Tstart) / 2.0), RoutineName);
   11294              :                 }
   11295            0 :                 tmpMaxCapacity = (this->Volume * rho * Cp * (Tfinish - Tstart)) /
   11296            0 :                                  (this->Sizing.RecoveryTime * Constant::rSecsInHour); // m3 | kg/m3 | J/Kg/K | K | seconds
   11297              :             } else {
   11298            0 :                 ShowFatalError(
   11299            0 :                     state, format("{}: Tank=\"{}\", requested sizing for max capacity but entered Recovery Time is zero.", RoutineName, this->Name));
   11300              :             }
   11301              :         }
   11302              : 
   11303           30 :         if (this->MaxCapacityWasAutoSized && state.dataPlnt->PlantFirstSizesOkayToFinalize) {
   11304            0 :             this->MaxCapacity = tmpMaxCapacity;
   11305            0 :             if (state.dataPlnt->PlantFinalSizesOkayToReport) {
   11306            0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Maximum Heater Capacity [W]", this->MaxCapacity);
   11307              :             }
   11308            0 :             if (state.dataPlnt->PlantFirstSizesOkayToReport) {
   11309            0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Initial Maximum Heater Capacity [W]", this->MaxCapacity);
   11310              :             }
   11311              :         }
   11312          756 :     } else if (this->Sizing.DesignMode == SizingMode::PerSolarColArea) {
   11313              : 
   11314            0 :         this->Sizing.TotalSolarCollectorArea = 0.0;
   11315              : 
   11316            0 :         for (int CollectorNum = 1; CollectorNum <= state.dataSolarCollectors->NumOfCollectors; ++CollectorNum) {
   11317            0 :             auto const &collector = state.dataSolarCollectors->Collector(CollectorNum);
   11318            0 :             this->Sizing.TotalSolarCollectorArea += state.dataSurface->Surface(collector.Surface).Area;
   11319              :         }
   11320              : 
   11321            0 :         for (int CollectorNum = 1; CollectorNum <= state.dataPhotovoltaicThermalCollector->NumPVT; ++CollectorNum) {
   11322            0 :             auto const &collector = state.dataPhotovoltaicThermalCollector->PVT(CollectorNum);
   11323            0 :             this->Sizing.TotalSolarCollectorArea += collector.AreaCol;
   11324              :         }
   11325              : 
   11326            0 :         if (this->VolumeWasAutoSized) {
   11327            0 :             if (this->Sizing.TotalSolarCollectorArea > 0) {
   11328            0 :                 tmpTankVolume = this->Sizing.TotalSolarCollectorArea * this->Sizing.TankCapacityPerCollectorArea;
   11329              :             } else {
   11330            0 :                 ShowFatalError(state,
   11331            0 :                                format("{}: Tank=\"{}\", requested sizing for volume with PerSolarCollectorArea but total found "
   11332              :                                       "area of Collectors is zero.",
   11333              :                                       RoutineName,
   11334            0 :                                       this->Name));
   11335              :             }
   11336              :         }
   11337            0 :         if (this->MaxCapacityWasAutoSized) {
   11338            0 :             tmpMaxCapacity = 0.0;
   11339              :         }
   11340            0 :         if (this->VolumeWasAutoSized && state.dataPlnt->PlantFirstSizesOkayToFinalize) {
   11341            0 :             this->Volume = tmpTankVolume;
   11342            0 :             if (state.dataPlnt->PlantFinalSizesOkayToReport) {
   11343            0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Tank Volume [m3]", this->Volume);
   11344              :             }
   11345            0 :             if (state.dataPlnt->PlantFirstSizesOkayToReport) {
   11346            0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Initial Tank Volume [m3]", this->Volume);
   11347              :             }
   11348              :         }
   11349            0 :         if (this->MaxCapacityWasAutoSized && state.dataPlnt->PlantFirstSizesOkayToFinalize) {
   11350            0 :             this->MaxCapacity = tmpMaxCapacity;
   11351            0 :             if (state.dataPlnt->PlantFinalSizesOkayToReport) {
   11352            0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Maximum Heater Capacity [W]", this->MaxCapacity);
   11353              :             }
   11354            0 :             if (state.dataPlnt->PlantFirstSizesOkayToReport) {
   11355            0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Initial Maximum Heater Capacity [W]", this->MaxCapacity);
   11356              :             }
   11357              :         }
   11358              :     }
   11359              : 
   11360          786 :     if (this->MaxCapacityWasAutoSized) {
   11361           15 :         this->setBackupElementCapacity(state);
   11362              :     }
   11363              : 
   11364          786 :     if ((this->VolumeWasAutoSized) && (this->WaterThermalTankType == DataPlant::PlantEquipmentType::WtrHeaterStratified) &&
   11365            0 :         state.dataPlnt->PlantFirstSizesOkayToFinalize) { // might set height
   11366            0 :         if ((this->HeightWasAutoSized) && (!this->VolumeWasAutoSized)) {
   11367            0 :             this->Height = std::pow((4.0 * this->Volume * pow_2(this->Sizing.HeightAspectRatio)) / Constant::Pi, 0.3333333333333333);
   11368            0 :             if (state.dataPlnt->PlantFinalSizesOkayToReport) {
   11369            0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Tank Height [m]", this->Height);
   11370              :             }
   11371            0 :             if (state.dataPlnt->PlantFirstSizesOkayToReport) {
   11372            0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Initial Tank Height [m]", this->Height);
   11373              :             }
   11374              :         }
   11375              :     }
   11376          786 : }
   11377              : 
   11378          786 : void WaterThermalTankData::SizeDemandSidePlantConnections(EnergyPlusData &state)
   11379              : {
   11380              : 
   11381              :     // SUBROUTINE INFORMATION:
   11382              :     //       AUTHOR         Brent Griffith
   11383              :     //       DATE WRITTEN   October 2007
   11384              :     //       MODIFIED       na
   11385              :     //       RE-ENGINEERED  na
   11386              : 
   11387              :     // PURPOSE OF THIS SUBROUTINE:
   11388              :     // This subroutine is for sizing water heater plant connection flow rates
   11389              :     // on the demand side that have not been specified in the input.
   11390              : 
   11391              :     // METHODOLOGY EMPLOYED:
   11392              :     // For water heater sides on the Demand side, hot water flow rates are modeled entirely from user input data
   11393              :     // because the plant loop is not yet set up nor is plant sizing info populated.
   11394              :     // sizing is done by calculating an initial
   11395              :     //  recovery rate that if continued would reheat tank in user specified amount of time.
   11396              :     //  initial and final tank temperatures are 14.44 and reheat to 57.22 (values from CalcStandardRatings routine)
   11397              : 
   11398              :     static constexpr std::string_view RoutineName("SizeDemandSidePlantConnections");
   11399              : 
   11400          786 :     auto &PlantSizData = state.dataSize->PlantSizData;
   11401              : 
   11402          786 :     Real64 tankRecoverhours = this->SizingRecoveryTime;
   11403          786 :     bool ErrorsFound = false;
   11404          786 :     Real64 tmpUseDesignVolFlowRate = this->UseDesignVolFlowRate;
   11405          786 :     Real64 tmpSourceDesignVolFlowRate = this->SourceDesignVolFlowRate;
   11406              : 
   11407              :     Real64 Tstart;
   11408              :     Real64 Tfinish;
   11409          786 :     if (!this->IsChilledWaterTank) {
   11410          736 :         Tstart = 14.44;
   11411          736 :         Tfinish = 57.22;
   11412              :     } else {
   11413           50 :         Tstart = 14.44;
   11414           50 :         Tfinish = 9.0;
   11415              :     }
   11416              : 
   11417              :     // determine tank volume to use for sizing.
   11418          786 :     Real64 TankVolume = this->Volume;
   11419          786 :     if (this->VolumeWasAutoSized) {
   11420           20 :         TankVolume = this->Sizing.NominalVolForSizingDemandSideFlow;
   11421              :     }
   11422              : 
   11423          786 :     if (this->UseInletNode > 0) {
   11424          786 :         if (this->UseDesignVolFlowRateWasAutoSized) {
   11425          726 :             int PltSizNum = this->UseSidePlantSizNum;
   11426          726 :             if (PltSizNum > 0) { // we have a Plant Sizing Object
   11427          726 :                 if (this->UseSidePlantLoc.loopSideNum == DataPlant::LoopSideLocation::Demand) {
   11428              :                     // probably shouldn't come here as Use side is unlikley to be on demand side (?)
   11429              :                     // but going to treat component with symetry so if connections are reversed it'll still work
   11430              :                     // choose a flow rate that will allow the entire volume of the tank to go from 14.44 to 57.22 C
   11431              :                     // in user specified hours.
   11432              :                     //  using the plant inlet design temp for sizing.
   11433            0 :                     Real64 Tpdesign = PlantSizData(PltSizNum).ExitTemp;
   11434            0 :                     Real64 eff = this->UseEffectiveness;
   11435            0 :                     if ((Tpdesign >= 58.0) && (!this->IsChilledWaterTank)) {
   11436            0 :                         if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
   11437            0 :                             this->UseDesignVolFlowRate = -1.0 * (TankVolume / (tankRecoverhours * Constant::rSecsInHour * eff)) *
   11438            0 :                                                          std::log((Tpdesign - Tfinish) / (Tpdesign - Tstart));
   11439              :                         } else {
   11440            0 :                             tmpUseDesignVolFlowRate = -1.0 * (TankVolume / (tankRecoverhours * Constant::rSecsInHour * eff)) *
   11441            0 :                                                       std::log((Tpdesign - Tfinish) / (Tpdesign - Tstart));
   11442              :                         }
   11443            0 :                     } else if ((Tpdesign <= 8.0) && (this->IsChilledWaterTank)) {
   11444            0 :                         if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
   11445            0 :                             this->UseDesignVolFlowRate = -1.0 * (TankVolume / (tankRecoverhours * Constant::rSecsInHour * eff)) *
   11446            0 :                                                          std::log((Tpdesign - Tfinish) / (Tpdesign - Tstart));
   11447              :                         } else {
   11448            0 :                             tmpUseDesignVolFlowRate = -1.0 * (TankVolume / (tankRecoverhours * Constant::rSecsInHour * eff)) *
   11449            0 :                                                       std::log((Tpdesign - Tfinish) / (Tpdesign - Tstart));
   11450              :                         }
   11451              :                     } else {
   11452            0 :                         if (!this->IsChilledWaterTank) {
   11453              :                             // plant sizing object design temperature is set too low throw warning.
   11454            0 :                             ShowSevereError(state,
   11455              :                                             "Autosizing of Use side water heater design flow rate requires Sizing:Plant object to have an exit "
   11456              :                                             "temperature >= 58C");
   11457            0 :                             ShowContinueError(state, format("Occurs for water heater object={}", this->Name));
   11458              :                         } else {
   11459              :                             // plant sizing object design temperature is set too hi throw warning.
   11460            0 :                             ShowSevereError(state,
   11461              :                                             "Autosizing of Use side chilled water tank design flow rate requires Sizing:Plant object to have an "
   11462              :                                             "exit temperature <= 8C");
   11463            0 :                             ShowContinueError(state, format("Occurs for chilled water storage tank object={}", this->Name));
   11464              :                         }
   11465            0 :                         ErrorsFound = true;
   11466              :                     }
   11467            0 :                     if (state.dataPlnt->PlantFinalSizesOkayToReport) {
   11468            0 :                         BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Use Side Design Flow Rate [m3/s]", this->UseDesignVolFlowRate);
   11469              :                     }
   11470            0 :                     if (state.dataPlnt->PlantFirstSizesOkayToReport) {
   11471            0 :                         BaseSizer::reportSizerOutput(
   11472              :                             state, this->Type, this->Name, "Initial Use Side Design Flow Rate [m3/s]", this->UseDesignVolFlowRate);
   11473              :                     }
   11474            0 :                     if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
   11475            0 :                         PlantUtilities::RegisterPlantCompDesignFlow(state, this->UseInletNode, this->UseDesignVolFlowRate);
   11476              :                     } else {
   11477            0 :                         PlantUtilities::RegisterPlantCompDesignFlow(state, this->UseInletNode, tmpUseDesignVolFlowRate);
   11478              :                     }
   11479              :                     Real64 rho =
   11480            0 :                         state.dataPlnt->PlantLoop(this->UseSidePlantLoc.loopNum).glycol->getDensity(state, Constant::InitConvTemp, RoutineName);
   11481            0 :                     if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
   11482            0 :                         this->PlantUseMassFlowRateMax = this->UseDesignVolFlowRate * rho;
   11483              :                     } else {
   11484            0 :                         this->PlantUseMassFlowRateMax = tmpUseDesignVolFlowRate * rho;
   11485              :                     }
   11486              :                 } // Demand side
   11487              :             } else {
   11488              :                 // do nothing
   11489              :             } // plant sizing object
   11490              : 
   11491              :         } else {
   11492              :             // not autosized - report flow to RegisterPlantCompDesignFlow for supply side component sizing
   11493           60 :             PlantUtilities::RegisterPlantCompDesignFlow(state, this->UseInletNode, this->UseDesignVolFlowRate);
   11494              :             Real64 rho;
   11495           60 :             if (this->UseSidePlantLoc.loopNum > 0) {
   11496           60 :                 rho = state.dataPlnt->PlantLoop(this->UseSidePlantLoc.loopNum).glycol->getDensity(state, Constant::InitConvTemp, RoutineName);
   11497              :             } else {
   11498            0 :                 rho = this->water->getDensity(state, Constant::InitConvTemp, RoutineName);
   11499              :             }
   11500           60 :             this->PlantUseMassFlowRateMax = this->UseDesignVolFlowRate * rho;
   11501              :         } // autosizing needed.
   11502              :     } // connected to plant
   11503              : 
   11504          786 :     if (this->SourceInletNode > 0) {
   11505          260 :         if (this->SourceDesignVolFlowRateWasAutoSized) {
   11506          125 :             int PltSizNum = this->SourceSidePlantSizNum;
   11507          125 :             if (PltSizNum > 0) {
   11508          110 :                 if (this->SrcSidePlantLoc.loopSideNum == DataPlant::LoopSideLocation::Demand) {
   11509              :                     //  choose a flow rate that will allow the entire volume of the tank to go from 14.44 to 57.22 C
   11510              :                     // in user specified hours.
   11511              :                     //  using the plant inlet design temp for sizing.
   11512           60 :                     Real64 Tpdesign = PlantSizData(PltSizNum).ExitTemp;
   11513           60 :                     Real64 eff = this->SourceEffectiveness;
   11514           60 :                     if ((Tpdesign >= 58.0) && (!this->IsChilledWaterTank)) {
   11515              : 
   11516           60 :                         if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
   11517            6 :                             this->SourceDesignVolFlowRate = -1.0 * (TankVolume / (tankRecoverhours * Constant::rSecsInHour * eff)) *
   11518            6 :                                                             std::log((Tpdesign - Tfinish) / (Tpdesign - Tstart));
   11519              :                         } else {
   11520           24 :                             tmpSourceDesignVolFlowRate = -1.0 * (TankVolume / (tankRecoverhours * Constant::rSecsInHour * eff)) *
   11521           24 :                                                          std::log((Tpdesign - Tfinish) / (Tpdesign - Tstart));
   11522              :                         }
   11523           30 :                     } else if ((Tpdesign <= 8.0) && (this->IsChilledWaterTank)) {
   11524           60 :                         if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
   11525            6 :                             this->SourceDesignVolFlowRate = -1.0 * (TankVolume / (tankRecoverhours * Constant::rSecsInHour * eff)) *
   11526            6 :                                                             std::log((Tpdesign - Tfinish) / (Tpdesign - Tstart));
   11527              :                         } else {
   11528           24 :                             tmpSourceDesignVolFlowRate = -1.0 * (TankVolume / (tankRecoverhours * Constant::rSecsInHour * eff)) *
   11529           24 :                                                          std::log((Tpdesign - Tfinish) / (Tpdesign - Tstart));
   11530              :                         }
   11531              :                     } else {
   11532            0 :                         if (!this->IsChilledWaterTank) {
   11533              :                             // plant sizing object design temperature is set too low throw warning.
   11534            0 :                             ShowSevereError(state,
   11535              :                                             "Autosizing of Source side water heater design flow rate requires Sizing:Plant object to have an "
   11536              :                                             "exit temperature >= 58C");
   11537            0 :                             ShowContinueError(state, format("Occurs for WaterHeater:Mixed object={}", this->Name));
   11538              :                         } else {
   11539              :                             // plant sizing object design temperature is set too hi throw warning.
   11540            0 :                             ShowSevereError(state,
   11541              :                                             "Autosizing of Source side chilled water tank design flow rate requires Sizing:Plant object to have "
   11542              :                                             "an exit temperature <= 8C");
   11543            0 :                             ShowContinueError(state, format("Occurs for chilled water storage tank object={}", this->Name));
   11544              :                         }
   11545            0 :                         ErrorsFound = true;
   11546              :                     }
   11547           60 :                     if (state.dataPlnt->PlantFinalSizesOkayToReport) {
   11548           12 :                         BaseSizer::reportSizerOutput(
   11549              :                             state, this->Type, this->Name, "Source Side Design Flow Rate [m3/s]", this->SourceDesignVolFlowRate);
   11550              :                     }
   11551           60 :                     if (state.dataPlnt->PlantFirstSizesOkayToReport) {
   11552            0 :                         BaseSizer::reportSizerOutput(
   11553              :                             state, this->Type, this->Name, "Initial Source Side Design Flow Rate [m3/s]", this->SourceDesignVolFlowRate);
   11554              :                     }
   11555           60 :                     if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
   11556           12 :                         PlantUtilities::RegisterPlantCompDesignFlow(state, this->SourceInletNode, this->SourceDesignVolFlowRate);
   11557              :                     } else {
   11558           48 :                         PlantUtilities::RegisterPlantCompDesignFlow(state, this->SourceInletNode, tmpSourceDesignVolFlowRate);
   11559              :                     }
   11560              :                     Real64 rho =
   11561           60 :                         state.dataPlnt->PlantLoop(this->SrcSidePlantLoc.loopNum).glycol->getDensity(state, Constant::InitConvTemp, RoutineName);
   11562           60 :                     if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
   11563           12 :                         this->PlantSourceMassFlowRateMax = this->SourceDesignVolFlowRate * rho;
   11564              :                     } else {
   11565           48 :                         this->PlantSourceMassFlowRateMax = tmpSourceDesignVolFlowRate * rho;
   11566              :                     }
   11567              :                 } // demand side
   11568              :             } else {
   11569              :                 // do nothing
   11570              :             } // plant sizing object
   11571              : 
   11572              :         } else {
   11573              :             // not autosized - report flow to RegisterPlantCompDesignFlow for supply side component sizing
   11574          135 :             PlantUtilities::RegisterPlantCompDesignFlow(state, this->SourceInletNode, this->SourceDesignVolFlowRate);
   11575              :             Real64 rho;
   11576          135 :             if (this->SrcSidePlantLoc.loopNum > 0) {
   11577          100 :                 rho = state.dataPlnt->PlantLoop(this->SrcSidePlantLoc.loopNum).glycol->getDensity(state, Constant::InitConvTemp, RoutineName);
   11578              :             } else {
   11579           35 :                 rho = this->water->getDensity(state, Constant::InitConvTemp, RoutineName);
   11580              :             }
   11581          135 :             this->PlantSourceMassFlowRateMax = this->SourceDesignVolFlowRate * rho;
   11582              :         } // autosizing needed.
   11583              :     } // connected to plant
   11584              : 
   11585          786 :     if (ErrorsFound) {
   11586            0 :         ShowFatalError(state, "Preceding sizing errors cause program termination");
   11587              :     }
   11588          786 : }
   11589              : 
   11590           49 : void WaterThermalTankData::SizeStandAloneWaterHeater(EnergyPlusData &state)
   11591              : {
   11592              : 
   11593              :     // SUBROUTINE INFORMATION:
   11594              :     //       AUTHOR         B. Griffith
   11595              :     //       DATE WRITTEN   October 2013
   11596              :     //       MODIFIED       na
   11597              :     //       RE-ENGINEERED  na
   11598              : 
   11599              :     // PURPOSE OF THIS SUBROUTINE:
   11600              :     // allow autosizing of tank volume and heat capacity for stand alone tanks
   11601              : 
   11602              :     // METHODOLOGY EMPLOYED:
   11603              :     // same as for plant connected water heaters, only draws are scheduled.
   11604              : 
   11605              :     // SUBROUTINE PARAMETER DEFINITIONS:
   11606           49 :     Real64 constexpr GalTocubicMeters(0.0037854);
   11607           49 :     Real64 constexpr kBtuPerHrToWatts(293.1);
   11608              :     static constexpr std::string_view routineName = "SizeStandAloneWaterHeater";
   11609              : 
   11610           49 :     Real64 Tstart = 14.44;
   11611           49 :     Real64 Tfinish = 57.22;
   11612           49 :     Real64 tmpTankVolume = this->Volume;
   11613           49 :     Real64 tmpMaxCapacity = this->MaxCapacity;
   11614              : 
   11615           49 :     if (this->VolumeWasAutoSized || this->MaxCapacityWasAutoSized) {
   11616              : 
   11617            0 :         switch (this->Sizing.DesignMode) {
   11618              : 
   11619            0 :         case SizingMode::PeakDraw: {
   11620              :             // get draw rate from maximum in schedule
   11621              : 
   11622            0 :             Real64 rho = this->water->getDensity(state, Constant::InitConvTemp, routineName);
   11623            0 :             Real64 DrawDesignVolFlowRate = this->flowRateSched->getCurrentVal() * this->MassFlowRateMax / rho;
   11624              : 
   11625            0 :             if (this->VolumeWasAutoSized) {
   11626            0 :                 tmpTankVolume = this->Sizing.TankDrawTime * DrawDesignVolFlowRate * Constant::rSecsInHour; // hours | m3/s | (3600 s/1 hour)
   11627            0 :                 this->Volume = tmpTankVolume;
   11628            0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Tank Volume [m3]", this->Volume);
   11629              :             }
   11630            0 :             if (this->MaxCapacityWasAutoSized) {
   11631            0 :                 if (this->Sizing.RecoveryTime > 0.0) {
   11632            0 :                     rho = this->water->getDensity(state, ((Tfinish + Tstart) / 2.0), routineName);
   11633            0 :                     Real64 Cp = this->water->getSpecificHeat(state, ((Tfinish + Tstart) / 2.0), routineName);
   11634              : 
   11635            0 :                     tmpMaxCapacity = (this->Volume * rho * Cp * (Tfinish - Tstart)) /
   11636            0 :                                      (this->Sizing.RecoveryTime * Constant::rSecsInHour); // m3 | kg/m3 | J/Kg/K | K | seconds
   11637              :                 } else {
   11638            0 :                     ShowFatalError(
   11639              :                         state,
   11640            0 :                         format("{}: Tank=\"{}\", requested sizing for max capacity but entered Recovery Time is zero.", routineName, this->Name));
   11641              :                 }
   11642            0 :                 this->MaxCapacity = tmpMaxCapacity;
   11643            0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Maximum Heater Capacity [W]", this->MaxCapacity);
   11644              :             }
   11645              : 
   11646            0 :             break;
   11647              :         }
   11648            0 :         case SizingMode::ResidentialMin: {
   11649              :             // assume can propagate rules for gas to other fuels.
   11650            0 :             bool FuelTypeIsLikeGas = false;
   11651            0 :             switch (this->FuelType) {
   11652            0 :             case Constant::eFuel::NaturalGas:
   11653              :             case Constant::eFuel::Diesel:
   11654              :             case Constant::eFuel::Gasoline:
   11655              :             case Constant::eFuel::Coal:
   11656              :             case Constant::eFuel::FuelOilNo1:
   11657              :             case Constant::eFuel::FuelOilNo2:
   11658              :             case Constant::eFuel::Propane:
   11659              :             case Constant::eFuel::OtherFuel1:
   11660              :             case Constant::eFuel::OtherFuel2:
   11661              :             case Constant::eFuel::DistrictHeatingWater:
   11662              :             case Constant::eFuel::DistrictHeatingSteam:
   11663            0 :                 FuelTypeIsLikeGas = true;
   11664            0 :                 break;
   11665            0 :             default: // FuelTypeIsLikeGas stays false
   11666            0 :                 break;
   11667              :             }
   11668              : 
   11669            0 :             if (this->Sizing.NumberOfBedrooms == 1) {
   11670            0 :                 if (this->FuelType == Constant::eFuel::Electricity) {
   11671            0 :                     if (this->VolumeWasAutoSized) {
   11672            0 :                         tmpTankVolume = 20.0 * GalTocubicMeters;
   11673              :                     }
   11674            0 :                     if (this->MaxCapacityWasAutoSized) {
   11675            0 :                         tmpMaxCapacity = 2.5 * 1000.0; // 2.5 kW
   11676              :                     }
   11677            0 :                 } else if (FuelTypeIsLikeGas) {
   11678            0 :                     if (this->VolumeWasAutoSized) {
   11679            0 :                         tmpTankVolume = 20.0 * GalTocubicMeters;
   11680              :                     }
   11681            0 :                     if (this->MaxCapacityWasAutoSized) {
   11682            0 :                         tmpMaxCapacity = 27.0 * kBtuPerHrToWatts; // 27kBtu/hr
   11683              :                     }
   11684              :                 }
   11685              : 
   11686            0 :             } else if (this->Sizing.NumberOfBedrooms == 2) {
   11687            0 :                 if (this->Sizing.NumberOfBathrooms <= 1.5) {
   11688            0 :                     if (this->FuelType == Constant::eFuel::Electricity) {
   11689            0 :                         if (this->VolumeWasAutoSized) {
   11690            0 :                             tmpTankVolume = 30.0 * GalTocubicMeters;
   11691              :                         }
   11692            0 :                         if (this->MaxCapacityWasAutoSized) {
   11693            0 :                             tmpMaxCapacity = 3.5 * 1000.0; // 3.5 kW
   11694              :                         }
   11695            0 :                     } else if (FuelTypeIsLikeGas) {
   11696            0 :                         if (this->VolumeWasAutoSized) {
   11697            0 :                             tmpTankVolume = 30.0 * GalTocubicMeters;
   11698              :                         }
   11699            0 :                         if (this->MaxCapacityWasAutoSized) {
   11700            0 :                             tmpMaxCapacity = 36.0 * kBtuPerHrToWatts; // 36 kBtu/hr
   11701              :                         }
   11702              :                     }
   11703            0 :                 } else if ((this->Sizing.NumberOfBathrooms > 1.5) && (this->Sizing.NumberOfBathrooms < 3.0)) {
   11704            0 :                     if (this->FuelType == Constant::eFuel::Electricity) {
   11705            0 :                         if (this->VolumeWasAutoSized) {
   11706            0 :                             tmpTankVolume = 40.0 * GalTocubicMeters;
   11707              :                         }
   11708            0 :                         if (this->MaxCapacityWasAutoSized) {
   11709            0 :                             tmpMaxCapacity = 4.5 * 1000.0; // 4.5 kW
   11710              :                         }
   11711            0 :                     } else if (FuelTypeIsLikeGas) {
   11712            0 :                         if (this->VolumeWasAutoSized) {
   11713            0 :                             tmpTankVolume = 30.0 * GalTocubicMeters;
   11714              :                         }
   11715            0 :                         if (this->MaxCapacityWasAutoSized) {
   11716            0 :                             tmpMaxCapacity = 36.0 * kBtuPerHrToWatts; // 36 kBtu/hr
   11717              :                         }
   11718              :                     }
   11719            0 :                 } else if (this->Sizing.NumberOfBathrooms >= 3.0) {
   11720            0 :                     if (this->FuelType == Constant::eFuel::Electricity) {
   11721            0 :                         if (this->VolumeWasAutoSized) {
   11722            0 :                             tmpTankVolume = 50.0 * GalTocubicMeters;
   11723              :                         }
   11724            0 :                         if (this->MaxCapacityWasAutoSized) {
   11725            0 :                             tmpMaxCapacity = 5.5 * 1000.0; // 5.5 kW
   11726              :                         }
   11727            0 :                     } else if (FuelTypeIsLikeGas) {
   11728            0 :                         if (this->VolumeWasAutoSized) {
   11729            0 :                             tmpTankVolume = 40.0 * GalTocubicMeters;
   11730              :                         }
   11731            0 :                         if (this->MaxCapacityWasAutoSized) {
   11732            0 :                             tmpMaxCapacity = 36.0 * kBtuPerHrToWatts; // 36 kBtu/hr
   11733              :                         }
   11734              :                     }
   11735              :                 }
   11736            0 :             } else if (this->Sizing.NumberOfBedrooms == 3) {
   11737            0 :                 if (this->Sizing.NumberOfBathrooms <= 1.5) {
   11738            0 :                     if (this->FuelType == Constant::eFuel::Electricity) {
   11739            0 :                         if (this->VolumeWasAutoSized) {
   11740            0 :                             tmpTankVolume = 40.0 * GalTocubicMeters;
   11741              :                         }
   11742            0 :                         if (this->MaxCapacityWasAutoSized) {
   11743            0 :                             tmpMaxCapacity = 4.5 * 1000.0; // 4.5 kW
   11744              :                         }
   11745            0 :                     } else if (FuelTypeIsLikeGas) {
   11746            0 :                         if (this->VolumeWasAutoSized) {
   11747            0 :                             tmpTankVolume = 30.0 * GalTocubicMeters;
   11748              :                         }
   11749            0 :                         if (this->MaxCapacityWasAutoSized) {
   11750            0 :                             tmpMaxCapacity = 36.0 * kBtuPerHrToWatts; // 36 kBtu/hr
   11751              :                         }
   11752              :                     }
   11753            0 :                 } else if ((this->Sizing.NumberOfBathrooms > 1.5) && (this->Sizing.NumberOfBathrooms < 3.0)) {
   11754            0 :                     if (this->FuelType == Constant::eFuel::Electricity) {
   11755            0 :                         if (this->VolumeWasAutoSized) {
   11756            0 :                             tmpTankVolume = 50.0 * GalTocubicMeters;
   11757              :                         }
   11758            0 :                         if (this->MaxCapacityWasAutoSized) {
   11759            0 :                             tmpMaxCapacity = 5.5 * 1000.0; // 5.5 kW
   11760              :                         }
   11761            0 :                     } else if (FuelTypeIsLikeGas) {
   11762            0 :                         if (this->VolumeWasAutoSized) {
   11763            0 :                             tmpTankVolume = 40.0 * GalTocubicMeters;
   11764              :                         }
   11765            0 :                         if (this->MaxCapacityWasAutoSized) {
   11766            0 :                             tmpMaxCapacity = 36.0 * kBtuPerHrToWatts; // 36 kBtu/hr
   11767              :                         }
   11768              :                     }
   11769            0 :                 } else if (this->Sizing.NumberOfBathrooms >= 3.0) {
   11770            0 :                     if (this->FuelType == Constant::eFuel::Electricity) {
   11771            0 :                         if (this->VolumeWasAutoSized) {
   11772            0 :                             tmpTankVolume = 50.0 * GalTocubicMeters;
   11773              :                         }
   11774            0 :                         if (this->MaxCapacityWasAutoSized) {
   11775            0 :                             tmpMaxCapacity = 5.5 * 1000.0; // 5.5 kW
   11776              :                         }
   11777            0 :                     } else if (FuelTypeIsLikeGas) {
   11778            0 :                         if (this->VolumeWasAutoSized) {
   11779            0 :                             tmpTankVolume = 40.0 * GalTocubicMeters;
   11780              :                         }
   11781            0 :                         if (this->MaxCapacityWasAutoSized) {
   11782            0 :                             tmpMaxCapacity = 38.0 * kBtuPerHrToWatts; // 38 kBtu/hr
   11783              :                         }
   11784              :                     }
   11785              :                 }
   11786            0 :             } else if (this->Sizing.NumberOfBedrooms == 4) {
   11787            0 :                 if (this->Sizing.NumberOfBathrooms <= 1.5) {
   11788            0 :                     if (this->FuelType == Constant::eFuel::Electricity) {
   11789            0 :                         if (this->VolumeWasAutoSized) {
   11790            0 :                             tmpTankVolume = 50.0 * GalTocubicMeters;
   11791              :                         }
   11792            0 :                         if (this->MaxCapacityWasAutoSized) {
   11793            0 :                             tmpMaxCapacity = 5.5 * 1000.0; // 5.5 kW
   11794              :                         }
   11795            0 :                     } else if (FuelTypeIsLikeGas) {
   11796            0 :                         if (this->VolumeWasAutoSized) {
   11797            0 :                             tmpTankVolume = 40.0 * GalTocubicMeters;
   11798              :                         }
   11799            0 :                         if (this->MaxCapacityWasAutoSized) {
   11800            0 :                             tmpMaxCapacity = 36.0 * kBtuPerHrToWatts; // 36 kBtu/hr
   11801              :                         }
   11802              :                     }
   11803            0 :                 } else if ((this->Sizing.NumberOfBathrooms > 1.5) && (this->Sizing.NumberOfBathrooms < 3.0)) {
   11804            0 :                     if (this->FuelType == Constant::eFuel::Electricity) {
   11805            0 :                         if (this->VolumeWasAutoSized) {
   11806            0 :                             tmpTankVolume = 50.0 * GalTocubicMeters;
   11807              :                         }
   11808            0 :                         if (this->MaxCapacityWasAutoSized) {
   11809            0 :                             tmpMaxCapacity = 5.5 * 1000.0; // 5.5 kW
   11810              :                         }
   11811            0 :                     } else if (FuelTypeIsLikeGas) {
   11812            0 :                         if (this->VolumeWasAutoSized) {
   11813            0 :                             tmpTankVolume = 40.0 * GalTocubicMeters;
   11814              :                         }
   11815            0 :                         if (this->MaxCapacityWasAutoSized) {
   11816            0 :                             tmpMaxCapacity = 38.0 * kBtuPerHrToWatts; // 38 kBtu/hr
   11817              :                         }
   11818              :                     }
   11819            0 :                 } else if (this->Sizing.NumberOfBathrooms >= 3.0) {
   11820            0 :                     if (this->FuelType == Constant::eFuel::Electricity) {
   11821            0 :                         if (this->VolumeWasAutoSized) {
   11822            0 :                             tmpTankVolume = 66.0 * GalTocubicMeters;
   11823              :                         }
   11824            0 :                         if (this->MaxCapacityWasAutoSized) {
   11825            0 :                             tmpMaxCapacity = 5.5 * 1000.0; // 5.5 kW
   11826              :                         }
   11827            0 :                     } else if (FuelTypeIsLikeGas) {
   11828            0 :                         if (this->VolumeWasAutoSized) {
   11829            0 :                             tmpTankVolume = 50.0 * GalTocubicMeters;
   11830              :                         }
   11831            0 :                         if (this->MaxCapacityWasAutoSized) {
   11832            0 :                             tmpMaxCapacity = 38.0 * kBtuPerHrToWatts; // 38 kBtu/hr
   11833              :                         }
   11834              :                     }
   11835              :                 }
   11836            0 :             } else if (this->Sizing.NumberOfBedrooms == 5) {
   11837            0 :                 if (this->FuelType == Constant::eFuel::Electricity) {
   11838            0 :                     if (this->VolumeWasAutoSized) {
   11839            0 :                         tmpTankVolume = 66.0 * GalTocubicMeters;
   11840              :                     }
   11841            0 :                     if (this->MaxCapacityWasAutoSized) {
   11842            0 :                         tmpMaxCapacity = 5.5 * 1000.0; // 5.5 kW
   11843              :                     }
   11844            0 :                 } else if (FuelTypeIsLikeGas) {
   11845            0 :                     if (this->VolumeWasAutoSized) {
   11846            0 :                         tmpTankVolume = 50.0 * GalTocubicMeters;
   11847              :                     }
   11848            0 :                     if (this->MaxCapacityWasAutoSized) {
   11849            0 :                         tmpMaxCapacity = 47.0 * kBtuPerHrToWatts; // 47 kBtu/hr
   11850              :                     }
   11851              :                 }
   11852            0 :             } else if (this->Sizing.NumberOfBedrooms >= 6) {
   11853            0 :                 if (this->FuelType == Constant::eFuel::Electricity) {
   11854            0 :                     if (this->VolumeWasAutoSized) {
   11855            0 :                         tmpTankVolume = 66.0 * GalTocubicMeters;
   11856              :                     }
   11857            0 :                     if (this->MaxCapacityWasAutoSized) {
   11858            0 :                         tmpMaxCapacity = 5.5 * 1000.0; // 5.5 kW
   11859              :                     }
   11860            0 :                 } else if (FuelTypeIsLikeGas) {
   11861            0 :                     if (this->VolumeWasAutoSized) {
   11862            0 :                         tmpTankVolume = 50.0 * GalTocubicMeters;
   11863              :                     }
   11864            0 :                     if (this->MaxCapacityWasAutoSized) {
   11865            0 :                         tmpMaxCapacity = 50.0 * kBtuPerHrToWatts; // 50 kBtu/hr
   11866              :                     }
   11867              :                 }
   11868              :             }
   11869            0 :             if (this->VolumeWasAutoSized) {
   11870            0 :                 this->Volume = tmpTankVolume;
   11871            0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Tank Volume [m3]", this->Volume);
   11872              :             }
   11873            0 :             if (this->MaxCapacityWasAutoSized) {
   11874            0 :                 this->MaxCapacity = tmpMaxCapacity;
   11875            0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Maximum Heater Capacity [W]", this->MaxCapacity);
   11876              :             }
   11877              : 
   11878            0 :             break;
   11879              :         }
   11880            0 :         case SizingMode::PerPerson: {
   11881              :             // how to get number of people?
   11882              : 
   11883              :             // MJW TODO: this won't compile now: Real64 SumPeopleAllZones = sum(state.dataHeatBal->Zone, &DataHeatBalance::ZoneData::TotOccupants);
   11884            0 :             Real64 SumPeopleAllZones = 0.0;
   11885            0 :             for (auto const &thisZone : state.dataHeatBal->Zone) {
   11886            0 :                 SumPeopleAllZones += thisZone.TotOccupants;
   11887            0 :             }
   11888            0 :             if (this->VolumeWasAutoSized) {
   11889            0 :                 tmpTankVolume = this->Sizing.TankCapacityPerPerson * SumPeopleAllZones;
   11890              :             }
   11891            0 :             if (this->MaxCapacityWasAutoSized) {
   11892            0 :                 Real64 rho = this->water->getDensity(state, ((Tfinish + Tstart) / 2.0), routineName);
   11893            0 :                 Real64 Cp = this->water->getSpecificHeat(state, ((Tfinish + Tstart) / 2.0), routineName);
   11894            0 :                 tmpMaxCapacity = SumPeopleAllZones * this->Sizing.RecoveryCapacityPerPerson * (Tfinish - Tstart) * (1.0 / Constant::rSecsInHour) *
   11895              :                                  rho * Cp; // m3/hr/person | delta T  in K | 1 hr/ 3600 s | kg/m3 | J/Kg/k
   11896              :             }
   11897              : 
   11898            0 :             if (this->VolumeWasAutoSized) {
   11899            0 :                 this->Volume = tmpTankVolume;
   11900            0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Tank Volume [m3]", this->Volume);
   11901              :             }
   11902            0 :             if (this->MaxCapacityWasAutoSized) {
   11903            0 :                 this->MaxCapacity = tmpMaxCapacity;
   11904            0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Maximum Heater Capacity [W]", this->MaxCapacity);
   11905              :             }
   11906              : 
   11907            0 :             break;
   11908              :         }
   11909            0 :         case SizingMode::PerFloorArea: {
   11910              : 
   11911              :             // MJW TODO: this won't compile now: Real64 SumFloorAreaAllZones = sum(state.dataHeatBal->Zone, &DataHeatBalance::ZoneData::FloorArea);
   11912            0 :             Real64 SumFloorAreaAllZones = 0.0;
   11913            0 :             for (auto const &thisZone : state.dataHeatBal->Zone) {
   11914            0 :                 SumFloorAreaAllZones += thisZone.FloorArea;
   11915            0 :             }
   11916            0 :             if (this->VolumeWasAutoSized) {
   11917            0 :                 tmpTankVolume = this->Sizing.TankCapacityPerArea * SumFloorAreaAllZones;
   11918              :             }
   11919              : 
   11920            0 :             if (this->MaxCapacityWasAutoSized) {
   11921            0 :                 Real64 rho = this->water->getDensity(state, ((Tfinish + Tstart) / 2.0), routineName);
   11922            0 :                 Real64 Cp = this->water->getSpecificHeat(state, ((Tfinish + Tstart) / 2.0), routineName);
   11923            0 :                 tmpMaxCapacity = SumFloorAreaAllZones * this->Sizing.RecoveryCapacityPerArea * (Tfinish - Tstart) * (1.0 / Constant::rSecsInHour) *
   11924              :                                  rho * Cp; // m2 | m3/hr/m2 | delta T  in K | 1 hr/ 3600 s | kg/m3 | J/Kg/k
   11925              :             }
   11926            0 :             if (this->VolumeWasAutoSized) {
   11927            0 :                 this->Volume = tmpTankVolume;
   11928            0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Tank Volume [m3]", this->Volume);
   11929              :             }
   11930            0 :             if (this->MaxCapacityWasAutoSized) {
   11931            0 :                 this->MaxCapacity = tmpMaxCapacity;
   11932            0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Maximum Heater Capacity [W]", this->MaxCapacity);
   11933              :             }
   11934            0 :             break;
   11935              :         }
   11936            0 :         case SizingMode::PerUnit: {
   11937              : 
   11938            0 :             if (this->VolumeWasAutoSized) {
   11939            0 :                 tmpTankVolume = this->Sizing.TankCapacityPerUnit * this->Sizing.NumberOfUnits;
   11940              :             }
   11941              : 
   11942            0 :             if (this->MaxCapacityWasAutoSized) {
   11943            0 :                 Real64 rho = this->water->getDensity(state, ((Tfinish + Tstart) / 2.0), routineName);
   11944            0 :                 Real64 Cp = this->water->getSpecificHeat(state, ((Tfinish + Tstart) / 2.0), routineName);
   11945            0 :                 tmpMaxCapacity = this->Sizing.NumberOfUnits * this->Sizing.RecoveryCapacityPerUnit * (Tfinish - Tstart) *
   11946            0 :                                  (1.0 / Constant::rSecsInHour) * rho * Cp; // m3/hr/ea | delta T  in K | 1 hr/ 3600 s | kg/m3 | J/Kg/k
   11947              :             }
   11948              : 
   11949            0 :             if (this->VolumeWasAutoSized) {
   11950            0 :                 this->Volume = tmpTankVolume;
   11951            0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Tank Volume [m3]", this->Volume);
   11952              :             }
   11953            0 :             if (this->MaxCapacityWasAutoSized) {
   11954            0 :                 this->MaxCapacity = tmpMaxCapacity;
   11955            0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Maximum Heater Capacity [W]", this->MaxCapacity);
   11956              :             }
   11957            0 :             break;
   11958              :         }
   11959            0 :         case SizingMode::PerSolarColArea: {
   11960              : 
   11961            0 :             this->Sizing.TotalSolarCollectorArea = 0.0;
   11962              : 
   11963            0 :             for (int CollectorNum = 1; CollectorNum <= state.dataSolarCollectors->NumOfCollectors; ++CollectorNum) {
   11964            0 :                 auto const &collector = state.dataSolarCollectors->Collector(CollectorNum);
   11965            0 :                 this->Sizing.TotalSolarCollectorArea += state.dataSurface->Surface(collector.Surface).Area;
   11966              :             }
   11967              : 
   11968            0 :             for (int CollectorNum = 1; CollectorNum <= state.dataPhotovoltaicThermalCollector->NumPVT; ++CollectorNum) {
   11969            0 :                 auto const &collector = state.dataPhotovoltaicThermalCollector->PVT(CollectorNum);
   11970            0 :                 this->Sizing.TotalSolarCollectorArea += collector.AreaCol;
   11971              :             }
   11972              : 
   11973            0 :             if (this->VolumeWasAutoSized) {
   11974            0 :                 if (this->Sizing.TotalSolarCollectorArea > 0) {
   11975            0 :                     tmpTankVolume = this->Sizing.TotalSolarCollectorArea * this->Sizing.TankCapacityPerCollectorArea;
   11976              :                 } else {
   11977            0 :                     ShowFatalError(state,
   11978            0 :                                    format("{}: Tank=\"{}\", requested sizing for volume with PerSolarCollectorArea but total found "
   11979              :                                           "area of Collectors is zero.",
   11980              :                                           routineName,
   11981            0 :                                           this->Name));
   11982              :                 }
   11983              :             }
   11984            0 :             if (this->MaxCapacityWasAutoSized) {
   11985            0 :                 tmpMaxCapacity = 0.0;
   11986              :             }
   11987              : 
   11988            0 :             if (this->VolumeWasAutoSized) {
   11989            0 :                 this->Volume = tmpTankVolume;
   11990            0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Tank Volume [m3]", this->Volume);
   11991              :             }
   11992            0 :             if (this->MaxCapacityWasAutoSized) {
   11993            0 :                 this->MaxCapacity = tmpMaxCapacity;
   11994            0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Maximum Heater Capacity [W]", this->MaxCapacity);
   11995              :             }
   11996            0 :             break;
   11997              :         }
   11998            0 :         default:
   11999            0 :             if (this->MaxCapacityWasAutoSized) {
   12000            0 :                 this->setBackupElementCapacity(state);
   12001              :             }
   12002            0 :             break;
   12003              :         }
   12004              :     }
   12005           49 : }
   12006              : 
   12007      6336629 : void WaterThermalTankData::UpdateWaterThermalTank(EnergyPlusData &state)
   12008              : {
   12009              : 
   12010              :     // SUBROUTINE INFORMATION:
   12011              :     //       AUTHOR         Brandon Anderson
   12012              :     //       DATE WRITTEN   May 2000
   12013              :     //       MODIFIED       na
   12014              :     //                      Nov 2011, BAN; removed the use and source heat rate re-calculation for stratified tank
   12015              :     //                                     for energy conservation verification.
   12016              :     //       RE-ENGINEERED  Feb 2004, PGE
   12017              : 
   12018              :     // PURPOSE OF THIS SUBROUTINE:
   12019              :     // Updates the node variables with local variables.
   12020              : 
   12021      6336629 :     if (this->UseInletNode > 0 && this->UseOutletNode > 0) {
   12022      5935311 :         state.dataLoopNodes->Node(UseOutletNode) = state.dataLoopNodes->Node(this->UseInletNode); // this could wipe out setpoints on outlet node
   12023              : 
   12024      5935311 :         state.dataLoopNodes->Node(this->UseOutletNode).Temp = this->UseOutletTemp;
   12025              :     }
   12026              : 
   12027      6336629 :     if (this->SourceInletNode > 0 && this->SourceOutletNode > 0) {
   12028      1800956 :         state.dataLoopNodes->Node(this->SourceOutletNode) = state.dataLoopNodes->Node(this->SourceInletNode);
   12029              : 
   12030      1800956 :         state.dataLoopNodes->Node(this->SourceOutletNode).Temp = this->SourceOutletTemp;
   12031              :     }
   12032      6336629 : }
   12033              : 
   12034      6336629 : void WaterThermalTankData::ReportWaterThermalTank(EnergyPlusData &state)
   12035              : {
   12036              : 
   12037              :     // SUBROUTINE INFORMATION:
   12038              :     //       AUTHOR         Brandon Anderson
   12039              :     //       DATE WRITTEN   May 2000
   12040              :     //       MODIFIED       na
   12041              :     //       RE-ENGINEERED  Feb 2004, PGE
   12042              : 
   12043      6336629 :     Real64 SecInTimeStep = state.dataHVACGlobal->TimeStepSysSec;
   12044              : 
   12045      6336629 :     this->UnmetEnergy = this->UnmetRate * SecInTimeStep;
   12046      6336629 :     this->LossEnergy = this->LossRate * SecInTimeStep;
   12047      6336629 :     this->FlueLossEnergy = this->FlueLossRate * SecInTimeStep;
   12048      6336629 :     this->UseEnergy = this->UseRate * SecInTimeStep;
   12049      6336629 :     this->TotalDemandEnergy = this->TotalDemandRate * SecInTimeStep;
   12050      6336629 :     this->SourceEnergy = this->SourceRate * SecInTimeStep;
   12051      6336629 :     this->HeaterEnergy = this->HeaterRate * SecInTimeStep;
   12052      6336629 :     this->HeaterEnergy1 = this->HeaterRate1 * SecInTimeStep;
   12053      6336629 :     this->HeaterEnergy2 = this->HeaterRate2 * SecInTimeStep;
   12054      6336629 :     this->FuelEnergy = this->FuelRate * SecInTimeStep;
   12055      6336629 :     this->VentEnergy = this->VentRate * SecInTimeStep;
   12056      6336629 :     this->OffCycParaFuelEnergy = this->OffCycParaFuelRate * SecInTimeStep;
   12057      6336629 :     this->OffCycParaEnergyToTank = this->OffCycParaRateToTank * SecInTimeStep;
   12058      6336629 :     this->OnCycParaFuelEnergy = this->OnCycParaFuelRate * SecInTimeStep;
   12059      6336629 :     this->OnCycParaEnergyToTank = this->OnCycParaRateToTank * SecInTimeStep;
   12060      6336629 :     this->NetHeatTransferEnergy = this->NetHeatTransferRate * SecInTimeStep;
   12061      6336629 :     this->VolumeConsumed = this->VolFlowRate * SecInTimeStep;
   12062      6336629 : }
   12063              : 
   12064          349 : void WaterThermalTankData::CalcStandardRatings(EnergyPlusData &state)
   12065              : {
   12066              : 
   12067              :     // SUBROUTINE INFORMATION:
   12068              :     //       AUTHOR         Peter Graham Ellis
   12069              :     //       DATE WRITTEN   January 2005
   12070              :     //       MODIFIED       R. Raustad, July 2005 - added HPWH to ratings procedure
   12071              :     //       RE-ENGINEERED  na
   12072              : 
   12073              :     // PURPOSE OF THIS SUBROUTINE:
   12074              :     // Calculates the water heater standard ratings, such as Energy Factor and Recovery Efficiency.  Results are written
   12075              :     // to the EIO file.  Standard ratings are not calculated for storage-only tanks, i.e., MaxCapacity = 0, nor for Integrated Heat Pumps
   12076              : 
   12077              :     // METHODOLOGY EMPLOYED:
   12078              :     // Water heater inputs are set to the specified test conditions. For HPWHs, the heating capacity and COP are assumed
   12079              :     // to be the primary element in the water heater and are used during the rating procedure.  CalcWaterThermalTankMixed
   12080              :     // is iteratively called in a self-contained, 24 hour simulation of the standard test procedure.
   12081              : 
   12082              :     // REFERENCES:
   12083              :     // Title 10, Code of Federal Regulations, Part 430- Energy Conservation Program for Consumer Products, Appendix E to
   12084              :     // Subpart B- Uniform Test Procedure for Measuring the Energy Consumption of Water Heaters, January 1, 2004.
   12085              : 
   12086          349 :     if (this->AlreadyRated) { // bail we already did this one
   12087          154 :         return;
   12088              :     }
   12089              : 
   12090              :     bool FirstTimeFlag; // used during HPWH rating procedure
   12091          195 :     bool bIsVSCoil = false;
   12092              :     Real64 RecoveryEfficiency;
   12093              :     Real64 EnergyFactor;
   12094          195 :     Real64 RatedDXCoilTotalCapacity = 0.0;
   12095          195 :     if (this->MaxCapacity > 0.0 || this->HeatPumpNum > 0) {
   12096              :         // Set test conditions
   12097          190 :         this->AmbientTemp = 19.7222;   // 67.5 F
   12098          190 :         this->UseInletTemp = 14.4444;  // 58 F
   12099          190 :         this->SetPointTemp = 57.2222;  // 135 F
   12100          190 :         this->SetPointTemp2 = 57.2222; // 135 F
   12101          190 :         this->TankTemp = 57.2222;      // Initialize tank temperature
   12102          190 :         if (this->Nodes > 0) {
   12103          144 :             for (auto &e : this->Node) {
   12104          128 :                 e.Temp = 57.2222;
   12105              :             }
   12106              :         }
   12107              : 
   12108          190 :         Real64 TotalDrawMass = 0.243402 * Psychrometrics::RhoH2O(Constant::InitConvTemp); // 64.3 gal * rho
   12109          190 :         Real64 DrawMass = TotalDrawMass / 6.0;                                            // 6 equal draws
   12110          190 :         Real64 SecInTimeStep = state.dataHVACGlobal->TimeStepSysSec;
   12111          190 :         Real64 DrawMassFlowRate = DrawMass / SecInTimeStep;
   12112          190 :         Real64 FuelEnergy_loc = 0.0;
   12113          190 :         FirstTimeFlag = true;
   12114              : 
   12115          190 :         int TimeStepPerHour = int(1.0 / state.dataHVACGlobal->TimeStepSys);
   12116              :         // Simulate 24 hour test
   12117        23566 :         for (int Step = 1; Step <= TimeStepPerHour * 24; ++Step) {
   12118              : 
   12119        23376 :             if (Step == 1 || Step == (1 + TimeStepPerHour) || Step == (1 + TimeStepPerHour * 2) || Step == (1 + TimeStepPerHour * 3) ||
   12120        22616 :                 Step == (1 + TimeStepPerHour * 4) || Step == (1 + TimeStepPerHour * 5)) { // Hour 1 | Hour 2 | Hour 3 | Hour 4 | Hour 5 | Hour 6
   12121              : 
   12122         1140 :                 this->UseMassFlowRate = DrawMassFlowRate;
   12123              :             } else {
   12124        22236 :                 this->UseMassFlowRate = 0.0;
   12125              :             }
   12126              : 
   12127        23376 :             this->SavedTankTemp = this->TankTemp;
   12128        23376 :             this->SavedMode = this->Mode;
   12129        23376 :             if (this->Nodes > 0) {
   12130        33552 :                 for (auto &e : this->Node) {
   12131        30336 :                     e.SavedTemp = e.Temp;
   12132              :                 }
   12133         3216 :                 this->SavedHeaterOn1 = this->HeaterOn1;
   12134         3216 :                 this->SavedHeaterOn2 = this->HeaterOn2;
   12135              :             }
   12136              : 
   12137        23376 :             if (this->HeatPumpNum == 0) {
   12138              : 
   12139        19584 :                 if (this->WaterThermalTankType == DataPlant::PlantEquipmentType::WtrHeaterMixed) {
   12140        18960 :                     this->CalcWaterThermalTankMixed(state);
   12141              : 
   12142          624 :                 } else if (this->WaterThermalTankType == DataPlant::PlantEquipmentType::WtrHeaterStratified) {
   12143          624 :                     this->CalcWaterThermalTankStratified(state);
   12144              :                 }
   12145              : 
   12146              :             } else {
   12147              : 
   12148         3792 :                 int HPNum = this->HeatPumpNum;  // Convenience variable
   12149         3792 :                 Real64 AmbientHumRat = 0.00717; // Humidity ratio at 67.5 F / 50% RH
   12150              : 
   12151              :                 //       set the heat pump air- and water-side mass flow rate
   12152         3792 :                 Real64 MdotWater = state.dataWaterThermalTanks->HPWaterHeater(HPNum).OperatingWaterFlowRate * Psychrometrics::RhoH2O(this->TankTemp);
   12153         3792 :                 Real64 mdotAir = state.dataWaterThermalTanks->HPWaterHeater(HPNum).OperatingAirMassFlowRate;
   12154              : 
   12155              :                 // ?? why is HPWH condenser inlet node temp reset inside the for loop? shouldn't it chnage with the tank temp throughout these
   12156              :                 // iterations?
   12157         3792 :                 if (state.dataWaterThermalTanks->HPWaterHeater(HPNum).HPWHType == DataPlant::PlantEquipmentType::HeatPumpWtrHeaterPumped) {
   12158              :                     // set the condenser inlet node mass flow rate and temperature
   12159         2064 :                     state.dataLoopNodes->Node(state.dataWaterThermalTanks->HPWaterHeater(HPNum).CondWaterInletNode).MassFlowRate = MdotWater;
   12160         2064 :                     state.dataLoopNodes->Node(state.dataWaterThermalTanks->HPWaterHeater(HPNum).CondWaterInletNode).Temp = this->TankTemp;
   12161              :                 }
   12162              : 
   12163              :                 //       initialize temperatures for HPWH DX Coil heating capacity and COP curves
   12164         3792 :                 state.dataHVACGlobal->HPWHInletDBTemp = this->AmbientTemp;
   12165         7584 :                 state.dataHVACGlobal->HPWHInletWBTemp =
   12166         3792 :                     Psychrometrics::PsyTwbFnTdbWPb(state, state.dataHVACGlobal->HPWHInletDBTemp, AmbientHumRat, state.dataEnvrn->OutBaroPress);
   12167              : 
   12168              :                 //       set up full air flow on DX coil inlet node
   12169         3792 :                 if (state.dataWaterThermalTanks->HPWaterHeater(HPNum).InletAirMixerNode > 0) {
   12170          288 :                     state.dataLoopNodes->Node(state.dataWaterThermalTanks->HPWaterHeater(HPNum).InletAirMixerNode).MassFlowRate = mdotAir;
   12171          288 :                     state.dataLoopNodes->Node(state.dataWaterThermalTanks->HPWaterHeater(HPNum).InletAirMixerNode).MassFlowRateMaxAvail = mdotAir;
   12172          288 :                     state.dataLoopNodes->Node(state.dataWaterThermalTanks->HPWaterHeater(HPNum).InletAirMixerNode).Temp = this->AmbientTemp;
   12173          288 :                     state.dataLoopNodes->Node(state.dataWaterThermalTanks->HPWaterHeater(HPNum).InletAirMixerNode).HumRat = AmbientHumRat;
   12174          288 :                     state.dataLoopNodes->Node(state.dataWaterThermalTanks->HPWaterHeater(HPNum).InletAirMixerNode).Enthalpy =
   12175          288 :                         Psychrometrics::PsyHFnTdbW(this->AmbientTemp, AmbientHumRat);
   12176              :                 } else {
   12177         3504 :                     if (state.dataWaterThermalTanks->HPWaterHeater(HPNum).OutsideAirNode == 0) {
   12178         1056 :                         state.dataLoopNodes->Node(state.dataWaterThermalTanks->HPWaterHeater(HPNum).HeatPumpAirInletNode).MassFlowRate = mdotAir;
   12179         1056 :                         state.dataLoopNodes->Node(state.dataWaterThermalTanks->HPWaterHeater(HPNum).HeatPumpAirInletNode).MassFlowRateMaxAvail =
   12180              :                             mdotAir;
   12181         1056 :                         state.dataLoopNodes->Node(state.dataWaterThermalTanks->HPWaterHeater(HPNum).HeatPumpAirInletNode).Temp = this->AmbientTemp;
   12182         1056 :                         state.dataLoopNodes->Node(state.dataWaterThermalTanks->HPWaterHeater(HPNum).HeatPumpAirInletNode).HumRat = AmbientHumRat;
   12183         1056 :                         state.dataLoopNodes->Node(state.dataWaterThermalTanks->HPWaterHeater(HPNum).HeatPumpAirInletNode).Enthalpy =
   12184         1056 :                             Psychrometrics::PsyHFnTdbW(this->AmbientTemp, AmbientHumRat);
   12185              :                     } else {
   12186         2448 :                         state.dataLoopNodes->Node(state.dataWaterThermalTanks->HPWaterHeater(HPNum).OutsideAirNode).MassFlowRate = mdotAir;
   12187         2448 :                         state.dataLoopNodes->Node(state.dataWaterThermalTanks->HPWaterHeater(HPNum).OutsideAirNode).MassFlowRateMaxAvail = mdotAir;
   12188         2448 :                         state.dataLoopNodes->Node(state.dataWaterThermalTanks->HPWaterHeater(HPNum).OutsideAirNode).Temp = this->AmbientTemp;
   12189         2448 :                         state.dataLoopNodes->Node(state.dataWaterThermalTanks->HPWaterHeater(HPNum).OutsideAirNode).HumRat = AmbientHumRat;
   12190         2448 :                         state.dataLoopNodes->Node(state.dataWaterThermalTanks->HPWaterHeater(HPNum).OutsideAirNode).Enthalpy =
   12191         2448 :                             Psychrometrics::PsyHFnTdbW(this->AmbientTemp, AmbientHumRat);
   12192              :                     }
   12193              :                 }
   12194              : 
   12195         3792 :                 state.dataHVACGlobal->HPWHCrankcaseDBTemp = this->AmbientTemp;
   12196              : 
   12197         3792 :                 if (Util::SameString(state.dataWaterThermalTanks->HPWaterHeater(HPNum).DXCoilType,
   12198         6960 :                                      "Coil:WaterHeating:AirToWaterHeatPump:VariableSpeed") ||
   12199         3168 :                     (state.dataWaterThermalTanks->HPWaterHeater(HPNum).bIsIHP)) {
   12200          768 :                     bIsVSCoil = true;
   12201          768 :                     std::string VSCoilName = state.dataWaterThermalTanks->HPWaterHeater(HPNum).DXCoilName;
   12202          768 :                     int VSCoilNum = state.dataWaterThermalTanks->HPWaterHeater(HPNum).DXCoilNum;
   12203          768 :                     if (state.dataWaterThermalTanks->HPWaterHeater(HPNum).bIsIHP) {
   12204          144 :                         VSCoilNum =
   12205          144 :                             state.dataIntegratedHP->IntegratedHeatPumps(state.dataWaterThermalTanks->HPWaterHeater(HPNum).DXCoilNum).SCWHCoilIndex;
   12206              :                         VSCoilName =
   12207          144 :                             state.dataIntegratedHP->IntegratedHeatPumps(state.dataWaterThermalTanks->HPWaterHeater(HPNum).DXCoilNum).SCWHCoilName;
   12208              :                     }
   12209              : 
   12210          768 :                     Real64 RhoWater = Psychrometrics::RhoH2O(this->TankTemp);
   12211          768 :                     auto &HPWH = state.dataWaterThermalTanks->HPWaterHeater(HPNum);
   12212          768 :                     this->SetVSHPWHFlowRates(
   12213              :                         state,
   12214              :                         HPWH,
   12215          768 :                         state.dataVariableSpeedCoils->VarSpeedCoil(state.dataWaterThermalTanks->HPWaterHeater(HPNum).DXCoilNum).NormSpedLevel,
   12216              :                         1.0,
   12217              :                         RhoWater,
   12218              :                         MdotWater,
   12219              :                         true);
   12220              :                     //       simulate the HPWH coil/fan to find heating capacity
   12221          768 :                     if (state.dataWaterThermalTanks->HPWaterHeater(HPNum).fanPlace == HVAC::FanPlace::BlowThru) {
   12222              :                         //   simulate fan and DX coil twice
   12223          576 :                         state.dataFans->fans(state.dataWaterThermalTanks->HPWaterHeater(HPNum).FanNum)->simulate(state, true, _, _);
   12224              : 
   12225          576 :                         VariableSpeedCoils::SimVariableSpeedCoils(
   12226              :                             state,
   12227              :                             VSCoilName,
   12228              :                             VSCoilNum,
   12229              :                             HVAC::FanOp::Cycling,
   12230              :                             HVAC::CompressorOp::On,
   12231              :                             1.0,
   12232          576 :                             state.dataVariableSpeedCoils->VarSpeedCoil(state.dataWaterThermalTanks->HPWaterHeater(HPNum).DXCoilNum).NormSpedLevel,
   12233              :                             1.0,
   12234              :                             0.0,
   12235              :                             0.0,
   12236              :                             1.0);
   12237              : 
   12238          576 :                         state.dataFans->fans(state.dataWaterThermalTanks->HPWaterHeater(HPNum).FanNum)->simulate(state, true, _, _);
   12239              : 
   12240          576 :                         VariableSpeedCoils::SimVariableSpeedCoils(
   12241              :                             state,
   12242              :                             VSCoilName,
   12243              :                             VSCoilNum,
   12244              :                             HVAC::FanOp::Cycling,
   12245              :                             HVAC::CompressorOp::On,
   12246              :                             1.0,
   12247          576 :                             state.dataVariableSpeedCoils->VarSpeedCoil(state.dataWaterThermalTanks->HPWaterHeater(HPNum).DXCoilNum).NormSpedLevel,
   12248              :                             1.0,
   12249              :                             0.0,
   12250              :                             0.0,
   12251              :                             1.0);
   12252              :                     } else {
   12253              :                         //   simulate DX coil and fan twice to pass fan power (FanElecPower) to DX coil
   12254          192 :                         VariableSpeedCoils::SimVariableSpeedCoils(
   12255              :                             state,
   12256              :                             VSCoilName,
   12257              :                             VSCoilNum,
   12258              :                             HVAC::FanOp::Cycling,
   12259              :                             HVAC::CompressorOp::On,
   12260              :                             1.0,
   12261          192 :                             state.dataVariableSpeedCoils->VarSpeedCoil(state.dataWaterThermalTanks->HPWaterHeater(HPNum).DXCoilNum).NormSpedLevel,
   12262              :                             1.0,
   12263              :                             0.0,
   12264              :                             0.0,
   12265              :                             1.0);
   12266              : 
   12267          192 :                         state.dataFans->fans(state.dataWaterThermalTanks->HPWaterHeater(HPNum).FanNum)->simulate(state, true, _, _);
   12268              : 
   12269          192 :                         VariableSpeedCoils::SimVariableSpeedCoils(
   12270              :                             state,
   12271              :                             VSCoilName,
   12272              :                             VSCoilNum,
   12273              :                             HVAC::FanOp::Cycling,
   12274              :                             HVAC::CompressorOp::On,
   12275              :                             1.0,
   12276          192 :                             state.dataVariableSpeedCoils->VarSpeedCoil(state.dataWaterThermalTanks->HPWaterHeater(HPNum).DXCoilNum).NormSpedLevel,
   12277              :                             1.0,
   12278              :                             0.0,
   12279              :                             0.0,
   12280              :                             1.0);
   12281              : 
   12282          192 :                         state.dataFans->fans(state.dataWaterThermalTanks->HPWaterHeater(HPNum).FanNum)->simulate(state, true, _, _);
   12283              :                     }
   12284              : 
   12285          768 :                     this->MaxCapacity = state.dataVariableSpeedCoils->VSHPWHHeatingCapacity;
   12286          768 :                     this->MinCapacity = state.dataVariableSpeedCoils->VSHPWHHeatingCapacity;
   12287          768 :                     this->Efficiency = state.dataVariableSpeedCoils->VSHPWHHeatingCOP;
   12288          768 :                 } else {
   12289         3024 :                     bIsVSCoil = false;
   12290              :                     //       simulate the HPWH coil/fan to find heating capacity
   12291         3024 :                     if (state.dataWaterThermalTanks->HPWaterHeater(HPNum).fanPlace == HVAC::FanPlace::BlowThru) {
   12292          720 :                         if (FirstTimeFlag) { // first time DXCoils::DXCoil is called, it's sized at the RatedCondenserWaterInlet temp, size and
   12293              :                                              // reset water inlet temp. If already sized, no harm.
   12294            7 :                             state.dataFans->fans(state.dataWaterThermalTanks->HPWaterHeater(HPNum).FanNum)->simulate(state, true, _, _);
   12295              : 
   12296           21 :                             DXCoils::SimDXCoil(state,
   12297            7 :                                                state.dataWaterThermalTanks->HPWaterHeater(HPNum).DXCoilName,
   12298              :                                                HVAC::CompressorOp::On,
   12299              :                                                true,
   12300            7 :                                                state.dataWaterThermalTanks->HPWaterHeater(HPNum).DXCoilNum,
   12301              :                                                HVAC::FanOp::Cycling,
   12302           14 :                                                1.0);
   12303            7 :                             state.dataLoopNodes->Node(state.dataWaterThermalTanks->HPWaterHeater(HPNum).CondWaterInletNode).Temp = this->TankTemp;
   12304              :                         }
   12305              :                         // ?? should only need to call twice if PLR<1 since this might affect OnOffFanPartLoadFraction which impacts fan energy.
   12306              :                         // PLR=1 here.
   12307          720 :                         state.dataFans->fans(state.dataWaterThermalTanks->HPWaterHeater(HPNum).FanNum)->simulate(state, true, _, _);
   12308              : 
   12309         2160 :                         DXCoils::SimDXCoil(state,
   12310          720 :                                            state.dataWaterThermalTanks->HPWaterHeater(HPNum).DXCoilName,
   12311              :                                            HVAC::CompressorOp::On,
   12312              :                                            true,
   12313          720 :                                            state.dataWaterThermalTanks->HPWaterHeater(HPNum).DXCoilNum,
   12314              :                                            HVAC::FanOp::Cycling,
   12315         1440 :                                            1.0);
   12316              : 
   12317          720 :                         state.dataFans->fans(state.dataWaterThermalTanks->HPWaterHeater(HPNum).FanNum)->simulate(state, true, _, _);
   12318              : 
   12319         2160 :                         DXCoils::SimDXCoil(state,
   12320          720 :                                            state.dataWaterThermalTanks->HPWaterHeater(HPNum).DXCoilName,
   12321              :                                            HVAC::CompressorOp::On,
   12322              :                                            true,
   12323          720 :                                            state.dataWaterThermalTanks->HPWaterHeater(HPNum).DXCoilNum,
   12324              :                                            HVAC::FanOp::Cycling,
   12325         1440 :                                            1.0);
   12326              :                     } else {
   12327         2304 :                         if (FirstTimeFlag) { // first time DXCoils::DXCoil is called, it's sized at the RatedCondenserWaterInlet temp, size and
   12328              :                                              // reset water inlet temp. If already sized, no harm.
   12329           27 :                             DXCoils::SimDXCoil(state,
   12330            9 :                                                state.dataWaterThermalTanks->HPWaterHeater(HPNum).DXCoilName,
   12331              :                                                HVAC::CompressorOp::On,
   12332              :                                                true,
   12333            9 :                                                state.dataWaterThermalTanks->HPWaterHeater(HPNum).DXCoilNum,
   12334              :                                                HVAC::FanOp::Cycling,
   12335           18 :                                                1.0);
   12336            9 :                             state.dataLoopNodes->Node(state.dataWaterThermalTanks->HPWaterHeater(HPNum).CondWaterInletNode).Temp = this->TankTemp;
   12337              :                         }
   12338              :                         // ?? should only need to call twice if PLR<1 since this might affect OnOffFanPartLoadFraction which impacts fan energy.
   12339              :                         // PLR=1 here.
   12340         6912 :                         DXCoils::SimDXCoil(state,
   12341         2304 :                                            state.dataWaterThermalTanks->HPWaterHeater(HPNum).DXCoilName,
   12342              :                                            HVAC::CompressorOp::On,
   12343              :                                            true,
   12344         2304 :                                            state.dataWaterThermalTanks->HPWaterHeater(HPNum).DXCoilNum,
   12345              :                                            HVAC::FanOp::Cycling,
   12346         4608 :                                            1.0);
   12347              : 
   12348         2304 :                         state.dataFans->fans(state.dataWaterThermalTanks->HPWaterHeater(HPNum).FanNum)->simulate(state, true, _, _);
   12349              : 
   12350         6912 :                         DXCoils::SimDXCoil(state,
   12351         2304 :                                            state.dataWaterThermalTanks->HPWaterHeater(HPNum).DXCoilName,
   12352              :                                            HVAC::CompressorOp::On,
   12353              :                                            true,
   12354         2304 :                                            state.dataWaterThermalTanks->HPWaterHeater(HPNum).DXCoilNum,
   12355              :                                            HVAC::FanOp::Cycling,
   12356         4608 :                                            1.0);
   12357              : 
   12358         2304 :                         state.dataFans->fans(state.dataWaterThermalTanks->HPWaterHeater(HPNum).FanNum)->simulate(state, true, _, _);
   12359              :                     }
   12360              : 
   12361         3024 :                     this->MaxCapacity = state.dataDXCoils->HPWHHeatingCapacity;
   12362         3024 :                     this->MinCapacity = state.dataDXCoils->HPWHHeatingCapacity;
   12363         3024 :                     this->Efficiency = state.dataDXCoils->HPWHHeatingCOP;
   12364              :                 }
   12365              : 
   12366         3792 :                 if (FirstTimeFlag) {
   12367           23 :                     RatedDXCoilTotalCapacity = state.dataHVACGlobal->DXCoilTotalCapacity;
   12368           23 :                     FirstTimeFlag = false;
   12369              :                 }
   12370              : 
   12371              :                 //       Switch the HPWH info with the tank info and call CalcWaterThermalTankMixed to get Standard Rating
   12372              :                 //       (backup element is assumed to be disabled during the rating procedure)
   12373         3792 :                 this->SourceMassFlowRate = 0.0;
   12374         3792 :                 this->OnCycParaLoad = state.dataWaterThermalTanks->HPWaterHeater(HPNum).OnCycParaLoad;
   12375         3792 :                 this->OffCycParaLoad = state.dataWaterThermalTanks->HPWaterHeater(HPNum).OffCycParaLoad;
   12376         3792 :                 this->OffCycParaFracToTank = 0.0;
   12377         3792 :                 this->OnCycParaFracToTank = 0.0;
   12378         3792 :                 this->PLFCurve = state.dataWaterThermalTanks->HPWaterHeater(HPNum).DXCoilPLFFPLR;
   12379              : 
   12380         3792 :                 if (this->WaterThermalTankType == DataPlant::PlantEquipmentType::WtrHeaterMixed) {
   12381         1200 :                     if (this->Efficiency > 0.0) {
   12382         1056 :                         this->CalcWaterThermalTankMixed(state);
   12383              :                     }
   12384              : 
   12385         2592 :                 } else if (this->WaterThermalTankType == DataPlant::PlantEquipmentType::WtrHeaterStratified) {
   12386         2592 :                     if (this->Efficiency > 0.0) {
   12387         2592 :                         this->CalcWaterThermalTankStratified(state);
   12388              :                     }
   12389              :                 }
   12390              : 
   12391              :                 //       reset the water heater data to original values
   12392         3792 :                 this->MaxCapacity = state.dataWaterThermalTanks->HPWaterHeater(HPNum).BackupElementCapacity;
   12393         3792 :                 this->MinCapacity = state.dataWaterThermalTanks->HPWaterHeater(HPNum).BackupElementCapacity;
   12394         3792 :                 this->Efficiency = state.dataWaterThermalTanks->HPWaterHeater(HPNum).BackupElementEfficiency;
   12395         3792 :                 this->OnCycParaLoad = state.dataWaterThermalTanks->HPWaterHeater(HPNum).WHOnCycParaLoad;
   12396         3792 :                 this->OffCycParaLoad = state.dataWaterThermalTanks->HPWaterHeater(HPNum).WHOffCycParaLoad;
   12397         3792 :                 this->OnCycParaFracToTank = state.dataWaterThermalTanks->HPWaterHeater(HPNum).WHOnCycParaFracToTank;
   12398         3792 :                 this->OffCycParaFracToTank = state.dataWaterThermalTanks->HPWaterHeater(HPNum).WHOffCycParaFracToTank;
   12399         3792 :                 this->PLFCurve = state.dataWaterThermalTanks->HPWaterHeater(HPNum).WHPLFCurve;
   12400              :             }
   12401              : 
   12402        23376 :             FuelEnergy_loc += (this->FuelRate + this->OffCycParaFuelRate + this->OnCycParaFuelRate) * SecInTimeStep;
   12403              : 
   12404              :         } // Step
   12405              : 
   12406          190 :         if (this->FirstRecoveryDone && this->FirstRecoveryFuel > 0.0) {
   12407              :             // Calculate Recovery Efficiency based on energy used to recover from the first draw
   12408              :             // FirstRecoveryFuel is recorded inside the CalcWaterThermalTank subroutine
   12409          172 :             RecoveryEfficiency = DrawMass * Psychrometrics::CPHW(57.2222) * (57.2222 - 14.4444) / this->FirstRecoveryFuel;
   12410              : 
   12411              :             // Calculate Energy Factor based on total energy (including parasitics) used over entire test
   12412          172 :             EnergyFactor = TotalDrawMass * Psychrometrics::CPHW(57.2222) * (57.2222 - 14.4444) / FuelEnergy_loc;
   12413              : 
   12414              :         } else {
   12415           18 :             RecoveryEfficiency = 0.0;
   12416           18 :             EnergyFactor = 0.0;
   12417              :             // If this a regular tank, or an HPWH that's not an Integrated one
   12418           18 :             if ((this->HeatPumpNum == 0) || !state.dataWaterThermalTanks->HPWaterHeater(this->HeatPumpNum).bIsIHP) {
   12419           34 :                 ShowWarningError(
   12420              :                     state,
   12421           34 :                     format("Water heater = {}:  Recovery Efficiency and Energy Factor could not be calculated during the test for standard ratings",
   12422           17 :                            this->Name));
   12423           51 :                 ShowContinueError(state, "Setpoint was never recovered and/or heater never turned on");
   12424              :             }
   12425              :         }
   12426              : 
   12427          190 :     } else {
   12428              : 
   12429              :         // Storage-only tank
   12430            5 :         RecoveryEfficiency = 0.0;
   12431            5 :         EnergyFactor = 0.0;
   12432              : 
   12433              :     } // WaterThermalTank(WaterThermalTankNum)%MaxCapacity > 0.0
   12434              : 
   12435              :     // create predefined report
   12436              :     // Store values for the input verification and summary report
   12437          195 :     std::string equipName;
   12438          195 :     if (this->HeatPumpNum == 0) {
   12439          172 :         equipName = this->Name;
   12440          172 :         OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchSWHType, equipName, this->Type);
   12441          172 :         OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchSWHVol, equipName, this->Volume);
   12442          172 :         OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchSWHHeatIn, equipName, this->MaxCapacity);
   12443          172 :         OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchSWHThEff, equipName, this->Efficiency);
   12444          172 :         OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchSWHRecEff, equipName, RecoveryEfficiency);
   12445          172 :         OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchSWHEnFac, equipName, EnergyFactor);
   12446              :     } else {
   12447           23 :         equipName = state.dataWaterThermalTanks->HPWaterHeater(this->HeatPumpNum).Name;
   12448           46 :         OutputReportPredefined::PreDefTableEntry(
   12449           46 :             state, state.dataOutRptPredefined->pdchSWHType, equipName, state.dataWaterThermalTanks->HPWaterHeater(this->HeatPumpNum).Type);
   12450           23 :         OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchSWHVol, equipName, this->Volume);
   12451           23 :         if (bIsVSCoil) {
   12452           21 :             OutputReportPredefined::PreDefTableEntry(
   12453           14 :                 state, state.dataOutRptPredefined->pdchSWHHeatIn, equipName, state.dataVariableSpeedCoils->VSHPWHHeatingCapacity);
   12454              :         } else {
   12455           48 :             OutputReportPredefined::PreDefTableEntry(
   12456           32 :                 state, state.dataOutRptPredefined->pdchSWHHeatIn, equipName, state.dataDXCoils->HPWHHeatingCapacity);
   12457              :         }
   12458           23 :         OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchSWHThEff, equipName, this->Efficiency);
   12459           23 :         OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchSWHRecEff, equipName, RecoveryEfficiency);
   12460           23 :         OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchSWHEnFac, equipName, EnergyFactor);
   12461              :     }
   12462              : 
   12463              :     // Write test results
   12464          195 :     if (this->HeatPumpNum == 0) {
   12465              :         Real64 MaxCapacity_loc;
   12466          172 :         if (this->WaterThermalTankType == DataPlant::PlantEquipmentType::WtrHeaterStratified) {
   12467            5 :             if (this->StratifiedControlMode == PriorityControlMode::MasterSlave) {
   12468            5 :                 MaxCapacity_loc = max(this->MaxCapacity, this->MaxCapacity2);
   12469              :             } else { // PrioritySimultaneous
   12470            0 :                 MaxCapacity_loc = this->MaxCapacity + this->MaxCapacity2;
   12471              :             }
   12472              :         } else { // WaterHeaterMixed
   12473          167 :             MaxCapacity_loc = this->MaxCapacity;
   12474              :         }
   12475              : 
   12476              :         static constexpr std::string_view Format_720("Water Heater Information,{},{},{:.4T},{:.1T},{:.3T},{:.4T}\n");
   12477          172 :         print(state.files.eio, Format_720, this->Type, this->Name, this->Volume, MaxCapacity_loc, RecoveryEfficiency, EnergyFactor);
   12478              :     } else {
   12479              :         static constexpr std::string_view Format_721("Heat Pump Water Heater Information,{},{},{:.4T},{:.1T},{:.3T},{:.4T},{:.0T}\n");
   12480           23 :         print(state.files.eio,
   12481              :               Format_721,
   12482           23 :               state.dataWaterThermalTanks->HPWaterHeater(this->HeatPumpNum).Type,
   12483           23 :               state.dataWaterThermalTanks->HPWaterHeater(this->HeatPumpNum).Name,
   12484           23 :               this->Volume,
   12485           23 :               state.dataDXCoils->HPWHHeatingCapacity,
   12486              :               RecoveryEfficiency,
   12487              :               EnergyFactor,
   12488              :               RatedDXCoilTotalCapacity);
   12489              :     }
   12490              : 
   12491          195 :     this->AlreadyRated = true;
   12492          195 : }
   12493              : 
   12494           10 : void WaterThermalTankData::ReportCWTankInits(EnergyPlusData &state)
   12495              : {
   12496              : 
   12497              :     // SUBROUTINE INFORMATION:
   12498              :     //       AUTHOR         B. Griffith
   12499              :     //       DATE WRITTEN   March 2009
   12500              :     //       MODIFIED       na
   12501              :     //       RE-ENGINEERED  na
   12502              : 
   12503              :     // PURPOSE OF THIS SUBROUTINE:
   12504              :     // send chilled water tank info to EIO
   12505              : 
   12506           10 :     if (this->myOneTimeInitFlag) {
   12507            0 :         this->setupOutputVars(state);
   12508            0 :         this->myOneTimeInitFlag = false;
   12509              :     }
   12510              : 
   12511           10 :     if (this->AlreadyReported) { // bail we already did this one
   12512            4 :         return;
   12513              :     }
   12514              : 
   12515              :     static constexpr std::string_view Format_728("Chilled Water Tank Information,{},{},{:.4T},{:.4T},{:.4T}\n");
   12516            6 :     print(state.files.eio, Format_728, this->Type, this->Name, this->Volume, this->UseDesignVolFlowRate, this->SourceDesignVolFlowRate);
   12517              : 
   12518            6 :     this->AlreadyReported = true;
   12519              : }
   12520              : 
   12521       801434 : Real64 WaterThermalTankData::FindStratifiedTankSensedTemp(EnergyPlusData &state, bool UseAverage)
   12522              : {
   12523              : 
   12524              :     // FUNCTION INFORMATION:
   12525              :     //       AUTHOR         B. Griffith
   12526              :     //       DATE WRITTEN   March 2012
   12527              :     //       MODIFIED       na
   12528              :     //       RE-ENGINEERED  Noel Merket, April 2015
   12529              : 
   12530              :     // PURPOSE OF THIS FUNCTION:
   12531              :     // find tank temperature depending on how sensed
   12532              : 
   12533              :     // FUNCTION LOCAL VARIABLE DECLARATIONS:
   12534       801434 :     HeatPumpWaterHeaterData const &HPWH = state.dataWaterThermalTanks->HPWaterHeater(this->HeatPumpNum);
   12535              :     Real64 ControlSensor1Temp;
   12536              :     Real64 ControlSensor2Temp;
   12537              : 
   12538       801434 :     if (UseAverage) {
   12539       199890 :         ControlSensor1Temp = this->Node(HPWH.ControlSensor1Node).TempAvg;
   12540       199890 :         ControlSensor2Temp = this->Node(HPWH.ControlSensor2Node).TempAvg;
   12541              :     } else {
   12542       601544 :         ControlSensor1Temp = this->Node(HPWH.ControlSensor1Node).Temp;
   12543       601544 :         ControlSensor2Temp = this->Node(HPWH.ControlSensor2Node).Temp;
   12544              :     }
   12545              : 
   12546       801434 :     Real64 SensedTemp = ControlSensor1Temp * HPWH.ControlSensor1Weight + ControlSensor2Temp * HPWH.ControlSensor2Weight;
   12547              : 
   12548       801434 :     return SensedTemp;
   12549              : }
   12550              : 
   12551      6551906 : Real64 WaterThermalTankData::getDeadBandTemp()
   12552              : {
   12553      6551906 :     if (this->IsChilledWaterTank) {
   12554       389660 :         return (this->SetPointTemp + this->DeadBandDeltaTemp);
   12555              :     } else {
   12556      6162246 :         return (this->SetPointTemp - this->DeadBandDeltaTemp);
   12557              :     }
   12558              : }
   12559      5928161 : void WaterThermalTankData::oneTimeInit(EnergyPlusData &state)
   12560              : {
   12561      5928161 :     if (this->myOneTimeInitFlag) {
   12562          178 :         this->setupOutputVars(state);
   12563          178 :         this->myOneTimeInitFlag = false;
   12564              :     }
   12565      5928161 : }
   12566              : 
   12567           30 : void WaterThermalTankData::setBackupElementCapacity(EnergyPlusData &state)
   12568              : {
   12569              :     // Fix for #9001: The BackupElementCapacity was not being reset from the autosize value (-99999) which resulted in
   12570              :     // negative electric consumption.  Using a test for any negative numbers here instead of just -99999 for safety.
   12571              :     // Only reset the backup element capacity if a problem has been occured.
   12572           30 :     if (this->HeatPumpNum > 0) {
   12573           20 :         if (state.dataWaterThermalTanks->HPWaterHeater(this->HeatPumpNum).HPWHType == DataPlant::PlantEquipmentType::HeatPumpWtrHeaterWrapped) {
   12574           20 :             return;
   12575              :         }
   12576            0 :         if (state.dataWaterThermalTanks->HPWaterHeater(this->HeatPumpNum).BackupElementCapacity < 0.0) {
   12577            0 :             state.dataWaterThermalTanks->HPWaterHeater(this->HeatPumpNum).BackupElementCapacity = this->MaxCapacity;
   12578              :         }
   12579           10 :     } else if (this->DesuperheaterNum > 0) {
   12580            0 :         if (state.dataWaterThermalTanks->WaterHeaterDesuperheater(this->DesuperheaterNum).BackupElementCapacity < 0.0) {
   12581            0 :             state.dataWaterThermalTanks->WaterHeaterDesuperheater(this->DesuperheaterNum).BackupElementCapacity = this->MaxCapacity;
   12582              :         }
   12583              :     }
   12584              : }
   12585              : 
   12586           16 : bool GetHeatPumpWaterHeaterNodeNumber(EnergyPlusData &state, int const NodeNumber)
   12587              : {
   12588              :     // PURPOSE OF THIS FUNCTION:
   12589              :     // Check if a node is used by a heat pump water heater
   12590              :     // and can be excluded from an airflow network.
   12591              : 
   12592              :     // Return value
   12593              :     bool HeatPumpWaterHeaterNodeException;
   12594              : 
   12595              :     int HeatPumpWaterHeaterIndex;
   12596              : 
   12597           16 :     if (state.dataWaterThermalTanks->getWaterThermalTankInputFlag) {
   12598            0 :         GetWaterThermalTankInput(state);
   12599            0 :         state.dataWaterThermalTanks->getWaterThermalTankInputFlag = false;
   12600              :     }
   12601              : 
   12602           16 :     HeatPumpWaterHeaterNodeException = false;
   12603              : 
   12604           26 :     for (HeatPumpWaterHeaterIndex = 1; HeatPumpWaterHeaterIndex <= state.dataWaterThermalTanks->numHeatPumpWaterHeater; ++HeatPumpWaterHeaterIndex) {
   12605              : 
   12606              :         // Get heat pump water heater data
   12607           16 :         HeatPumpWaterHeaterData &HPWH = state.dataWaterThermalTanks->HPWaterHeater(HeatPumpWaterHeaterIndex);
   12608              : 
   12609              :         // "Zone and outdoor air" configuration is expected break the conservation of mass
   12610           16 :         if (HPWH.InletAirConfiguration != WTTAmbientTemp::ZoneAndOA) {
   12611              : 
   12612              :             // Air outlet node
   12613           16 :             if (NodeNumber == HPWH.HeatPumpAirOutletNode) {
   12614            2 :                 HeatPumpWaterHeaterNodeException = true;
   12615            2 :                 break;
   12616              :             }
   12617              : 
   12618              :             // Air inlet node
   12619           14 :             if (NodeNumber == HPWH.HeatPumpAirInletNode) {
   12620            2 :                 HeatPumpWaterHeaterNodeException = true;
   12621            2 :                 break;
   12622              :             }
   12623              : 
   12624              :             // Get fan inlet node index
   12625           12 :             int FanInletNodeIndex = state.dataFans->fans(HPWH.FanNum)->inletNodeNum;
   12626              : 
   12627              :             // Fan inlet node
   12628           12 :             if (NodeNumber == FanInletNodeIndex) {
   12629            2 :                 HeatPumpWaterHeaterNodeException = true;
   12630            2 :                 break;
   12631              :             }
   12632              : 
   12633              :             // Fan outlet node
   12634           10 :             if (NodeNumber == HPWH.FanOutletNode) {
   12635            0 :                 HeatPumpWaterHeaterNodeException = true;
   12636            0 :                 break;
   12637              :             }
   12638              : 
   12639              :             // Outside air node
   12640           10 :             if (NodeNumber == HPWH.OutsideAirNode) {
   12641            0 :                 HeatPumpWaterHeaterNodeException = true;
   12642            0 :                 break;
   12643              :             }
   12644              : 
   12645              :             // Exhaust air node
   12646           10 :             if (NodeNumber == HPWH.ExhaustAirNode) {
   12647            0 :                 HeatPumpWaterHeaterNodeException = true;
   12648            0 :                 break;
   12649              :             }
   12650              :         }
   12651              :     }
   12652              : 
   12653           16 :     return HeatPumpWaterHeaterNodeException;
   12654              : }
   12655              : 
   12656            0 : int getHeatPumpWaterHeaterIndex(EnergyPlusData &state, std::string_view CompName)
   12657              : {
   12658            0 :     if (state.dataWaterThermalTanks->getWaterThermalTankInputFlag) {
   12659            0 :         GetWaterThermalTankInput(state);
   12660            0 :         state.dataWaterThermalTanks->getWaterThermalTankInputFlag = false;
   12661              :     }
   12662              : 
   12663            0 :     for (int HPNum = 1; HPNum <= state.dataWaterThermalTanks->numHeatPumpWaterHeater; ++HPNum) {
   12664            0 :         if (Util::SameString(state.dataWaterThermalTanks->HPWaterHeater(HPNum).Name, CompName)) {
   12665            0 :             return HPNum;
   12666              :         }
   12667              :     }
   12668              : 
   12669            0 :     return 0;
   12670              : }
   12671              : 
   12672              : } // namespace EnergyPlus::WaterThermalTanks
        

Generated by: LCOV version 2.0-1