LCOV - code coverage report
Current view: top level - EnergyPlus - WaterThermalTanks.cc (source / functions) Hit Total Coverage
Test: lcov.output.filtered Lines: 4474 6666 67.1 %
Date: 2024-08-23 23:50:59 Functions: 65 70 92.9 %

          Line data    Source code
       1             : // EnergyPlus, Copyright (c) 1996-2024, 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             : std::string const fluidNameWater = "WATER";
     135             : 
     136         142 : PlantComponent *WaterThermalTankData::factory(EnergyPlusData &state, std::string const &objectName)
     137             : {
     138             :     // Process the input data
     139         142 :     if (state.dataWaterThermalTanks->getWaterThermalTankInputFlag) {
     140          10 :         GetWaterThermalTankInput(state);
     141          10 :         state.dataWaterThermalTanks->getWaterThermalTankInputFlag = false;
     142             :     }
     143             : 
     144             :     // Now look for this object in the list
     145         163 :     for (auto &tank : state.dataWaterThermalTanks->WaterThermalTank) {
     146         163 :         if (tank.Name == objectName) {
     147         142 :             return &tank;
     148             :         }
     149             :     }
     150             :     // If we didn't find it, fatal
     151             :     ShowFatalError(state, format("LocalWaterTankFactory: Error getting inputs for tank named: {}", objectName)); // LCOV_EXCL_LINE
     152             :     // Shut up the compiler
     153             :     return nullptr; // LCOV_EXCL_LINE
     154             : }
     155             : 
     156         771 : void WaterThermalTankData::onInitLoopEquip(EnergyPlusData &state, const PlantLocation &calledFromLocation)
     157             : {
     158         771 :     this->initialize(state, true);
     159         771 :     this->MinePlantStructForInfo(state);
     160         771 :     if (calledFromLocation.loopNum > 0) {
     161         771 :         if ((this->SrcSidePlantLoc.loopNum == calledFromLocation.loopNum) || (this->UseSidePlantLoc.loopNum == calledFromLocation.loopNum)) {
     162         766 :             this->SizeTankForDemandSide(state);
     163         766 :             this->SizeDemandSidePlantConnections(state);
     164         766 :             this->SizeSupplySidePlantConnections(state, calledFromLocation.loopNum);
     165         766 :             this->SizeTankForSupplySide(state);
     166             :         } else {
     167           5 :             return;
     168             :         }
     169             :     } else {
     170           0 :         this->SizeTankForDemandSide(state);
     171           0 :         this->SizeDemandSidePlantConnections(state);
     172           0 :         this->SizeSupplySidePlantConnections(state, this->SrcSidePlantLoc.loopNum);
     173           0 :         this->SizeTankForSupplySide(state);
     174             :     }
     175             : 
     176         766 :     if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
     177         166 :         if (!this->IsChilledWaterTank) {
     178         156 :             this->CalcStandardRatings(state);
     179             :         } else {
     180          10 :             this->ReportCWTankInits(state);
     181             :         }
     182             :     }
     183             : }
     184             : 
     185         721 : void WaterThermalTankData::getDesignCapacities([[maybe_unused]] EnergyPlusData &state,
     186             :                                                [[maybe_unused]] const PlantLocation &calledFromLocation,
     187             :                                                Real64 &MaxLoad,
     188             :                                                Real64 &MinLoad,
     189             :                                                Real64 &OptLoad)
     190             : {
     191         721 :     MinLoad = 0.0;
     192         721 :     MaxLoad = this->MaxCapacity;
     193         721 :     OptLoad = this->MaxCapacity;
     194         721 : }
     195             : 
     196           0 : int getTankIDX(EnergyPlusData &state, std::string_view CompName, int &CompIndex)
     197             : {
     198           0 :     if (state.dataWaterThermalTanks->getWaterThermalTankInputFlag) {
     199           0 :         GetWaterThermalTankInput(state);
     200           0 :         state.dataWaterThermalTanks->getWaterThermalTankInputFlag = false;
     201             :     }
     202             : 
     203             :     int CompNum;
     204             : 
     205           0 :     if (CompIndex == 0) {
     206           0 :         CompNum = Util::FindItem(CompName, state.dataWaterThermalTanks->WaterThermalTank);
     207           0 :         if (CompNum == 0) {
     208           0 :             ShowFatalError(state, format("SimWaterThermalTank_WaterTank:  Unit not found={}", CompName));
     209             :         }
     210           0 :         CompIndex = CompNum;
     211             :     } else {
     212           0 :         CompNum = CompIndex;
     213           0 :         if (CompNum > state.dataWaterThermalTanks->numWaterThermalTank || CompNum < 1) {
     214           0 :             ShowFatalError(state,
     215           0 :                            format("SimWaterThermalTank_WaterTank:  Invalid CompIndex passed={}, Number of Units={}, Entered Unit name={}",
     216             :                                   CompNum,
     217           0 :                                   state.dataWaterThermalTanks->numWaterThermalTank,
     218             :                                   CompName));
     219             :         }
     220           0 :         if (state.dataWaterThermalTanks->WaterThermalTank(CompNum).CheckWTTEquipName) {
     221           0 :             if (CompName != state.dataWaterThermalTanks->WaterThermalTank(CompNum).Name) {
     222           0 :                 ShowFatalError(state,
     223           0 :                                format("SimWaterThermalTank_WaterTank: Invalid CompIndex passed={}, Unit name={}, stored Unit Name for that index={}",
     224             :                                       CompNum,
     225             :                                       CompName,
     226           0 :                                       state.dataWaterThermalTanks->WaterThermalTank(CompNum).Name));
     227             :             }
     228           0 :             state.dataWaterThermalTanks->WaterThermalTank(CompNum).CheckWTTEquipName = false;
     229             :         }
     230             :     }
     231             : 
     232           0 :     return CompNum;
     233             : }
     234             : 
     235        5022 : int getHPTankIDX(EnergyPlusData &state, std::string_view CompName, int &CompIndex)
     236             : {
     237        5022 :     if (state.dataWaterThermalTanks->getWaterThermalTankInputFlag) {
     238           0 :         GetWaterThermalTankInput(state);
     239           0 :         state.dataWaterThermalTanks->getWaterThermalTankInputFlag = false;
     240             :     }
     241             : 
     242             :     int CompNum;
     243             : 
     244        5022 :     if (CompIndex == 0) {
     245           0 :         CompNum = Util::FindItem(CompName, state.dataWaterThermalTanks->HPWaterHeater);
     246           0 :         if (CompNum == 0) {
     247           0 :             ShowFatalError(state, format("SimWaterThermalTank_HeatPump:  Unit not found={}", CompName));
     248             :         }
     249           0 :         CompIndex = CompNum;
     250             :     } else {
     251        5022 :         CompNum = CompIndex;
     252        5022 :         if (CompNum > state.dataWaterThermalTanks->numWaterThermalTank || CompNum < 1) {
     253           0 :             ShowFatalError(state,
     254           0 :                            format("SimWaterThermalTank_HeatPump:  Invalid CompIndex passed={}, Number of Units={}, Entered Unit name={}",
     255             :                                   CompNum,
     256           0 :                                   state.dataWaterThermalTanks->numHeatPumpWaterHeater,
     257             :                                   CompName));
     258             :         }
     259        5022 :         if (state.dataWaterThermalTanks->HPWaterHeater(CompNum).CheckHPWHEquipName) {
     260           1 :             if (CompName != state.dataWaterThermalTanks->HPWaterHeater(CompNum).Name) {
     261           0 :                 ShowFatalError(state,
     262           0 :                                format("SimWaterThermalTank_HeatPump: Invalid CompIndex passed={}, Unit name={}, stored Unit Name for that index={}",
     263             :                                       CompNum,
     264             :                                       CompName,
     265           0 :                                       state.dataWaterThermalTanks->HPWaterHeater(CompNum).Name));
     266             :             }
     267           1 :             state.dataWaterThermalTanks->HPWaterHeater(CompNum).CheckHPWHEquipName = false;
     268             :         }
     269             :     }
     270             : 
     271        5022 :     return CompNum;
     272             : }
     273             : 
     274     5835179 : void WaterThermalTankData::simulate(
     275             :     EnergyPlusData &state, const PlantLocation &calledFromLocation, bool FirstHVACIteration, Real64 &CurLoad, [[maybe_unused]] bool RunFlag)
     276             : {
     277             :     // SUBROUTINE INFORMATION:
     278             :     //       AUTHOR         Brandon Anderson
     279             :     //       DATE WRITTEN   May 2000
     280             :     //       MODIFIED       FSEC, July 2005
     281             :     //       RE-ENGINEERED  na
     282             : 
     283             :     // set the caller loop num to mimic what was happening in plant loop equip
     284     5835179 :     this->callerLoopNum = calledFromLocation.loopNum;
     285             : 
     286     5835179 :     this->oneTimeInit(state);
     287             : 
     288     5835179 :     if (this->MyOneTimeFlagWH) {
     289         174 :         this->MyOneTimeFlagWH = false;
     290             :     } else {
     291     5835005 :         if (this->MyTwoTimeFlagWH) {
     292         174 :             this->MinePlantStructForInfo(state); // call it again to get control types filled out
     293         174 :             this->MyTwoTimeFlagWH = false;
     294             :         }
     295             :     }
     296     5835179 :     this->UseSideLoadRequested = std::abs(CurLoad);
     297    11338444 :     if (this->UseSidePlantLoc.loopNum > 0 && this->UseSidePlantLoc.loopSideNum != DataPlant::LoopSideLocation::Invalid &&
     298     5503265 :         !state.dataGlobal->KickOffSimulation) {
     299     5482664 :         this->UseCurrentFlowLock = state.dataPlnt->PlantLoop(this->UseSidePlantLoc.loopNum).LoopSide(this->UseSidePlantLoc.loopSideNum).FlowLock;
     300             :     } else {
     301      352515 :         this->UseCurrentFlowLock = DataPlant::FlowLock::Locked;
     302             :     }
     303     5835179 :     this->initialize(state, FirstHVACIteration);
     304             :     //       Plant connected water heaters may have a desuperheater heating coil attached
     305     5835179 :     if (this->DesuperheaterNum == 0) {
     306     5805695 :         if ((this->WaterThermalTankType == DataPlant::PlantEquipmentType::WtrHeaterMixed) ||
     307      656022 :             (this->WaterThermalTankType == DataPlant::PlantEquipmentType::ChilledWaterTankMixed)) {
     308     5547453 :             this->CalcWaterThermalTankMixed(state);
     309      258242 :         } else if ((this->WaterThermalTankType == DataPlant::PlantEquipmentType::WtrHeaterStratified) ||
     310      175445 :                    (this->WaterThermalTankType == DataPlant::PlantEquipmentType::ChilledWaterTankStratified)) {
     311      258242 :             this->CalcWaterThermalTankStratified(state);
     312             :         }
     313       29484 :     } else if (this->DesuperheaterNum > 0) {
     314       29484 :         this->CalcDesuperheaterWaterHeater(state, FirstHVACIteration);
     315             :     }
     316     5835179 :     this->UpdateWaterThermalTank(state);
     317     5835179 :     this->ReportWaterThermalTank(state);
     318             :     // reset the caller loop num to mimic what was happening in PlantLoopEquip
     319     5835179 :     this->callerLoopNum = 0;
     320     5835179 : }
     321             : 
     322          10 : PlantComponent *HeatPumpWaterHeaterData::factory(EnergyPlusData &state, std::string const &objectName)
     323             : {
     324             :     // Process the input data
     325          10 :     if (state.dataWaterThermalTanks->getWaterThermalTankInputFlag) {
     326           3 :         GetWaterThermalTankInput(state);
     327           3 :         state.dataWaterThermalTanks->getWaterThermalTankInputFlag = false;
     328             :     }
     329             : 
     330             :     // Now look for this object in the list
     331          28 :     for (auto &HPWH : state.dataWaterThermalTanks->HPWaterHeater) {
     332          28 :         if (HPWH.Name == objectName) {
     333          10 :             return &HPWH;
     334             :         }
     335             :     }
     336             :     // If we didn't find it, fatal
     337             :     ShowFatalError(state, format("LocalHeatPumpWaterHeaterFactory: Error getting inputs for object named: {}", objectName)); // LCOV_EXCL_LINE
     338             :     // Shut up the compiler
     339             :     return nullptr; // LCOV_EXCL_LINE
     340             : }
     341             : 
     342          50 : void HeatPumpWaterHeaterData::onInitLoopEquip(EnergyPlusData &state, const PlantLocation &calledFromLocation)
     343             : {
     344          50 :     auto &Tank = state.dataWaterThermalTanks->WaterThermalTank(this->WaterHeaterTankNum);
     345          50 :     Tank.onInitLoopEquip(state, calledFromLocation);
     346          50 : }
     347             : 
     348          50 : void HeatPumpWaterHeaterData::getDesignCapacities([[maybe_unused]] EnergyPlusData &state,
     349             :                                                   [[maybe_unused]] const PlantLocation &calledFromLocation,
     350             :                                                   Real64 &MaxLoad,
     351             :                                                   Real64 &MinLoad,
     352             :                                                   Real64 &OptLoad)
     353             : {
     354          50 :     MinLoad = 0.0;
     355          50 :     MaxLoad = this->Capacity;
     356          50 :     OptLoad = this->Capacity;
     357          50 : }
     358             : 
     359      448686 : void HeatPumpWaterHeaterData::simulate(
     360             :     EnergyPlusData &state, const PlantLocation &calledFromLocation, bool FirstHVACIteration, Real64 &CurLoad, [[maybe_unused]] bool RunFlag)
     361             : {
     362             :     // SUBROUTINE INFORMATION:
     363             :     //       AUTHOR         Brandon Anderson
     364             :     //       DATE WRITTEN   May 2000
     365             :     //       MODIFIED       FSEC, July 2005
     366             :     //       RE-ENGINEERED  na
     367             : 
     368      448686 :     auto &Tank = state.dataWaterThermalTanks->WaterThermalTank(this->WaterHeaterTankNum);
     369             : 
     370             :     // set caller loop num to mimic what plantloopequip was doing
     371      448686 :     Tank.callerLoopNum = calledFromLocation.loopNum;
     372             : 
     373      448686 :     if (this->myOneTimeInitFlag) {
     374          23 :         if (Tank.myOneTimeInitFlag) {
     375          23 :             Tank.setupOutputVars(state);
     376          23 :             Tank.myOneTimeInitFlag = false;
     377             :         }
     378          23 :         this->myOneTimeInitFlag = false;
     379             :     }
     380             : 
     381      448686 :     if (this->MyOneTimeFlagHP) {
     382          23 :         this->MyOneTimeFlagHP = false;
     383             :     } else {
     384      448663 :         if (this->MyTwoTimeFlagHP) {
     385          23 :             Tank.MinePlantStructForInfo(state); // call it again to get control types filled out
     386          23 :             this->MyTwoTimeFlagHP = false;
     387             :         }
     388             :     }
     389      448686 :     Tank.UseSideLoadRequested = std::abs(CurLoad);
     390      808640 :     if (Tank.UseSidePlantLoc.loopNum > 0 && Tank.UseSidePlantLoc.loopSideNum != DataPlant::LoopSideLocation::Invalid &&
     391      359954 :         !state.dataGlobal->KickOffSimulation) {
     392      358574 :         Tank.UseCurrentFlowLock = state.dataPlnt->PlantLoop(Tank.UseSidePlantLoc.loopNum).LoopSide(Tank.UseSidePlantLoc.loopSideNum).FlowLock;
     393             :     } else {
     394       90112 :         Tank.UseCurrentFlowLock = DataPlant::FlowLock::Locked;
     395             :     }
     396             : 
     397      448686 :     Tank.initialize(state, FirstHVACIteration);
     398             : 
     399      448686 :     int InletNodeSav = this->HeatPumpAirInletNode;
     400      448686 :     int OutletNodeSav = this->HeatPumpAirOutletNode;
     401      448686 :     int DXINletNodeSav = this->DXCoilAirInletNode;
     402      448686 :     int IHPFanIndexSav = this->FanNum;
     403      448686 :     std::string IHPFanNameSave = this->FanName;
     404      448686 :     HVAC::FanPlace IHPFanplaceSav = this->fanPlace;
     405             : 
     406      448686 :     if (this->bIsIHP) // pass the tank indexes to the IHP object
     407             :     {
     408       10046 :         state.dataIntegratedHP->IntegratedHeatPumps(this->DXCoilNum).WHtankType = this->HPWHType;
     409       10046 :         state.dataIntegratedHP->IntegratedHeatPumps(this->DXCoilNum).WHtankName = this->Name;
     410       10046 :         state.dataIntegratedHP->IntegratedHeatPumps(this->DXCoilNum).WHtankID = this->WaterHeaterTankNum;
     411       10046 :         IntegratedHeatPump::IHPOperationMode IHPMode = IntegratedHeatPump::GetCurWorkMode(state, this->DXCoilNum);
     412             : 
     413       10046 :         if ((IntegratedHeatPump::IHPOperationMode::DedicatedWaterHtg == IHPMode) ||
     414        7643 :             (IntegratedHeatPump::IHPOperationMode::SpaceClgDedicatedWaterHtg == IHPMode) ||
     415        7643 :             (IntegratedHeatPump::IHPOperationMode::SHDWHElecHeatOff == IHPMode) ||
     416             :             (IntegratedHeatPump::IHPOperationMode::SHDWHElecHeatOn == IHPMode)) { // default is to specify the air nodes for SCWH mode
     417        2403 :             bool bDWHCoilReading = false;
     418        2403 :             this->HeatPumpAirInletNode =
     419        2403 :                 VariableSpeedCoils::GetCoilInletNodeVariableSpeed(state,
     420             :                                                                   "COIL:WATERHEATING:AIRTOWATERHEATPUMP:VARIABLESPEED",
     421        2403 :                                                                   state.dataIntegratedHP->IntegratedHeatPumps(this->DXCoilNum).DWHCoilName,
     422             :                                                                   bDWHCoilReading);
     423        2403 :             this->HeatPumpAirOutletNode =
     424        2403 :                 VariableSpeedCoils::GetCoilOutletNodeVariableSpeed(state,
     425             :                                                                    "COIL:WATERHEATING:AIRTOWATERHEATPUMP:VARIABLESPEED",
     426        2403 :                                                                    state.dataIntegratedHP->IntegratedHeatPumps(this->DXCoilNum).DWHCoilName,
     427             :                                                                    bDWHCoilReading);
     428        2403 :             this->DXCoilAirInletNode = this->HeatPumpAirInletNode;
     429        2403 :         } else // default is to input outdoor fan to the HPWH
     430             :         {
     431        7643 :             this->FanNum = state.dataIntegratedHP->IntegratedHeatPumps(this->DXCoilNum).IDFanID;
     432        7643 :             this->FanName = state.dataIntegratedHP->IntegratedHeatPumps(this->DXCoilNum).IDFanName;
     433        7643 :             this->fanPlace = state.dataIntegratedHP->IntegratedHeatPumps(this->DXCoilNum).fanPlace;
     434             :         }
     435             :     }
     436             : 
     437      448686 :     Tank.CalcHeatPumpWaterHeater(state, FirstHVACIteration);
     438      448686 :     Tank.UpdateWaterThermalTank(state);
     439      448686 :     Tank.ReportWaterThermalTank(state);
     440             : 
     441      448686 :     this->HeatPumpAirInletNode = InletNodeSav;
     442      448686 :     this->HeatPumpAirOutletNode = OutletNodeSav;
     443      448686 :     this->DXCoilAirInletNode = DXINletNodeSav;
     444      448686 :     this->FanNum = IHPFanIndexSav;
     445      448686 :     this->FanName = IHPFanNameSave;
     446      448686 :     this->fanPlace = IHPFanplaceSav;
     447             :     // reset caller loop num to 0 to mimic what plantloopequip was doing
     448      448686 :     Tank.callerLoopNum = 0;
     449      448686 : }
     450           0 : void HeatPumpWaterHeaterData::oneTimeInit([[maybe_unused]] EnergyPlusData &state)
     451             : {
     452           0 : }
     453             : 
     454     1397102 : void SimulateWaterHeaterStandAlone(EnergyPlusData &state, int const WaterHeaterNum, bool const FirstHVACIteration)
     455             : {
     456             : 
     457             :     // SUBROUTINE INFORMATION:
     458             :     //       AUTHOR         Peter Graham Ellis
     459             :     //       DATE WRITTEN   January 2004
     460             :     //       MODIFIED       July 2005, FSEC - added HPWHs and desuperheater water heating coils
     461             :     //       RE-ENGINEERED  na
     462             : 
     463             :     // PURPOSE OF THIS SUBROUTINE:
     464             :     // This subroutine acts an interface to SimWaterHeater for stand-alone water heaters with no plant connections,
     465             :     // HPWHs not defined as zone equipment with no plant connections, and stand-alone water heaters with
     466             :     // desuperheater heating coils with no plant connections.
     467             : 
     468             :     // METHODOLOGY EMPLOYED:
     469             :     // The necessary control flags and dummy variables are set and passed into SimWaterHeater. This subroutine is
     470             :     // called from NonZoneEquipmentManager.
     471             : 
     472             :     Real64 MyLoad;
     473             : 
     474     1397102 :     if (state.dataWaterThermalTanks->getWaterThermalTankInputFlag) {
     475           7 :         GetWaterThermalTankInput(state);
     476           7 :         state.dataWaterThermalTanks->getWaterThermalTankInputFlag = false;
     477             :     }
     478             : 
     479     1397102 :     auto &Tank = state.dataWaterThermalTanks->WaterThermalTank(WaterHeaterNum);
     480             : 
     481             :     // Only simulate stand-alone water heaters here.  Plant connected water heaters are called by the PlantLoopEquipments.
     482     1397102 :     if (Tank.StandAlone) {
     483      289134 :         bool localRunFlag = true;
     484      289134 :         PlantLocation A(0, DataPlant::LoopSideLocation::Invalid, 0, 0);
     485      289134 :         Tank.simulate(state, A, FirstHVACIteration, MyLoad, localRunFlag);
     486             : 
     487             :         // HPWHs with inlet air from a zone and not connected to a plant loop are simulated through a CALL from ZoneEquipmentManager.
     488             :         // HPWHs that are plant connected are always simulated through a CALL from PlantLoopEquipments directly to SimWaterThermalTank.
     489             : 
     490             :         // NOTE: HPWHs with inlet air from a zone AND plant connected are not stand alone and are simulated in PlantLoopEquipments
     491     1107968 :     } else if (Tank.HeatPumpNum > 0) {
     492             :         //   Only HPWHs with inlet air from outdoors or scheduled HPWHs (not connected to a plant loop) are simulated here.
     493             : 
     494      141406 :         auto &HPWaterHtr = state.dataWaterThermalTanks->HPWaterHeater(Tank.HeatPumpNum);
     495             : 
     496      141406 :         if (HPWaterHtr.StandAlone &&
     497       82280 :             (HPWaterHtr.InletAirConfiguration == WTTAmbientTemp::OutsideAir || HPWaterHtr.InletAirConfiguration == WTTAmbientTemp::Schedule)) {
     498       43652 :             bool LocalRunFlag = true;
     499       43652 :             PlantLocation A(0, DataPlant::LoopSideLocation::Invalid, 0, 0);
     500       43652 :             HPWaterHtr.simulate(state, A, FirstHVACIteration, MyLoad, LocalRunFlag);
     501             :         }
     502             : 
     503             :         // Only simulate stand-alone water heaters with desuperheater water heating coils here.  Plant connected water heaters
     504             :         // with desuperheater water heating coils are called by PlantLoopEquipments.
     505      966562 :     } else if (Tank.DesuperheaterNum > 0) {
     506       29484 :         if (state.dataWaterThermalTanks->WaterHeaterDesuperheater(Tank.DesuperheaterNum).StandAlone) {
     507       29484 :             bool localRunFlag = true;
     508       29484 :             PlantLocation A(0, DataPlant::LoopSideLocation::Invalid, 0, 0);
     509       29484 :             Tank.simulate(state, A, FirstHVACIteration, MyLoad, localRunFlag);
     510             :         }
     511             :     }
     512     1397102 : }
     513             : 
     514      132563 : void SimHeatPumpWaterHeater(EnergyPlusData &state,
     515             :                             std::string_view CompName,
     516             :                             bool const FirstHVACIteration,
     517             :                             Real64 &SensLoadMet, // sensible load met by this equipment and sent to zone, W
     518             :                             Real64 &LatLoadMet,  // net latent load met and sent to zone (kg/s), dehumid = negative
     519             :                             int &CompIndex)
     520             : {
     521             :     // SUBROUTINE INFORMATION:
     522             :     //       AUTHOR         Richard Raustad
     523             :     //       DATE WRITTEN   April 2005
     524             :     //       MODIFIED       Don Shirey, Aug 2009 (LatLoadMet)
     525             :     //       RE-ENGINEERED  na
     526             : 
     527             :     // PURPOSE OF THIS SUBROUTINE:
     528             :     // This subroutine acts as an interface to SimWaterHeater.
     529             :     // HPWHs defined as zone equipment and not connected to a plant loop are called here by ZoneEquipmentManager
     530             : 
     531             :     // METHODOLOGY EMPLOYED:
     532             :     // The necessary control flags and dummy variables are set and passed into SimWaterHeater.
     533             : 
     534      132563 :     if (state.dataWaterThermalTanks->getWaterThermalTankInputFlag) {
     535           0 :         GetWaterThermalTankInput(state);
     536           0 :         state.dataWaterThermalTanks->getWaterThermalTankInputFlag = false;
     537             :     }
     538             : 
     539             :     // Find the correct Heat Pump Water Heater
     540             :     int HeatPumpNum;
     541      132563 :     if (CompIndex == 0) {
     542          10 :         HeatPumpNum = Util::FindItemInList(CompName, state.dataWaterThermalTanks->HPWaterHeater);
     543          10 :         if (HeatPumpNum == 0) {
     544           0 :             ShowFatalError(state, format("SimHeatPumpWaterHeater: Unit not found={}", CompName));
     545             :         }
     546          10 :         CompIndex = HeatPumpNum;
     547             :     } else {
     548      132553 :         HeatPumpNum = CompIndex;
     549      132553 :         if (HeatPumpNum > state.dataWaterThermalTanks->numHeatPumpWaterHeater || HeatPumpNum < 1) {
     550           0 :             ShowFatalError(state,
     551           0 :                            format("SimHeatPumpWaterHeater:  Invalid CompIndex passed={}, Number of Units={}, Entered Unit name={}",
     552             :                                   HeatPumpNum,
     553           0 :                                   state.dataWaterThermalTanks->numHeatPumpWaterHeater,
     554             :                                   CompName));
     555             :         }
     556             :     }
     557             : 
     558             :     // Only simulate HPWHs specified as zone equipment and not connected to a plant loop.
     559             :     // HPWHs not defined as zone equipment with no plant connections are simulated in NonZoneEquipmentManager.
     560             :     // Plant connected HPWHs are called by PlantLoopEquipments (but only those on supply side ).
     561             :     // HPWH will not be included in sizing calculations, fan is initialized only during BeginEnvrnFlag (FALSE during sizing)
     562             :     // (fan will be turned off during Standard Ratings procedure yielding incorrect results)
     563      132563 :     if (state.dataGlobal->DoingSizing) return;
     564             : 
     565             :     // For HPWHs, StandAlone means not connected to a plant loop (use nodes are not used, source nodes are connected to a HPWH)
     566      132553 :     if (state.dataWaterThermalTanks->HPWaterHeater(HeatPumpNum).StandAlone) {
     567       40058 :         bool LocalRunFlag = true;
     568             :         Real64 MyLoad;
     569             : 
     570       40058 :         PlantLocation A(0, DataPlant::LoopSideLocation::Invalid, 0, 0);
     571       40058 :         state.dataWaterThermalTanks->HPWaterHeater(HeatPumpNum).simulate(state, A, FirstHVACIteration, MyLoad, LocalRunFlag);
     572             : 
     573       40058 :         SensLoadMet = state.dataWaterThermalTanks->HPWaterHeater(HeatPumpNum).HPWaterHeaterSensibleCapacity;
     574       40058 :         LatLoadMet = state.dataWaterThermalTanks->HPWaterHeater(HeatPumpNum).HPWaterHeaterLatentCapacity;
     575             :     } else {
     576             :         // HPWH is plant connected and will get simulated when called from plant SimWaterThermalTank, but need to update loads met here
     577       92495 :         SensLoadMet = state.dataWaterThermalTanks->HPWaterHeater(HeatPumpNum).HPWaterHeaterSensibleCapacity;
     578       92495 :         LatLoadMet = state.dataWaterThermalTanks->HPWaterHeater(HeatPumpNum).HPWaterHeaterLatentCapacity;
     579             :     }
     580             : }
     581             : 
     582     2804678 : void CalcWaterThermalTankZoneGains(EnergyPlusData &state)
     583             : {
     584             : 
     585             :     // SUBROUTINE INFORMATION:
     586             :     //       AUTHOR         Peter Graham Ellis
     587             :     //       DATE WRITTEN   March 2005
     588             :     //       MODIFIED       B. Griffith November 2011, new internal gains structure
     589             :     //       RE-ENGINEERED  na
     590             : 
     591             :     // PURPOSE OF THIS SUBROUTINE:
     592             :     // Calculates the zone internal gains due to water heater skin losses during sizing.
     593             :     // initializes gains to zone at begin environment.
     594             : 
     595             :     // METHODOLOGY EMPLOYED:
     596             :     // Sums the tank losses from all of the water heaters in the zone to add as a gain to the zone.
     597             :     // Now used to determine tank losses during sizing.  Internal gains are summed in a centralized way now
     598             : 
     599     2804678 :     if (state.dataWaterThermalTanks->numWaterThermalTank == 0) {
     600             : 
     601     2285644 :         if (!state.dataGlobal->DoingSizing) {
     602     1688154 :             return;
     603             :         } else {
     604      597490 :             if (state.dataWaterThermalTanks->getWaterThermalTankInputFlag) {
     605         422 :                 GetWaterThermalTankInput(state);
     606         422 :                 state.dataWaterThermalTanks->getWaterThermalTankInputFlag = false;
     607             :             }
     608      597490 :             if (state.dataWaterThermalTanks->numWaterThermalTank == 0) return;
     609             :         }
     610             :     }
     611             : 
     612      519146 :     if (state.dataGlobal->BeginEnvrnFlag && state.dataWaterThermalTanks->calcWaterThermalTankZoneGainsMyEnvrnFlag) {
     613        3317 :         for (auto &e : state.dataWaterThermalTanks->WaterThermalTank) {
     614        1989 :             e.AmbientZoneGain = 0.0;
     615        1989 :             e.FuelEnergy = 0.0;
     616        1989 :             e.OffCycParaFuelEnergy = 0.0;
     617        1989 :             e.OnCycParaFuelEnergy = 0.0;
     618             :         }
     619        1328 :         state.dataWaterThermalTanks->calcWaterThermalTankZoneGainsMyEnvrnFlag = false;
     620             :     }
     621             : 
     622      519146 :     if (!state.dataGlobal->BeginEnvrnFlag) state.dataWaterThermalTanks->calcWaterThermalTankZoneGainsMyEnvrnFlag = true;
     623             : 
     624     1226483 :     for (int WaterThermalTankNum = 1; WaterThermalTankNum <= state.dataWaterThermalTanks->numWaterThermalTank; ++WaterThermalTankNum) {
     625      707337 :         auto &Tank = state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum);
     626      707337 :         if (Tank.AmbientTempZone == 0) continue;
     627      237555 :         auto &thisZoneHB = state.dataZoneTempPredictorCorrector->zoneHeatBalance(Tank.AmbientTempZone);
     628      237555 :         if (state.dataGlobal->DoingSizing) {
     629             :             // Initialize tank temperature to setpoint
     630             :             // (use HPWH or Desuperheater heating coil set point if applicable)
     631             :             int SchIndex;
     632      107106 :             if (Tank.HeatPumpNum > 0) {
     633       14844 :                 SchIndex = state.dataWaterThermalTanks->HPWaterHeater(Tank.HeatPumpNum).SetPointTempSchedule;
     634       92262 :             } else if (Tank.DesuperheaterNum > 0) {
     635        1350 :                 SchIndex = state.dataWaterThermalTanks->WaterHeaterDesuperheater(Tank.DesuperheaterNum).SetPointTempSchedule;
     636             :             } else {
     637       90912 :                 SchIndex = Tank.SetPointTempSchedule;
     638             :             }
     639             : 
     640             :             Real64 TankTemp;
     641      107106 :             Real64 QLossToZone = 0.0;
     642      107106 :             if (SchIndex > 0) {
     643      107106 :                 TankTemp = ScheduleManager::GetCurrentScheduleValue(state, SchIndex);
     644             :             } else {
     645           0 :                 TankTemp = 20.0;
     646             :             }
     647      107106 :             switch (Tank.WaterThermalTankType) {
     648       90918 :             case DataPlant::PlantEquipmentType::WtrHeaterMixed: {
     649       90918 :                 QLossToZone = max(Tank.OnCycLossCoeff * Tank.OnCycLossFracToZone, Tank.OffCycLossCoeff * Tank.OffCycLossFracToZone) *
     650       90918 :                               (TankTemp - thisZoneHB.MAT);
     651       90918 :                 break;
     652             :             }
     653        8094 :             case DataPlant::PlantEquipmentType::WtrHeaterStratified: {
     654        8094 :                 QLossToZone = max(Tank.Node(1).OnCycLossCoeff * Tank.SkinLossFracToZone, Tank.Node(1).OffCycLossCoeff * Tank.SkinLossFracToZone) *
     655        8094 :                               (TankTemp - thisZoneHB.MAT);
     656        8094 :                 break;
     657             :             }
     658        4050 :             case DataPlant::PlantEquipmentType::ChilledWaterTankMixed: {
     659        4050 :                 QLossToZone = Tank.OffCycLossCoeff * Tank.OffCycLossFracToZone * (TankTemp - thisZoneHB.MAT);
     660        4050 :                 break;
     661             :             }
     662        4044 :             case DataPlant::PlantEquipmentType::ChilledWaterTankStratified: {
     663        4044 :                 QLossToZone = Tank.Node(1).OffCycLossCoeff * Tank.SkinLossFracToZone * (TankTemp - thisZoneHB.MAT);
     664        4044 :                 break;
     665             :             }
     666           0 :             default:
     667           0 :                 break;
     668             :             }
     669      107106 :             Tank.AmbientZoneGain = QLossToZone;
     670             :         }
     671             :     }
     672             : }
     673             : 
     674           6 : bool getDesuperHtrInput(EnergyPlusData &state)
     675             : {
     676           6 :     bool ErrorsFound = false;
     677             :     static constexpr std::string_view RoutineName = "getDesuperHtrInput";
     678             :     // Make local copies of IPShortCut because other getinputs might overwrite the ones in state <-- need to fix this idiom
     679           6 :     std::string cCurrentModuleObject = state.dataIPShortCut->cCurrentModuleObject;
     680           6 :     Array1D<std::string> cAlphaArgs = state.dataIPShortCut->cAlphaArgs;
     681           6 :     Array1D<Real64> rNumericArgs = state.dataIPShortCut->rNumericArgs;
     682           6 :     Array1D<bool> lNumericFieldBlanks = state.dataIPShortCut->lNumericFieldBlanks;
     683           6 :     Array1D<bool> lAlphaFieldBlanks = state.dataIPShortCut->lAlphaFieldBlanks;
     684           6 :     Array1D<std::string> cAlphaFieldNames = state.dataIPShortCut->cAlphaFieldNames;
     685           6 :     Array1D<std::string> cNumericFieldNames = state.dataIPShortCut->cNumericFieldNames;
     686             : 
     687           6 :     cCurrentModuleObject = cCoilDesuperheater;
     688          12 :     for (int DesuperheaterNum = 1; DesuperheaterNum <= state.dataWaterThermalTanks->numWaterHeaterDesuperheater; ++DesuperheaterNum) {
     689             :         int NumAlphas;
     690             :         int NumNums;
     691             :         int IOStat;
     692           6 :         state.dataInputProcessing->inputProcessor->getObjectItem(state,
     693             :                                                                  cCurrentModuleObject,
     694             :                                                                  DesuperheaterNum,
     695             :                                                                  cAlphaArgs,
     696             :                                                                  NumAlphas,
     697             :                                                                  rNumericArgs,
     698             :                                                                  NumNums,
     699             :                                                                  IOStat,
     700             :                                                                  lNumericFieldBlanks,
     701             :                                                                  lAlphaFieldBlanks,
     702             :                                                                  cAlphaFieldNames,
     703             :                                                                  cNumericFieldNames);
     704           6 :         Util::IsNameEmpty(state, cAlphaArgs(1), cCurrentModuleObject, ErrorsFound);
     705             : 
     706             :         // ErrorsFound will be set to True if problem was found, left untouched otherwise
     707           6 :         GlobalNames::VerifyUniqueCoilName(state, cCurrentModuleObject, cAlphaArgs(1), ErrorsFound, cCurrentModuleObject + " Name");
     708             : 
     709           6 :         auto &DesupHtr = state.dataWaterThermalTanks->WaterHeaterDesuperheater(DesuperheaterNum);
     710             : 
     711           6 :         DesupHtr.Name = cAlphaArgs(1);
     712           6 :         DesupHtr.Type = cCurrentModuleObject;
     713             : 
     714             :         //       convert availability schedule name to pointer
     715           6 :         if (!lAlphaFieldBlanks(2)) {
     716           6 :             DesupHtr.AvailSchedPtr = ScheduleManager::GetScheduleIndex(state, cAlphaArgs(2));
     717           6 :             if (DesupHtr.AvailSchedPtr == 0) {
     718           0 :                 ShowSevereError(state, format("Invalid, {} = {}", cAlphaFieldNames(2), cAlphaArgs(2)));
     719           0 :                 ShowContinueError(state, format("Entered in {}={}", cCurrentModuleObject, cAlphaArgs(1)));
     720           0 :                 ErrorsFound = true;
     721             :             }
     722             :         } else {
     723           0 :             DesupHtr.AvailSchedPtr = ScheduleManager::ScheduleAlwaysOn;
     724             :         }
     725             : 
     726             :         // convert schedule name to pointer
     727           6 :         DesupHtr.SetPointTempSchedule = ScheduleManager::GetScheduleIndex(state, cAlphaArgs(3));
     728           6 :         if (DesupHtr.SetPointTempSchedule == 0) {
     729           0 :             ShowSevereError(state, format("Invalid, {} = {}", cAlphaFieldNames(3), cAlphaArgs(3)));
     730           0 :             ShowContinueError(state, format("Entered in {}={}", cCurrentModuleObject, cAlphaArgs(1)));
     731           0 :             ErrorsFound = true;
     732             :         }
     733             : 
     734           6 :         DesupHtr.DeadBandTempDiff = rNumericArgs(1);
     735           6 :         if (DesupHtr.DeadBandTempDiff <= 0.0 || DesupHtr.DeadBandTempDiff > 20.0) {
     736           0 :             ShowSevereError(state,
     737           0 :                             format("{} = {}: {} must be > 0 and <= 20. {} = {:.1T}",
     738             :                                    cCurrentModuleObject,
     739           0 :                                    DesupHtr.Name,
     740             :                                    cNumericFieldNames(1),
     741             :                                    cNumericFieldNames(1),
     742             :                                    rNumericArgs(1)));
     743           0 :             ErrorsFound = true;
     744             :         }
     745             : 
     746             :         // Error limits on heat reclaim efficiency applied after source type identified
     747             : 
     748           6 :         DesupHtr.RatedInletWaterTemp = rNumericArgs(3);
     749           6 :         DesupHtr.RatedOutdoorAirTemp = rNumericArgs(4);
     750           6 :         DesupHtr.MaxInletWaterTemp = rNumericArgs(5);
     751             : 
     752           6 :         if (!lAlphaFieldBlanks(4)) {
     753           6 :             DesupHtr.HEffFTemp = Curve::GetCurveIndex(state, cAlphaArgs(4));
     754           6 :             if (DesupHtr.HEffFTemp == 0) {
     755           0 :                 ShowSevereError(state,
     756           0 :                                 format("{} = {}:  {} not found = {}", cCurrentModuleObject, DesupHtr.Name, cAlphaFieldNames(4), cAlphaArgs(4)));
     757           0 :                 ErrorsFound = true;
     758             :             } else {
     759           6 :                 ErrorsFound |= Curve::CheckCurveDims(state,
     760             :                                                      DesupHtr.HEffFTemp,   // Curve index
     761             :                                                      {2},                  // Valid dimensions
     762             :                                                      RoutineName,          // Routine name
     763             :                                                      cCurrentModuleObject, // Object Type
     764             :                                                      DesupHtr.Name,        // Object Name
     765           6 :                                                      cAlphaFieldNames(4)); // Field Name
     766           6 :                 if (!ErrorsFound) {
     767           6 :                     if (DesupHtr.HEffFTemp > 0) {
     768           6 :                         Real64 HEffFTemp = min(
     769           6 :                             1.0, max(0.0, Curve::CurveValue(state, DesupHtr.HEffFTemp, DesupHtr.RatedInletWaterTemp, DesupHtr.RatedOutdoorAirTemp)));
     770           6 :                         if (std::abs(HEffFTemp - 1.0) > 0.05) {
     771           0 :                             ShowWarningError(state, format("{}, \"{}\":", cCurrentModuleObject, DesupHtr.Name));
     772           0 :                             ShowContinueError(state, format("The {} should be normalized ", cAlphaFieldNames(4)));
     773           0 :                             ShowContinueError(state, format(" to 1.0 at the rating point. Curve output at the rating point = {:.3T}", HEffFTemp));
     774           0 :                             ShowContinueError(state, " The simulation continues using the user-specified curve.");
     775             :                         }
     776             :                     }
     777             :                 }
     778             :             }
     779             :         }
     780             : 
     781           6 :         DesupHtr.WaterInletNode = NodeInputManager::GetOnlySingleNode(state,
     782           6 :                                                                       cAlphaArgs(5),
     783             :                                                                       ErrorsFound,
     784             :                                                                       DataLoopNode::ConnectionObjectType::CoilWaterHeatingDesuperheater,
     785           6 :                                                                       cAlphaArgs(1),
     786             :                                                                       DataLoopNode::NodeFluidType::Water,
     787             :                                                                       DataLoopNode::ConnectionType::Inlet,
     788             :                                                                       NodeInputManager::CompFluidStream::Primary,
     789             :                                                                       DataLoopNode::ObjectIsParent);
     790             : 
     791           6 :         DesupHtr.WaterOutletNode = NodeInputManager::GetOnlySingleNode(state,
     792           6 :                                                                        cAlphaArgs(6),
     793             :                                                                        ErrorsFound,
     794             :                                                                        DataLoopNode::ConnectionObjectType::CoilWaterHeatingDesuperheater,
     795           6 :                                                                        cAlphaArgs(1),
     796             :                                                                        DataLoopNode::NodeFluidType::Water,
     797             :                                                                        DataLoopNode::ConnectionType::Outlet,
     798             :                                                                        NodeInputManager::CompFluidStream::Primary,
     799             :                                                                        DataLoopNode::ObjectIsParent);
     800             : 
     801           6 :         DesupHtr.InletNodeName1 = cAlphaArgs(5);
     802           6 :         DesupHtr.OutletNodeName1 = cAlphaArgs(6);
     803             : 
     804           6 :         DesupHtr.TankType = cAlphaArgs(7);
     805             : 
     806           6 :         if (!Util::SameString(DesupHtr.TankType, cMixedWHModuleObj) && !Util::SameString(DesupHtr.TankType, cStratifiedWHModuleObj)) {
     807             : 
     808           0 :             ShowSevereError(state, format("{} = {}:", cCurrentModuleObject, state.dataWaterThermalTanks->HPWaterHeater(DesuperheaterNum).Name));
     809           0 :             ShowContinueError(state, format("Desuperheater can only be used with {} or {}.", cMixedWHModuleObj, cStratifiedWHModuleObj));
     810           0 :             ErrorsFound = true;
     811             :         }
     812             : 
     813           6 :         DesupHtr.TankName = cAlphaArgs(8);
     814             : 
     815             :         // Set up comp set for water side nodes (reverse inlet/outlet for water heater)
     816           6 :         BranchNodeConnections::SetUpCompSets(state, DesupHtr.Type, DesupHtr.Name, DesupHtr.TankType, DesupHtr.TankName, cAlphaArgs(6), cAlphaArgs(5));
     817             : 
     818           6 :         std::string const heatSourceObjType = cAlphaArgs(9);
     819             : 
     820          11 :         if ((Util::SameString(heatSourceObjType, "Refrigeration:Condenser:AirCooled")) ||
     821          11 :             (Util::SameString(heatSourceObjType, "Refrigeration:Condenser:EvaporativeCooled")) ||
     822          11 :             (Util::SameString(heatSourceObjType, "Refrigeration:Condenser:WaterCooled"))) {
     823           1 :             if (lNumericFieldBlanks(2)) {
     824           0 :                 DesupHtr.HeatReclaimRecoveryEff = 0.8;
     825             :             } else {
     826           1 :                 DesupHtr.HeatReclaimRecoveryEff = rNumericArgs(2);
     827           1 :                 if (DesupHtr.HeatReclaimRecoveryEff <= 0.0 || DesupHtr.HeatReclaimRecoveryEff > 0.9) {
     828           0 :                     ShowSevereError(state,
     829           0 :                                     format("{} = {}: {} must be > 0.0 and <= 0.9, Efficiency = {:.3T}",
     830             :                                            cCurrentModuleObject,
     831           0 :                                            DesupHtr.Name,
     832             :                                            cNumericFieldNames(2),
     833           0 :                                            DesupHtr.HeatReclaimRecoveryEff));
     834           0 :                     ErrorsFound = true;
     835             :                 }
     836             :             }    // Blank Num(2)
     837             :         } else { // max is 0.3 for all other sources
     838           5 :             if (lNumericFieldBlanks(2)) {
     839           0 :                 DesupHtr.HeatReclaimRecoveryEff = 0.25;
     840             :             } else {
     841           5 :                 DesupHtr.HeatReclaimRecoveryEff = rNumericArgs(2);
     842           5 :                 if (DesupHtr.HeatReclaimRecoveryEff <= 0.0 || DesupHtr.HeatReclaimRecoveryEff > 0.3) {
     843           0 :                     ShowSevereError(state,
     844           0 :                                     format("{} = {}: {} must be > 0.0 and <= 0.3, {} = {:.3T}",
     845             :                                            cCurrentModuleObject,
     846           0 :                                            DesupHtr.Name,
     847             :                                            cNumericFieldNames(2),
     848             :                                            cNumericFieldNames(2),
     849           0 :                                            DesupHtr.HeatReclaimRecoveryEff));
     850           0 :                     ErrorsFound = true;
     851             :                 }
     852             :             } // Blank Num(2)
     853             :         }     // setting limits on heat recovery efficiency
     854             : 
     855             :         //       Find the Refrigeration equipment index associated with the desuperheater heating coil.
     856           6 :         bool errFlag = false;
     857           6 :         DesupHtr.HeatingSourceType = heatSourceObjType;
     858           6 :         DesupHtr.HeatingSourceName = cAlphaArgs(10);
     859           6 :         if (Util::SameString(heatSourceObjType, "Refrigeration:CompressorRack")) {
     860           0 :             DesupHtr.ReclaimHeatingSource = ReclaimHeatObjectType::CompressorRackRefrigeratedCase;
     861           0 :             for (int RackNum = 1; RackNum <= state.dataRefrigCase->NumRefrigeratedRacks; ++RackNum) {
     862           0 :                 if (!Util::SameString(state.dataHeatBal->HeatReclaimRefrigeratedRack(RackNum).Name, cAlphaArgs(10))) continue;
     863           0 :                 DesupHtr.ReclaimHeatingSourceIndexNum = RackNum;
     864           0 :                 if (allocated(state.dataHeatBal->HeatReclaimRefrigeratedRack)) {
     865             :                     DataHeatBalance::HeatReclaimDataBase &HeatReclaim =
     866           0 :                         state.dataHeatBal->HeatReclaimRefrigeratedRack(DesupHtr.ReclaimHeatingSourceIndexNum);
     867           0 :                     if (!allocated(HeatReclaim.WaterHeatingDesuperheaterReclaimedHeat)) {
     868           0 :                         HeatReclaim.WaterHeatingDesuperheaterReclaimedHeat.allocate(state.dataWaterThermalTanks->numWaterHeaterDesuperheater);
     869           0 :                         for (auto &num : HeatReclaim.WaterHeatingDesuperheaterReclaimedHeat)
     870           0 :                             num = 0.0;
     871             :                     }
     872           0 :                     DesupHtr.ValidSourceType = true;
     873           0 :                     HeatReclaim.ReclaimEfficiencyTotal += DesupHtr.HeatReclaimRecoveryEff;
     874           0 :                     if (HeatReclaim.ReclaimEfficiencyTotal > 0.3) {
     875           0 :                         ShowSevereError(
     876             :                             state,
     877           0 :                             format("{} = {}:  sum of heat reclaim recovery efficiencies from the same source coil: \"{}\" cannot be over 0.3",
     878             :                                    cCurrentModuleObject,
     879           0 :                                    DesupHtr.Name,
     880           0 :                                    DesupHtr.HeatingSourceName));
     881           0 :                         ErrorsFound = true;
     882             :                     }
     883             :                 }
     884           0 :                 break;
     885             :             }
     886          11 :         } else if ((Util::SameString(heatSourceObjType, "Refrigeration:Condenser:AirCooled")) ||
     887          11 :                    (Util::SameString(heatSourceObjType, "Refrigeration:Condenser:EvaporativeCooled")) ||
     888          11 :                    (Util::SameString(heatSourceObjType, "Refrigeration:Condenser:WaterCooled"))) {
     889           1 :             DesupHtr.ReclaimHeatingSource = ReclaimHeatObjectType::CondenserRefrigeration;
     890           2 :             for (int CondNum = 1; CondNum <= state.dataRefrigCase->NumRefrigCondensers; ++CondNum) {
     891           2 :                 if (!Util::SameString(state.dataHeatBal->HeatReclaimRefrigCondenser(CondNum).Name, cAlphaArgs(10))) continue;
     892           1 :                 DesupHtr.ReclaimHeatingSourceIndexNum = CondNum;
     893           1 :                 if (allocated(state.dataHeatBal->HeatReclaimRefrigCondenser)) {
     894             :                     DataHeatBalance::HeatReclaimDataBase &HeatReclaim =
     895           1 :                         state.dataHeatBal->HeatReclaimRefrigCondenser(DesupHtr.ReclaimHeatingSourceIndexNum);
     896           1 :                     if (!allocated(HeatReclaim.WaterHeatingDesuperheaterReclaimedHeat)) {
     897           1 :                         HeatReclaim.WaterHeatingDesuperheaterReclaimedHeat.allocate(state.dataWaterThermalTanks->numWaterHeaterDesuperheater);
     898           2 :                         for (auto &num : HeatReclaim.WaterHeatingDesuperheaterReclaimedHeat)
     899           1 :                             num = 0.0;
     900             :                     }
     901           1 :                     DesupHtr.ValidSourceType = true;
     902           1 :                     HeatReclaim.ReclaimEfficiencyTotal += DesupHtr.HeatReclaimRecoveryEff;
     903           1 :                     if (HeatReclaim.ReclaimEfficiencyTotal > 0.9) {
     904           0 :                         ShowSevereError(
     905             :                             state,
     906           0 :                             format("{} = {}:  sum of heat reclaim recovery efficiencies from the same source coil: \"{}\" cannot be over 0.9",
     907             :                                    cCurrentModuleObject,
     908           0 :                                    DesupHtr.Name,
     909           0 :                                    DesupHtr.HeatingSourceName));
     910           0 :                         ErrorsFound = true;
     911             :                     }
     912             :                 }
     913           1 :                 break;
     914             :             }
     915           8 :         } else if (Util::SameString(heatSourceObjType, "Coil:Cooling:DX:SingleSpeed") ||
     916           6 :                    Util::SameString(heatSourceObjType, "Coil:Cooling:DX:TwoSpeed") ||
     917          11 :                    Util::SameString(heatSourceObjType, "Coil:Cooling:DX:MultiSpeed") ||
     918           8 :                    Util::SameString(heatSourceObjType, "Coil:Cooling:DX:TwoStageWithHumidityControlMode")) {
     919             : 
     920           2 :             if (Util::SameString(heatSourceObjType, "Coil:Cooling:DX:SingleSpeed")) {
     921           2 :                 DesupHtr.ReclaimHeatingSource = ReclaimHeatObjectType::DXCooling;
     922           0 :             } else if (Util::SameString(heatSourceObjType, "Coil:Cooling:DX:TwoStageWithHumidityControlMode")) {
     923           0 :                 DesupHtr.ReclaimHeatingSource = ReclaimHeatObjectType::DXMultiMode;
     924             :             } else {
     925           0 :                 DesupHtr.ReclaimHeatingSource = ReclaimHeatObjectType::DXMultiSpeed;
     926             :             }
     927           2 :             DXCoils::GetDXCoilIndex(state, DesupHtr.HeatingSourceName, DesupHtr.ReclaimHeatingSourceIndexNum, errFlag, cCurrentModuleObject);
     928           2 :             if (allocated(state.dataHeatBal->HeatReclaimDXCoil)) {
     929           2 :                 DataHeatBalance::HeatReclaimDataBase &HeatReclaim = state.dataHeatBal->HeatReclaimDXCoil(DesupHtr.ReclaimHeatingSourceIndexNum);
     930           2 :                 if (!allocated(HeatReclaim.WaterHeatingDesuperheaterReclaimedHeat)) {
     931           2 :                     HeatReclaim.WaterHeatingDesuperheaterReclaimedHeat.allocate(state.dataWaterThermalTanks->numWaterHeaterDesuperheater);
     932           4 :                     for (auto &num : HeatReclaim.WaterHeatingDesuperheaterReclaimedHeat)
     933           2 :                         num = 0.0;
     934             :                 }
     935           2 :                 DesupHtr.ValidSourceType = true;
     936           2 :                 HeatReclaim.ReclaimEfficiencyTotal += DesupHtr.HeatReclaimRecoveryEff;
     937           2 :                 if (HeatReclaim.ReclaimEfficiencyTotal > 0.3) {
     938           0 :                     ShowSevereError(state,
     939           0 :                                     format("{} = {}:  sum of heat reclaim recovery efficiencies from the same source coil: \"{}\" cannot be over 0.3",
     940             :                                            cCurrentModuleObject,
     941           0 :                                            DesupHtr.Name,
     942           0 :                                            DesupHtr.HeatingSourceName));
     943           0 :                     ErrorsFound = true;
     944             :                 }
     945             :             }
     946           3 :         } else if (Util::SameString(heatSourceObjType, "Coil:Cooling:DX:VariableSpeed")) {
     947           1 :             DesupHtr.ReclaimHeatingSource = ReclaimHeatObjectType::DXVariableCooling;
     948           1 :             DesupHtr.ReclaimHeatingSourceIndexNum = VariableSpeedCoils::GetCoilIndexVariableSpeed(state, heatSourceObjType, cAlphaArgs(10), errFlag);
     949           1 :             if (allocated(state.dataHeatBal->HeatReclaimVS_DXCoil)) {
     950           1 :                 DataHeatBalance::HeatReclaimDataBase &HeatReclaim = state.dataHeatBal->HeatReclaimVS_DXCoil(DesupHtr.ReclaimHeatingSourceIndexNum);
     951           1 :                 if (!allocated(HeatReclaim.WaterHeatingDesuperheaterReclaimedHeat)) {
     952           1 :                     HeatReclaim.WaterHeatingDesuperheaterReclaimedHeat.allocate(state.dataWaterThermalTanks->numWaterHeaterDesuperheater);
     953           2 :                     for (auto &num : HeatReclaim.WaterHeatingDesuperheaterReclaimedHeat)
     954           1 :                         num = 0.0;
     955             :                 }
     956           1 :                 DesupHtr.ValidSourceType = true;
     957           1 :                 HeatReclaim.ReclaimEfficiencyTotal += DesupHtr.HeatReclaimRecoveryEff;
     958           1 :                 if (HeatReclaim.ReclaimEfficiencyTotal > 0.3) {
     959           0 :                     ShowSevereError(state,
     960           0 :                                     format("{} = {}:  sum of heat reclaim recovery efficiencies from the same source coil: \"{}\" cannot be over 0.3",
     961             :                                            cCurrentModuleObject,
     962           0 :                                            DesupHtr.Name,
     963           0 :                                            DesupHtr.HeatingSourceName));
     964           0 :                     ErrorsFound = true;
     965             :                 }
     966             :             }
     967           2 :         } else if (Util::SameString(heatSourceObjType, "Coil:Cooling:WaterToAirHeatPump:EquationFit")) {
     968           1 :             DesupHtr.ReclaimHeatingSource = ReclaimHeatObjectType::AirWaterHeatPumpEQ;
     969           1 :             DesupHtr.ReclaimHeatingSourceIndexNum = WaterToAirHeatPumpSimple::GetCoilIndex(state, heatSourceObjType, cAlphaArgs(10), errFlag);
     970           1 :             if (allocated(state.dataHeatBal->HeatReclaimSimple_WAHPCoil)) {
     971             :                 DataHeatBalance::HeatReclaimDataBase &HeatReclaim =
     972           1 :                     state.dataHeatBal->HeatReclaimSimple_WAHPCoil(DesupHtr.ReclaimHeatingSourceIndexNum);
     973           1 :                 if (!allocated(HeatReclaim.WaterHeatingDesuperheaterReclaimedHeat)) {
     974           1 :                     HeatReclaim.WaterHeatingDesuperheaterReclaimedHeat.allocate(state.dataWaterThermalTanks->numWaterHeaterDesuperheater);
     975           2 :                     for (auto &num : HeatReclaim.WaterHeatingDesuperheaterReclaimedHeat)
     976           1 :                         num = 0.0;
     977             :                 }
     978           1 :                 DesupHtr.ValidSourceType = true;
     979           1 :                 HeatReclaim.ReclaimEfficiencyTotal += DesupHtr.HeatReclaimRecoveryEff;
     980           1 :                 if (HeatReclaim.ReclaimEfficiencyTotal > 0.3) {
     981           0 :                     ShowSevereError(state,
     982           0 :                                     format("{} = {}:  sum of heat reclaim recovery efficiencies from the same source coil: \"{}\" cannot be over 0.3",
     983             :                                            cCurrentModuleObject,
     984           0 :                                            DesupHtr.Name,
     985           0 :                                            DesupHtr.HeatingSourceName));
     986           0 :                     ErrorsFound = true;
     987             :                 }
     988             :             }
     989           1 :         } else if (Util::SameString(heatSourceObjType, "Coil:Cooling:DX")) {
     990           1 :             DesupHtr.ReclaimHeatingSource = ReclaimHeatObjectType::CoilCoolingDX;
     991           1 :             DesupHtr.ReclaimHeatingSourceIndexNum = CoilCoolingDX::factory(state, cAlphaArgs(10));
     992           1 :             if (DesupHtr.ReclaimHeatingSourceIndexNum < 0) {
     993           0 :                 ShowSevereError(
     994             :                     state,
     995           0 :                     format("{}={}, could not find desuperheater coil {}={}", cCurrentModuleObject, DesupHtr.Name, cAlphaArgs(9), cAlphaArgs(10)));
     996           0 :                 ErrorsFound = true;
     997             :             } else {
     998             :                 DataHeatBalance::HeatReclaimDataBase &HeatReclaim =
     999           1 :                     state.dataCoilCooingDX->coilCoolingDXs[DesupHtr.ReclaimHeatingSourceIndexNum].reclaimHeat;
    1000           1 :                 if (!allocated(HeatReclaim.WaterHeatingDesuperheaterReclaimedHeat)) {
    1001           1 :                     HeatReclaim.WaterHeatingDesuperheaterReclaimedHeat.allocate(state.dataWaterThermalTanks->numWaterHeaterDesuperheater);
    1002           2 :                     for (auto &num : HeatReclaim.WaterHeatingDesuperheaterReclaimedHeat)
    1003           1 :                         num = 0.0;
    1004             :                 }
    1005           1 :                 DesupHtr.ValidSourceType = true;
    1006           1 :                 HeatReclaim.ReclaimEfficiencyTotal += DesupHtr.HeatReclaimRecoveryEff;
    1007           1 :                 if (HeatReclaim.ReclaimEfficiencyTotal > 0.3) {
    1008           0 :                     ShowSevereError(
    1009             :                         state,
    1010           0 :                         format("{}, \"{}\" sum of heat reclaim recovery efficiencies from the same source coil: \"{}\" cannot be over 0.3",
    1011             :                                cCurrentModuleObject,
    1012           0 :                                DesupHtr.Name,
    1013           0 :                                DesupHtr.HeatingSourceName));
    1014           0 :                     ErrorsFound = true;
    1015             :                 }
    1016             :             }
    1017             :         } else {
    1018           0 :             ShowSevereError(state, format("{} = {}:", cCurrentModuleObject, DesupHtr.Name));
    1019           0 :             ShowContinueError(state, " desuperheater can only be used with Coil:Cooling:DX:SingleSpeed, ");
    1020           0 :             ShowContinueError(state,
    1021             :                               " Coil:Cooling:DX:TwoSpeed, Coil:Cooling:DX:MultiSpeed, Coil:Cooling:DX:TwoStageWithHumidityControlMode, "
    1022             :                               "Coil:Cooling:DX:VariableSpeed, "
    1023             :                               "Coil:Cooling:WaterToAirHeatPump:EquationFit, Refrigeration:CompressorRack,");
    1024           0 :             ShowContinueError(state, " Refrigeration:Condenser:AirCooled ,Refrigeration:Condenser:EvaporativeCooled, ");
    1025           0 :             ShowContinueError(state, " or Refrigeration:Condenser:WaterCooled.");
    1026           0 :             ShowContinueError(state, format(" Invalid desuperheater heat source object: {} \"{}\"", heatSourceObjType, cAlphaArgs(10)));
    1027           0 :             ErrorsFound = true;
    1028             :         }
    1029           6 :         if (errFlag) {
    1030           0 :             ShowContinueError(state, format("...occurs in {}={}", cCurrentModuleObject, DesupHtr.Name));
    1031           0 :             ErrorsFound = true;
    1032             :         }
    1033             : 
    1034           6 :         if (DesupHtr.ReclaimHeatingSourceIndexNum == 0 && DesupHtr.ReclaimHeatingSource != ReclaimHeatObjectType::CoilCoolingDX) {
    1035           0 :             ShowSevereError(state,
    1036           0 :                             format("{}, \"{}\" desuperheater heat source object not found: {} \"{}\"",
    1037             :                                    cCurrentModuleObject,
    1038           0 :                                    DesupHtr.Name,
    1039             :                                    heatSourceObjType,
    1040             :                                    cAlphaArgs(10)));
    1041           0 :             ErrorsFound = true;
    1042             :         }
    1043             : 
    1044           6 :         DesupHtr.OperatingWaterFlowRate = rNumericArgs(6);
    1045           6 :         if (DesupHtr.OperatingWaterFlowRate <= 0.0) {
    1046           0 :             ShowSevereError(state,
    1047           0 :                             format("{} = {}: {} must be greater than 0. {} = {:.6T}",
    1048             :                                    cCurrentModuleObject,
    1049           0 :                                    DesupHtr.Name,
    1050             :                                    cNumericFieldNames(6),
    1051             :                                    cNumericFieldNames(6),
    1052             :                                    rNumericArgs(6)));
    1053           0 :             ErrorsFound = true;
    1054             :         }
    1055             : 
    1056           6 :         DesupHtr.PumpElecPower = rNumericArgs(7);
    1057           6 :         if (DesupHtr.PumpElecPower < 0.0) {
    1058           0 :             ShowSevereError(state,
    1059           0 :                             format("{} = {}: {} must be >= 0. {} = {:.2T}",
    1060             :                                    cCurrentModuleObject,
    1061           0 :                                    DesupHtr.Name,
    1062             :                                    cNumericFieldNames(7),
    1063             :                                    cNumericFieldNames(7),
    1064             :                                    rNumericArgs(7)));
    1065           0 :             ErrorsFound = true;
    1066             :         }
    1067             : 
    1068           6 :         if ((DesupHtr.PumpElecPower / DesupHtr.OperatingWaterFlowRate) > 7.9264e6) {
    1069           0 :             ShowWarningError(state,
    1070           0 :                              format("{} = {}: {} to {} ratio > 7.9264E6. {} to {} = {:.3T}",
    1071             :                                     cCurrentModuleObject,
    1072           0 :                                     DesupHtr.Name,
    1073             :                                     cNumericFieldNames(7),
    1074             :                                     cNumericFieldNames(6),
    1075             :                                     cNumericFieldNames(7),
    1076             :                                     cNumericFieldNames(6),
    1077           0 :                                     (DesupHtr.PumpElecPower / DesupHtr.OperatingWaterFlowRate)));
    1078           0 :             ShowContinueError(state, format(" Suggest reducing {} or increasing {}.", cNumericFieldNames(7), cNumericFieldNames(6)));
    1079           0 :             ShowContinueError(state, " The simulation will continue using the user defined values.");
    1080             :         }
    1081             : 
    1082           6 :         DesupHtr.PumpFracToWater = rNumericArgs(8);
    1083           6 :         if (DesupHtr.PumpFracToWater < 0.0 || DesupHtr.PumpFracToWater > 1.0) {
    1084           0 :             ShowSevereError(state,
    1085           0 :                             format("{} = {}: {} must be >= 0 or <= 1. {} = {:.3T}",
    1086             :                                    cCurrentModuleObject,
    1087           0 :                                    DesupHtr.Name,
    1088             :                                    cNumericFieldNames(8),
    1089             :                                    cNumericFieldNames(8),
    1090             :                                    rNumericArgs(8)));
    1091           0 :             ErrorsFound = true;
    1092             :         }
    1093             : 
    1094           6 :         DesupHtr.OnCycParaLoad = rNumericArgs(9);
    1095           6 :         if (DesupHtr.OnCycParaLoad < 0.0) {
    1096           0 :             ShowSevereError(state,
    1097           0 :                             format("{} = {}: {} must be >= 0. {} = {:.2T}",
    1098             :                                    cCurrentModuleObject,
    1099           0 :                                    DesupHtr.Name,
    1100             :                                    cNumericFieldNames(9),
    1101             :                                    cNumericFieldNames(9),
    1102             :                                    rNumericArgs(9)));
    1103           0 :             ErrorsFound = true;
    1104             :         }
    1105             : 
    1106           6 :         DesupHtr.OffCycParaLoad = rNumericArgs(10);
    1107           6 :         if (DesupHtr.OffCycParaLoad < 0.0) {
    1108           0 :             ShowSevereError(state,
    1109           0 :                             format("{} = {}: {} must be >= 0. {} = {:.2T}",
    1110             :                                    cCurrentModuleObject,
    1111           0 :                                    DesupHtr.Name,
    1112             :                                    cNumericFieldNames(10),
    1113             :                                    cNumericFieldNames(10),
    1114             :                                    rNumericArgs(10)));
    1115           0 :             ErrorsFound = true;
    1116             :         }
    1117           6 :     }
    1118             : 
    1119           6 :     if (ErrorsFound) {
    1120           0 :         ShowFatalError(state, format("Errors found in getting {} input. Preceding condition causes termination.", cCurrentModuleObject));
    1121             :     }
    1122             : 
    1123           6 :     return ErrorsFound;
    1124             : 
    1125           6 : } // namespace WaterThermalTanks
    1126             : 
    1127           9 : bool getHPWaterHeaterInput(EnergyPlusData &state)
    1128             : {
    1129             : 
    1130             :     static constexpr std::string_view routineName = "getHPWaterHeaterInput";
    1131           9 :     bool ErrorsFound = false;
    1132             : 
    1133           9 :     int const NumPumpedCondenser = state.dataInputProcessing->inputProcessor->getNumObjectsFound(
    1134             :         state, cHPWHPumpedCondenser); // number of WaterHeater:HeatPump:PumpedCondenser objects
    1135             :     int nAlphaOffset;                 // the difference of array location between alpha items between pumped and wrapped condensers
    1136             :     int nNumericOffset;               // the difference of array location between numeric items between pumped and wrapped condensers
    1137             :     int nNumPossibleNumericArgs;      // the number of possible numeric arguments in the idd
    1138             :     int nNumPossibleAlphaArgs;        // the number of possible numeric arguments in the idd
    1139             : 
    1140             :     // For looking up in IDF/epJSON, you need the index that corresponds to the actual object type (Pumped or Wrapped)
    1141             :     int HPWaterHeaterNumOfSpecificType;
    1142             : 
    1143          32 :     for (int HPWaterHeaterNum = 1; HPWaterHeaterNum <= state.dataWaterThermalTanks->numHeatPumpWaterHeater; ++HPWaterHeaterNum) {
    1144             : 
    1145             :         // Create reference to current HPWH object in array.
    1146          23 :         HeatPumpWaterHeaterData &HPWH = state.dataWaterThermalTanks->HPWaterHeater(HPWaterHeaterNum);
    1147             : 
    1148             :         // Initialize the offsets to zero
    1149          23 :         nAlphaOffset = 0;
    1150          23 :         nNumericOffset = 0;
    1151             : 
    1152             :         DataLoopNode::ConnectionObjectType objType;
    1153             : 
    1154          23 :         if (HPWaterHeaterNum <= NumPumpedCondenser) {
    1155             :             // Pumped Condenser
    1156          20 :             state.dataIPShortCut->cCurrentModuleObject = cHPWHPumpedCondenser;
    1157          20 :             objType = DataLoopNode::ConnectionObjectType::WaterHeaterHeatPumpPumpedCondenser;
    1158          20 :             HPWH.HPWHType = DataPlant::PlantEquipmentType::HeatPumpWtrHeaterPumped;
    1159          20 :             nNumPossibleAlphaArgs = 29;
    1160          20 :             nNumPossibleNumericArgs = 9;
    1161             :             // Actual index of Pumped type
    1162          20 :             HPWaterHeaterNumOfSpecificType = HPWaterHeaterNum;
    1163             :         } else {
    1164             :             // Wrapped Condenser
    1165           3 :             state.dataIPShortCut->cCurrentModuleObject = cHPWHWrappedCondenser;
    1166           3 :             objType = DataLoopNode::ConnectionObjectType::WaterHeaterHeatPumpWrappedCondenser;
    1167           3 :             HPWH.HPWHType = DataPlant::PlantEquipmentType::HeatPumpWtrHeaterWrapped;
    1168           3 :             nNumPossibleAlphaArgs = 27;
    1169           3 :             nNumPossibleNumericArgs = 10;
    1170             :             // Actual index of Wrapped type
    1171           3 :             HPWaterHeaterNumOfSpecificType = HPWaterHeaterNum - NumPumpedCondenser;
    1172             :         }
    1173             : 
    1174             :         int NumAlphas;
    1175             :         int NumNums;
    1176             :         int IOStat;
    1177          46 :         state.dataInputProcessing->inputProcessor->getObjectItem(state,
    1178          23 :                                                                  state.dataIPShortCut->cCurrentModuleObject,
    1179             :                                                                  HPWaterHeaterNumOfSpecificType,
    1180          23 :                                                                  state.dataIPShortCut->cAlphaArgs,
    1181             :                                                                  NumAlphas,
    1182          23 :                                                                  state.dataIPShortCut->rNumericArgs,
    1183             :                                                                  NumNums,
    1184             :                                                                  IOStat,
    1185          23 :                                                                  state.dataIPShortCut->lNumericFieldBlanks,
    1186          23 :                                                                  state.dataIPShortCut->lAlphaFieldBlanks,
    1187          23 :                                                                  state.dataIPShortCut->cAlphaFieldNames,
    1188          23 :                                                                  state.dataIPShortCut->cNumericFieldNames);
    1189             : 
    1190          23 :         ErrorObjectHeader eoh{routineName, state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)};
    1191             : 
    1192             :         // Copy those lists into C++ std::maps // Why, no really why?  This is really dumb
    1193          23 :         std::map<int, std::string> hpwhAlpha;
    1194          23 :         std::map<int, Real64> hpwhNumeric;
    1195          23 :         std::map<int, bool> hpwhAlphaBlank;
    1196          23 :         std::map<int, bool> hpwhNumericBlank;
    1197          23 :         std::map<int, std::string> hpwhAlphaFieldNames;
    1198          23 :         std::map<int, std::string> hpwhNumericFieldNames;
    1199         204 :         for (int i = 1; i <= NumNums; ++i) {
    1200         181 :             hpwhNumeric[i] = state.dataIPShortCut->rNumericArgs(i);
    1201         181 :             hpwhNumericBlank[i] = state.dataIPShortCut->lNumericFieldBlanks(i);
    1202         181 :             hpwhNumericFieldNames[i] = state.dataIPShortCut->cNumericFieldNames(i);
    1203             :         }
    1204          55 :         for (int i = NumNums + 1; i <= nNumPossibleNumericArgs; ++i) {
    1205          32 :             hpwhNumericBlank[i] = true;
    1206             :         }
    1207         642 :         for (int i = 1; i <= NumAlphas; ++i) {
    1208         619 :             hpwhAlpha[i] = state.dataIPShortCut->cAlphaArgs(i);
    1209         619 :             hpwhAlphaBlank[i] = state.dataIPShortCut->lAlphaFieldBlanks(i);
    1210         619 :             hpwhAlphaFieldNames[i] = state.dataIPShortCut->cAlphaFieldNames(i);
    1211             :         }
    1212          65 :         for (int i = NumAlphas + 1; i <= nNumPossibleAlphaArgs; ++i) {
    1213          42 :             hpwhAlphaBlank[i] = true;
    1214             :         }
    1215          23 :         Util::IsNameEmpty(state, hpwhAlpha[1], state.dataIPShortCut->cCurrentModuleObject, ErrorsFound);
    1216             : 
    1217             :         // Name and type
    1218          23 :         HPWH.Name = hpwhAlpha[1];
    1219          23 :         HPWH.Type = state.dataIPShortCut->cCurrentModuleObject;
    1220             : 
    1221             :         // Availability Schedule
    1222             :         // convert schedule name to pointer
    1223          23 :         if (!hpwhAlphaBlank[2]) {
    1224          23 :             HPWH.AvailSchedPtr = ScheduleManager::GetScheduleIndex(state, hpwhAlpha[2]);
    1225          23 :             if (HPWH.AvailSchedPtr == 0) {
    1226           0 :                 ShowSevereError(state, format("{}=\"{}\", not found", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    1227           0 :                 ShowContinueError(state, format("{}=\"{}\".", hpwhAlphaFieldNames[2], hpwhAlpha[2]));
    1228           0 :                 ErrorsFound = true;
    1229             :             }
    1230             :         } else {
    1231           0 :             HPWH.AvailSchedPtr = ScheduleManager::ScheduleAlwaysOn;
    1232             :         }
    1233             : 
    1234             :         // Compressor Setpoint Temperature Schedule
    1235             :         // convert schedule name to pointer
    1236          23 :         if (!hpwhAlphaBlank[3]) {
    1237          23 :             HPWH.SetPointTempSchedule = ScheduleManager::GetScheduleIndex(state, hpwhAlpha[3]);
    1238          23 :             if (HPWH.SetPointTempSchedule == 0) {
    1239           0 :                 ShowSevereError(state, format("{}=\"{}\", not found", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    1240           0 :                 ShowContinueError(state, format("{}=\"{}\".", hpwhAlphaFieldNames[3], hpwhAlpha[3]));
    1241           0 :                 ErrorsFound = true;
    1242             :             }
    1243             :         } else {
    1244           0 :             ShowSevereError(state, format("{}=\"{}\", ", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    1245           0 :             ShowContinueError(state, format("required {} is blank.", hpwhAlphaFieldNames[3]));
    1246           0 :             ErrorsFound = true;
    1247             :         }
    1248             : 
    1249             :         // Dead Band Temperature Difference
    1250          23 :         HPWH.DeadBandTempDiff = hpwhNumeric[1 + nNumericOffset];
    1251          23 :         if (HPWH.DeadBandTempDiff <= 0.0 || HPWH.DeadBandTempDiff > 20.0) {
    1252           0 :             ShowSevereError(state, format("{}=\"{}\", ", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    1253           0 :             ShowContinueError(state,
    1254           0 :                               format("{}{}",
    1255           0 :                                      hpwhNumericFieldNames[1 + nNumericOffset],
    1256           0 :                                      format(" difference must be > 0 and <= 20. Dead band = {:.1T}", hpwhNumeric[1 + nNumericOffset])));
    1257           0 :             ErrorsFound = true;
    1258             :         }
    1259             : 
    1260          23 :         if (HPWH.HPWHType == DataPlant::PlantEquipmentType::HeatPumpWtrHeaterPumped) {
    1261             : 
    1262             :             // Condenser Inlet/Outlet Nodes
    1263          20 :             HPWH.CondWaterInletNode = NodeInputManager::GetOnlySingleNode(state,
    1264          20 :                                                                           hpwhAlpha[4],
    1265             :                                                                           ErrorsFound,
    1266             :                                                                           objType,
    1267          20 :                                                                           HPWH.Name,
    1268             :                                                                           DataLoopNode::NodeFluidType::Water,
    1269             :                                                                           DataLoopNode::ConnectionType::Inlet,
    1270             :                                                                           NodeInputManager::CompFluidStream::Secondary,
    1271             :                                                                           DataLoopNode::ObjectIsParent);
    1272          20 :             HPWH.InletNodeName1 = hpwhAlpha[4];
    1273          20 :             HPWH.CondWaterOutletNode = NodeInputManager::GetOnlySingleNode(state,
    1274          20 :                                                                            hpwhAlpha[5],
    1275             :                                                                            ErrorsFound,
    1276             :                                                                            objType,
    1277          20 :                                                                            HPWH.Name,
    1278             :                                                                            DataLoopNode::NodeFluidType::Water,
    1279             :                                                                            DataLoopNode::ConnectionType::Outlet,
    1280             :                                                                            NodeInputManager::CompFluidStream::Secondary,
    1281             :                                                                            DataLoopNode::ObjectIsParent);
    1282          20 :             HPWH.OutletNodeName1 = hpwhAlpha[5];
    1283             : 
    1284             :             // Condenser Water Flow Rate
    1285          20 :             HPWH.OperatingWaterFlowRate = hpwhNumeric[2];
    1286          20 :             if (HPWH.OperatingWaterFlowRate <= 0.0 && hpwhNumeric[2] != Constant::AutoCalculate) {
    1287           0 :                 ShowSevereError(state, format("{}=\"{}\", ", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    1288           0 :                 ShowContinueError(state,
    1289           0 :                                   format("{} must be greater than 0. Condenser water flow rate = {:.6T}", hpwhNumericFieldNames[2], hpwhNumeric[2]));
    1290           0 :                 ErrorsFound = true;
    1291             :             }
    1292             : 
    1293           3 :         } else if (HPWH.HPWHType == DataPlant::PlantEquipmentType::HeatPumpWtrHeaterWrapped) {
    1294             : 
    1295             :             // Wrapped Condenser Location
    1296           3 :             HPWH.WrappedCondenserBottomLocation = hpwhNumeric[2 + nNumericOffset];
    1297           3 :             HPWH.WrappedCondenserTopLocation = hpwhNumeric[3 + nNumericOffset];
    1298             : 
    1299           3 :             if (HPWH.WrappedCondenserBottomLocation < 0.0) {
    1300           0 :                 ShowSevereError(state, format("{}=\"{}\", ", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    1301           0 :                 ShowContinueError(state,
    1302           0 :                                   format("{} must be greater than 0. Condenser bottom location = {:.6T}",
    1303           0 :                                          hpwhNumericFieldNames[2],
    1304           0 :                                          HPWH.WrappedCondenserBottomLocation));
    1305           0 :                 ErrorsFound = true;
    1306             :             }
    1307             : 
    1308           3 :             if (HPWH.WrappedCondenserBottomLocation >= HPWH.WrappedCondenserTopLocation) {
    1309           0 :                 ShowSevereError(state, format("{}=\"{}\", ", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    1310           0 :                 ShowContinueError(state,
    1311           0 :                                   format("{} ({:.6T}) must be greater than {} ({:.6T}).",
    1312           0 :                                          HPWH.WrappedCondenserTopLocation,
    1313           0 :                                          hpwhNumericFieldNames[2],
    1314           0 :                                          hpwhNumericFieldNames[3],
    1315           0 :                                          HPWH.WrappedCondenserBottomLocation));
    1316           0 :                 ErrorsFound = true;
    1317             :             }
    1318             : 
    1319             :             // Reset the offset
    1320           3 :             nAlphaOffset = -2;
    1321           3 :             nNumericOffset = 1;
    1322             : 
    1323             :         } else {
    1324           0 :             assert(0);
    1325             :         }
    1326             : 
    1327             :         // Evaporator Air Flow Rate
    1328          23 :         HPWH.OperatingAirFlowRate = hpwhNumeric[3 + nNumericOffset];
    1329          23 :         if (HPWH.OperatingAirFlowRate <= 0.0 && hpwhNumeric[3 + nNumericOffset] != Constant::AutoCalculate) {
    1330           0 :             ShowSevereError(state, format("{}=\"{}\", ", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    1331           0 :             ShowContinueError(state,
    1332           0 :                               format("{}{}",
    1333           0 :                                      hpwhNumericFieldNames[3 + nNumericOffset],
    1334           0 :                                      format(" must be greater than 0. Evaporator air flow rate = {:.6T}", hpwhNumeric[3 + nNumericOffset])));
    1335           0 :             ErrorsFound = true;
    1336             :         }
    1337             : 
    1338             :         // Inlet Air Configuration
    1339          23 :         HPWH.InletAirConfiguration = static_cast<WTTAmbientTemp>(getEnumValue(HPWHAmbientTempNamesUC, Util::makeUPPER(hpwhAlpha[6 + nAlphaOffset])));
    1340          23 :         switch (HPWH.InletAirConfiguration) {
    1341           3 :         case WTTAmbientTemp::Schedule: {
    1342             : 
    1343             :             // Inlet Air Temperature Schedule
    1344           3 :             if (!hpwhAlphaBlank[11 + nAlphaOffset]) {
    1345           3 :                 HPWH.AmbientTempSchedule = ScheduleManager::GetScheduleIndex(state, hpwhAlpha[11 + nAlphaOffset]);
    1346           3 :                 if (HPWH.AmbientTempSchedule == 0) {
    1347           0 :                     ShowSevereError(state, format("{}=\"{}\", not found", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    1348           0 :                     ShowContinueError(state, format("{}=\"{}\".", hpwhAlphaFieldNames[11 + nAlphaOffset], hpwhAlpha[11 + nAlphaOffset]));
    1349           0 :                     ErrorsFound = true;
    1350             :                 }
    1351             :             } else {
    1352           0 :                 ShowSevereError(state, format("{}=\"{}\", ", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    1353           0 :                 ShowContinueError(state, format("required {} is blank.", hpwhAlphaFieldNames[11 + nAlphaOffset]));
    1354           0 :                 ErrorsFound = true;
    1355             :             }
    1356             : 
    1357             :             // Inlet Air Humidity Schedule
    1358           3 :             if (!hpwhAlphaBlank[12 + nAlphaOffset]) {
    1359           3 :                 HPWH.AmbientRHSchedule = ScheduleManager::GetScheduleIndex(state, hpwhAlpha[12 + nAlphaOffset]);
    1360           3 :                 if (HPWH.AmbientRHSchedule == 0) {
    1361           0 :                     ShowSevereError(state, format("{}=\"{}\", not found", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    1362           0 :                     ShowContinueError(state, format("{}=\"{}\".", hpwhAlphaFieldNames[12 + nAlphaOffset], hpwhAlpha[12 + nAlphaOffset]));
    1363           0 :                     ErrorsFound = true;
    1364             :                 } else {
    1365           3 :                     if (!ScheduleManager::CheckScheduleValueMinMax(state, HPWH.AmbientRHSchedule, ">=", 0.0, "<=", 1.0)) {
    1366           0 :                         ShowSevereError(state, format("{}=\"{}\", invalid values", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    1367           0 :                         ShowContinueError(state,
    1368           0 :                                           format("{}=\"{}\", schedule values must be (>=0., <=1.)",
    1369           0 :                                                  hpwhAlphaFieldNames[12 + nAlphaOffset],
    1370           0 :                                                  hpwhAlpha[12 + nAlphaOffset]));
    1371           0 :                         ErrorsFound = true;
    1372             :                     }
    1373             :                 }
    1374             :             } else {
    1375           0 :                 ShowSevereError(state, format("{}=\"{}\", ", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    1376           0 :                 ShowContinueError(state, format("required {} is blank.", hpwhAlphaFieldNames[12 + nAlphaOffset]));
    1377           0 :                 ErrorsFound = true;
    1378             :             }
    1379             : 
    1380           3 :             break;
    1381             :         }
    1382          10 :         case WTTAmbientTemp::ZoneAndOA:
    1383             :         case WTTAmbientTemp::TempZone: {
    1384             : 
    1385             :             // Inlet Air Zone
    1386          10 :             if (!hpwhAlphaBlank[13 + nAlphaOffset]) {
    1387          10 :                 HPWH.AmbientTempZone = Util::FindItemInList(hpwhAlpha[13 + nAlphaOffset], state.dataHeatBal->Zone);
    1388          10 :                 if (HPWH.AmbientTempZone == 0) {
    1389           0 :                     ShowSevereError(state, format("{}=\"{}\", not found", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    1390           0 :                     ShowContinueError(state, format("{}=\"{}\".", hpwhAlphaFieldNames[13 + nAlphaOffset], hpwhAlpha[13 + nAlphaOffset]));
    1391           0 :                     ErrorsFound = true;
    1392             :                 }
    1393             :             } else {
    1394           0 :                 ShowSevereError(state, format("{}=\"{}\", ", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    1395           0 :                 ShowContinueError(state, format("required {} is blank.", hpwhAlphaFieldNames[13 + nAlphaOffset]));
    1396           0 :                 ErrorsFound = true;
    1397             :             }
    1398          10 :             break;
    1399             :         }
    1400          10 :         default:
    1401             :         case WTTAmbientTemp::OutsideAir:
    1402          10 :             break;
    1403             :         }
    1404             : 
    1405             :         // Read air inlet nodes after mixer/splitter nodes have been read in (state.dataIPShortCut->cAlphaArgs 7-10),
    1406             :         // Node_ConnectionType differs for inlet node if mixer/splitter node exists
    1407             : 
    1408             :         // Tank Name
    1409             :         // We will verify this exists and is the right kind of tank later when the tanks are all loaded.
    1410          23 :         HPWH.TankName = hpwhAlpha[15 + nAlphaOffset];
    1411          23 :         HPWH.TankType = hpwhAlpha[14 + nAlphaOffset];
    1412             : 
    1413             :         // Use Side Inlet/Outlet
    1414             :         // Get the water heater tank use side inlet node names for HPWHs connected to a plant loop
    1415             :         // Save the name of the node for use with set up comp sets
    1416          23 :         HPWH.InletNodeName2 = hpwhAlpha[16 + nAlphaOffset];
    1417          23 :         HPWH.OutletNodeName2 = hpwhAlpha[17 + nAlphaOffset];
    1418             : 
    1419          23 :         if (!hpwhAlphaBlank[16 + nAlphaOffset] && !hpwhAlphaBlank[17 + nAlphaOffset]) {
    1420          10 :             HPWH.WHUseInletNode = NodeInputManager::GetOnlySingleNode(state,
    1421          10 :                                                                       HPWH.InletNodeName2,
    1422             :                                                                       ErrorsFound,
    1423             :                                                                       objType,
    1424          10 :                                                                       HPWH.Name,
    1425             :                                                                       DataLoopNode::NodeFluidType::Water,
    1426             :                                                                       DataLoopNode::ConnectionType::Inlet,
    1427             :                                                                       NodeInputManager::CompFluidStream::Primary,
    1428             :                                                                       DataLoopNode::ObjectIsParent);
    1429          20 :             HPWH.WHUseOutletNode = NodeInputManager::GetOnlySingleNode(state,
    1430          10 :                                                                        HPWH.OutletNodeName2,
    1431             :                                                                        ErrorsFound,
    1432             :                                                                        objType,
    1433          10 :                                                                        HPWH.Name,
    1434             :                                                                        DataLoopNode::NodeFluidType::Water,
    1435             :                                                                        DataLoopNode::ConnectionType::Outlet,
    1436             :                                                                        NodeInputManager::CompFluidStream::Primary,
    1437             :                                                                        DataLoopNode::ObjectIsParent);
    1438             :         }
    1439             : 
    1440             :         // DX Coil
    1441             :         // get Coil:DX:HeatPumpWaterHeater object
    1442          23 :         HPWH.DXCoilName = hpwhAlpha[19 + nAlphaOffset];
    1443          23 :         HPWH.DXCoilType = hpwhAlpha[18 + nAlphaOffset];
    1444             : 
    1445             :         // check that the DX Coil exists
    1446          23 :         bool DXCoilErrFlag = false;
    1447          23 :         bool bIsVScoil = false;
    1448          23 :         DXCoils::GetDXCoilIndex(state, HPWH.DXCoilName, HPWH.DXCoilNum, DXCoilErrFlag, state.dataIPShortCut->cCurrentModuleObject, true);
    1449          23 :         if (DXCoilErrFlag) {
    1450             :             // This could be a variable speed heat pump water heater
    1451           7 :             bool bVSCoilErrFlag = false;
    1452             : 
    1453           7 :             bool checkIHPFirst = IntegratedHeatPump::IHPInModel(state);
    1454           7 :             if (checkIHPFirst) {
    1455           1 :                 HPWH.DXCoilNum =
    1456           1 :                     IntegratedHeatPump::GetCoilIndexIHP(state, "COILSYSTEM:INTEGRATEDHEATPUMP:AIRSOURCE", HPWH.DXCoilName, bVSCoilErrFlag);
    1457             : 
    1458           1 :                 if (!bVSCoilErrFlag) {
    1459           1 :                     HPWH.bIsIHP = true;
    1460             :                 }
    1461             :             }
    1462             : 
    1463           7 :             if (bVSCoilErrFlag || !checkIHPFirst) {
    1464           6 :                 bVSCoilErrFlag = false;
    1465           6 :                 HPWH.DXCoilNum = VariableSpeedCoils::GetCoilIndexVariableSpeed(
    1466           6 :                     state, "Coil:WaterHeating:AirToWaterHeatPump:VariableSpeed", HPWH.DXCoilName, bVSCoilErrFlag);
    1467             : 
    1468           6 :                 if (bVSCoilErrFlag) {
    1469           0 :                     ShowContinueError(state, format("...occurs in {} ={}", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    1470           0 :                     ShowContinueError(state, format("...could not find either DXCoils::DXCoil or Variable Speed Coil {}", HPWH.DXCoilName));
    1471           0 :                     ErrorsFound = true;
    1472             :                 }
    1473             :             }
    1474             : 
    1475           7 :             bIsVScoil = true;
    1476           7 :             HPWH.DXCoilTypeNum = 0;
    1477           7 :             if (HPWH.bIsIHP) {
    1478           1 :                 HPWH.DXCoilType = "COILSYSTEM:INTEGRATEDHEATPUMP:AIRSOURCE";
    1479             :             } else {
    1480           6 :                 HPWH.DXCoilType = state.dataVariableSpeedCoils->VarSpeedCoil(HPWH.DXCoilNum).VarSpeedCoilType;
    1481             :             }
    1482             :         } else {
    1483             :             // this is a single speed coil
    1484          16 :             DXCoils::DXCoilData &Coil = state.dataDXCoils->DXCoil(HPWH.DXCoilNum);
    1485          16 :             if (!Util::SameString(HPWH.DXCoilType, Coil.DXCoilType)) {
    1486           0 :                 ShowSevereError(state, format("{}=\"{}\", ", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    1487           0 :                 ShowContinueError(state, format("specifies the coil {}=\"{}\".", HPWH.DXCoilType, HPWH.DXCoilName));
    1488           0 :                 ShowContinueError(state, format("However, {} is a coil of type {}.", HPWH.DXCoilName, Coil.DXCoilType));
    1489           0 :                 ErrorsFound = true;
    1490             :             }
    1491          16 :             HPWH.DXCoilTypeNum = Coil.DXCoilType_Num;
    1492             :         }
    1493             : 
    1494             :         // Make sure that the coil and tank are compatible.
    1495          23 :         if (bIsVScoil) {
    1496           7 :             if (HPWH.HPWHType != DataPlant::PlantEquipmentType::HeatPumpWtrHeaterPumped) {
    1497           0 :                 ShowSevereError(state, format("{}=\"{}\":", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    1498           0 :                 ShowContinueError(state,
    1499             :                                   "Coil:WaterHeating:AirToWaterHeatPump:VariableSpeed can only be used with a pumped condenser heat pump "
    1500             :                                   "water heater.");
    1501           0 :                 ErrorsFound = true;
    1502             :             }
    1503             :         } else {
    1504          16 :             if (!((HPWH.DXCoilTypeNum == HVAC::CoilDX_HeatPumpWaterHeaterPumped &&
    1505          13 :                    HPWH.HPWHType == DataPlant::PlantEquipmentType::HeatPumpWtrHeaterPumped) ||
    1506           3 :                   (HPWH.DXCoilTypeNum == HVAC::CoilDX_HeatPumpWaterHeaterWrapped &&
    1507           3 :                    HPWH.HPWHType == DataPlant::PlantEquipmentType::HeatPumpWtrHeaterWrapped))) {
    1508           0 :                 ShowSevereError(state, format("{}=\"{}\":", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    1509           0 :                 std::string ExpectedCoilType;
    1510           0 :                 if (HPWH.HPWHType == DataPlant::PlantEquipmentType::HeatPumpWtrHeaterPumped) {
    1511           0 :                     ExpectedCoilType = HVAC::cAllCoilTypes(HVAC::CoilDX_HeatPumpWaterHeaterPumped);
    1512           0 :                 } else if (HPWH.HPWHType == DataPlant::PlantEquipmentType::HeatPumpWtrHeaterWrapped) {
    1513           0 :                     ExpectedCoilType = HVAC::cAllCoilTypes(HVAC::CoilDX_HeatPumpWaterHeaterWrapped);
    1514             :                 } else {
    1515           0 :                     assert(0);
    1516             :                 }
    1517           0 :                 ShowContinueError(state, format("can only be used with {}", ExpectedCoilType));
    1518           0 :                 ErrorsFound = true;
    1519           0 :             }
    1520             :         }
    1521             : 
    1522             :         // Dummy condenser Inlet/Outlet Nodes for wrapped tanks
    1523          23 :         if (HPWH.DXCoilTypeNum == HVAC::CoilDX_HeatPumpWaterHeaterWrapped) {
    1524           3 :             DXCoils::DXCoilData &Coil = state.dataDXCoils->DXCoil(HPWH.DXCoilNum);
    1525             : 
    1526           3 :             HPWH.InletNodeName1 = "DUMMY CONDENSER INLET " + Coil.Name;
    1527           3 :             HPWH.CondWaterInletNode = NodeInputManager::GetOnlySingleNode(state,
    1528           3 :                                                                           HPWH.InletNodeName1,
    1529             :                                                                           ErrorsFound,
    1530             :                                                                           objType,
    1531           3 :                                                                           HPWH.Name,
    1532             :                                                                           DataLoopNode::NodeFluidType::Water,
    1533             :                                                                           DataLoopNode::ConnectionType::Inlet,
    1534             :                                                                           NodeInputManager::CompFluidStream::Secondary,
    1535             :                                                                           DataLoopNode::ObjectIsParent);
    1536           3 :             HPWH.OutletNodeName1 = "DUMMY CONDENSER OUTLET " + Coil.Name;
    1537           6 :             HPWH.CondWaterOutletNode = NodeInputManager::GetOnlySingleNode(state,
    1538           3 :                                                                            HPWH.OutletNodeName1,
    1539             :                                                                            ErrorsFound,
    1540             :                                                                            objType,
    1541           3 :                                                                            HPWH.Name,
    1542             :                                                                            DataLoopNode::NodeFluidType::Water,
    1543             :                                                                            DataLoopNode::ConnectionType::Outlet,
    1544             :                                                                            NodeInputManager::CompFluidStream::Secondary,
    1545             :                                                                            DataLoopNode::ObjectIsParent);
    1546             :         }
    1547             : 
    1548             :         // Minimum Inlet Air Temperature for Compressor Operation
    1549          23 :         HPWH.MinAirTempForHPOperation = hpwhNumeric[4 + nNumericOffset];
    1550             : 
    1551             :         // Maximum Inlet Air Temperature for Compressor Operation
    1552          23 :         HPWH.MaxAirTempForHPOperation = hpwhNumeric[5 + nNumericOffset];
    1553          23 :         if (HPWH.MaxAirTempForHPOperation <= HPWH.MinAirTempForHPOperation) {
    1554           0 :             ShowWarningError(state,
    1555           0 :                              format("{}=\"{}\": maximum inlet air temperature for heat pump compressor operation",
    1556           0 :                                     state.dataIPShortCut->cCurrentModuleObject,
    1557           0 :                                     HPWH.Name));
    1558           0 :             ShowContinueError(state, "must be greater than the minimum inlet air temperature for heat pump compressor operation.");
    1559           0 :             ShowContinueError(state, format("...Minimum inlet air temperature = {:.1T}", HPWH.MinAirTempForHPOperation));
    1560           0 :             ShowContinueError(state, format("...Maximum inlet air temperature = {:.1T}", HPWH.MaxAirTempForHPOperation));
    1561             :         }
    1562             : 
    1563             :         // Compressor Location
    1564          23 :         HPWH.CrankcaseTempIndicator =
    1565          23 :             static_cast<CrankcaseHeaterControlTemp>(getEnumValue(CrankcaseHeaterControlTempNamesUC, Util::makeUPPER(hpwhAlpha[20 + nAlphaOffset])));
    1566          23 :         switch (HPWH.CrankcaseTempIndicator) {
    1567           3 :         case CrankcaseHeaterControlTemp::Schedule: {
    1568           3 :             if (!hpwhAlphaBlank[21 + nAlphaOffset]) {
    1569             :                 // Compressor Ambient Temperature Schedule
    1570           3 :                 HPWH.CrankcaseTempSchedule = ScheduleManager::GetScheduleIndex(state, hpwhAlpha[21 + nAlphaOffset]);
    1571           3 :                 if (HPWH.CrankcaseTempSchedule == 0) {
    1572           0 :                     ShowSevereError(state, format("{}=\"{}\", not found", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    1573           0 :                     ShowContinueError(state, format("{}=\"{}\".", hpwhAlphaFieldNames[21 + nAlphaOffset], hpwhAlpha[21 + nAlphaOffset]));
    1574           0 :                     ErrorsFound = true;
    1575             :                 }
    1576             :             } else {
    1577           0 :                 ShowSevereError(state, format("{}=\"{}\", ", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    1578           0 :                 ShowContinueError(state, format("required {} is blank.", hpwhAlphaFieldNames[21 + nAlphaOffset]));
    1579           0 :                 ErrorsFound = true;
    1580             :             }
    1581             : 
    1582           3 :             break;
    1583             :         }
    1584          10 :         case CrankcaseHeaterControlTemp::Zone: {
    1585          10 :             if (HPWH.InletAirConfiguration == WTTAmbientTemp::OutsideAir || HPWH.InletAirConfiguration == WTTAmbientTemp::Schedule) {
    1586           0 :                 ShowSevereError(state,
    1587           0 :                                 format("{}=\"{}\":  Inlet Air Configuration must be Zone Air Only or Zone And",
    1588           0 :                                        state.dataIPShortCut->cCurrentModuleObject,
    1589           0 :                                        HPWH.Name));
    1590           0 :                 ShowContinueError(state, " Outdoor Air when compressor location equals ZONE.");
    1591           0 :                 ErrorsFound = true;
    1592             :             }
    1593             : 
    1594          10 :             if (!hpwhAlphaBlank[21 + nAlphaOffset]) {
    1595           0 :                 ShowWarningError(state,
    1596           0 :                                  format("{}=\"{}\"  {} was provided but will not be used based on compressor location input=\"{}\".",
    1597           0 :                                         state.dataIPShortCut->cCurrentModuleObject,
    1598           0 :                                         HPWH.Name,
    1599           0 :                                         hpwhAlphaFieldNames[21 + nAlphaOffset],
    1600           0 :                                         hpwhAlpha[20 + nAlphaOffset]));
    1601             :             }
    1602          10 :             break;
    1603             :         }
    1604          10 :         case CrankcaseHeaterControlTemp::Outdoors: {
    1605          10 :             if (!hpwhAlphaBlank[21 + nAlphaOffset]) {
    1606           0 :                 ShowWarningError(state,
    1607           0 :                                  format("{}=\"{}\"  {} was provided but will not be used based on {}=\"{}\".",
    1608           0 :                                         state.dataIPShortCut->cCurrentModuleObject,
    1609           0 :                                         HPWH.Name,
    1610           0 :                                         hpwhAlphaFieldNames[21 + nAlphaOffset],
    1611           0 :                                         hpwhAlphaFieldNames[21 + nAlphaOffset],
    1612           0 :                                         hpwhAlpha[20 + nAlphaOffset]));
    1613             :             }
    1614          10 :             break;
    1615             :         }
    1616           0 :         default:
    1617           0 :             break;
    1618             :         }
    1619             : 
    1620             :         // Fan Name
    1621          23 :         HPWH.FanName = hpwhAlpha[23 + nAlphaOffset];
    1622             : 
    1623          23 :         Real64 FanVolFlow = 0.0;
    1624          23 :         bool errFlag(false);
    1625             : 
    1626          23 :         HPWH.fanType = static_cast<HVAC::FanType>(getEnumValue(HVAC::fanTypeNamesUC, hpwhAlpha[22 + nAlphaOffset]));
    1627             : 
    1628          23 :         if ((HPWH.FanNum = Fans::GetFanIndex(state, HPWH.FanName)) == 0) {
    1629           0 :             ShowSevereItemNotFound(state, eoh, hpwhAlphaFieldNames[23 + nAlphaOffset], HPWH.FanName);
    1630           0 :             ErrorsFound = true;
    1631             :         } else {
    1632          23 :             assert(HPWH.fanType == state.dataFans->fans(HPWH.FanNum)->type);
    1633          23 :             FanVolFlow = state.dataFans->fans(HPWH.FanNum)->maxAirFlowRate;
    1634             :         }
    1635             :         // issue #5630, set fan info in coils.
    1636          23 :         if (bIsVScoil) {
    1637           7 :             VariableSpeedCoils::setVarSpeedHPWHFanType(state, HPWH.DXCoilNum, HPWH.fanType);
    1638           7 :             VariableSpeedCoils::setVarSpeedHPWHFanIndex(state, HPWH.DXCoilNum, HPWH.FanNum);
    1639             :         } else {
    1640             :             // LOL
    1641          16 :             DXCoils::SetDXCoolingCoilData(state, HPWH.DXCoilNum, errFlag, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, HPWH.FanName);
    1642          16 :             DXCoils::SetDXCoolingCoilData(state, HPWH.DXCoilNum, errFlag, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, HPWH.FanNum);
    1643          16 :             DXCoils::SetDXCoolingCoilData(
    1644          16 :                 state, HPWH.DXCoilNum, errFlag, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, HPWH.fanType);
    1645             :         }
    1646             : 
    1647          23 :         if (errFlag) {
    1648           0 :             ErrorsFound = true;
    1649          23 :         } else if (HPWH.fanType != HVAC::FanType::OnOff && HPWH.fanType != HVAC::FanType::SystemModel) {
    1650           0 :             ShowSevereError(state, format("{}=\"{}\": illegal fan type specified.", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    1651           0 :             ShowContinueError(
    1652             :                 state,
    1653           0 :                 format(" The fan object ({}) type must be Fan:SystemModel or Fan:OnOff when used with a heat pump water heater.", HPWH.FanName));
    1654           0 :             ErrorsFound = true;
    1655          23 :         } else if (HPWH.fanType != HVAC::FanType::OnOff && HPWH.fanType != HVAC::FanType::SystemModel) {
    1656           0 :             ShowSevereError(state, format("{}=\"{}\": illegal fan type specified.", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    1657           0 :             ShowContinueError(state, format(" The {} must specify that the fan object", state.dataIPShortCut->cCurrentModuleObject));
    1658           0 :             ShowContinueError(state,
    1659             :                               " is of type FanSystemModel or Fan:OnOff in addition to the fan actually being of that type and defined elsewhere.");
    1660             :         }
    1661             : 
    1662          23 :         if (FanVolFlow != DataSizing::AutoSize && !errFlag) {
    1663          21 :             if (FanVolFlow < HPWH.OperatingAirFlowRate) {
    1664           0 :                 ShowSevereError(state,
    1665           0 :                                 format("{} - air flow rate = {:.7T} in fan object {} is less than the  HPWHs evaporator air flow rate.",
    1666           0 :                                        state.dataIPShortCut->cCurrentModuleObject,
    1667             :                                        FanVolFlow,
    1668           0 :                                        HPWH.FanName));
    1669           0 :                 ShowContinueError(state, " The fan flow rate must be >= to the HPWHs evaporator volumetric air flow rate.");
    1670           0 :                 ShowContinueError(state, format(" Occurs in unit = {}", HPWH.Name));
    1671           0 :                 ErrorsFound = true;
    1672             :             }
    1673             :         }
    1674             : 
    1675             :         // Fan Placement
    1676          23 :         HPWH.fanPlace = static_cast<HVAC::FanPlace>(getEnumValue(HVAC::fanPlaceNamesUC, hpwhAlpha[24 + nAlphaOffset]));
    1677          23 :         if (HPWH.fanPlace == HVAC::FanPlace::Invalid) {
    1678           0 :             ShowSevereInvalidKey(state, eoh, hpwhAlphaFieldNames[24 + nAlphaOffset], hpwhAlpha[24 + nAlphaOffset]);
    1679           0 :             ErrorsFound = true;
    1680             :         }
    1681             : 
    1682          23 :         if (HPWH.DXCoilNum > 0 && !bIsVScoil) {
    1683             :             // get HPWH capacity, air inlet node, and PLF curve info from DX coil object
    1684          16 :             HPWH.Capacity = state.dataDXCoils->DXCoil(HPWH.DXCoilNum).RatedTotCap2;
    1685          16 :             HPWH.DXCoilAirInletNode = state.dataDXCoils->DXCoil(HPWH.DXCoilNum).AirInNode;
    1686          16 :             HPWH.DXCoilPLFFPLR = state.dataDXCoils->DXCoil(HPWH.DXCoilNum).PLFFPLR(1);
    1687             :             // check the range of condenser pump power to be <= 5 gpm/ton
    1688          16 :             if (state.dataDXCoils->DXCoil(HPWH.DXCoilNum).HPWHCondPumpElecNomPower / state.dataDXCoils->DXCoil(HPWH.DXCoilNum).RatedTotCap2 >
    1689             :                 0.1422) {
    1690           0 :                 ShowWarningError(
    1691             :                     state,
    1692           0 :                     format("{}= {}{}",
    1693           0 :                            state.dataDXCoils->DXCoil(HPWH.DXCoilNum).DXCoilType,
    1694           0 :                            state.dataDXCoils->DXCoil(HPWH.DXCoilNum).Name,
    1695           0 :                            format(": Rated condenser pump power per watt of rated heating capacity has exceeded the recommended maximum of 0.1422 "
    1696             :                                   "W/W (41.67 watt/MBH). Condenser pump power per watt = {:.4T}",
    1697           0 :                                   (state.dataDXCoils->DXCoil(HPWH.DXCoilNum).HPWHCondPumpElecNomPower /
    1698           0 :                                    state.dataDXCoils->DXCoil(HPWH.DXCoilNum).RatedTotCap2))));
    1699             :             }
    1700           7 :         } else if ((HPWH.DXCoilNum > 0) && (bIsVScoil)) {
    1701             : 
    1702           7 :             if (HPWH.bIsIHP) {
    1703           1 :                 HPWH.Capacity =
    1704           1 :                     GetDWHCoilCapacityIHP(state, HPWH.DXCoilType, HPWH.DXCoilName, IntegratedHeatPump::IHPOperationMode::SCWHMatchWH, DXCoilErrFlag);
    1705           1 :                 HPWH.DXCoilAirInletNode = IntegratedHeatPump::GetCoilInletNodeIHP(state, HPWH.DXCoilType, HPWH.DXCoilName, DXCoilErrFlag);
    1706           1 :                 HPWH.DXCoilPLFFPLR =
    1707           1 :                     GetIHPDWHCoilPLFFPLR(state, HPWH.DXCoilType, HPWH.DXCoilName, IntegratedHeatPump::IHPOperationMode::SCWHMatchWH, DXCoilErrFlag);
    1708             :             } else {
    1709           6 :                 HPWH.Capacity = VariableSpeedCoils::GetCoilCapacityVariableSpeed(state, HPWH.DXCoilType, HPWH.DXCoilName, DXCoilErrFlag);
    1710           6 :                 HPWH.DXCoilAirInletNode = VariableSpeedCoils::GetCoilInletNodeVariableSpeed(state, HPWH.DXCoilType, HPWH.DXCoilName, DXCoilErrFlag);
    1711           6 :                 HPWH.DXCoilPLFFPLR = VariableSpeedCoils::GetVSCoilPLFFPLR(state, HPWH.DXCoilType, HPWH.DXCoilName, DXCoilErrFlag);
    1712             :             }
    1713             :             //         check the range of condenser pump power to be <= 5 gpm/ton, will be checked in the coil object
    1714             :         }
    1715             : 
    1716          23 :         if (HPWH.OperatingWaterFlowRate == Constant::AutoCalculate) {
    1717           8 :             HPWH.OperatingWaterFlowRate = 0.00000004487 * HPWH.Capacity;
    1718           8 :             HPWH.WaterFlowRateAutoSized = true;
    1719             :         }
    1720             : 
    1721          23 :         if (HPWH.OperatingAirFlowRate == Constant::AutoCalculate) {
    1722          10 :             HPWH.OperatingAirFlowRate = 0.00005035 * HPWH.Capacity;
    1723          10 :             HPWH.AirFlowRateAutoSized = true;
    1724             :         }
    1725             : 
    1726             :         // On Cycle Parasitic Electric Load
    1727          23 :         HPWH.OnCycParaLoad = hpwhNumeric[6 + nNumericOffset];
    1728          23 :         if (HPWH.OnCycParaLoad < 0.0) {
    1729           0 :             ShowSevereError(state, format("{}=\"{}\",", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    1730           0 :             ShowContinueError(state,
    1731           0 :                               format("{} must be >= 0. {}{}",
    1732           0 :                                      hpwhNumericFieldNames[6 + nNumericOffset],
    1733           0 :                                      hpwhNumericFieldNames[6 + nNumericOffset],
    1734           0 :                                      format(" = {:.2T}", hpwhNumeric[6 + nNumericOffset])));
    1735           0 :             ErrorsFound = true;
    1736             :         }
    1737             : 
    1738             :         // Off Cycle Parasitic Electric Load
    1739          23 :         HPWH.OffCycParaLoad = hpwhNumeric[7 + nNumericOffset];
    1740          23 :         if (HPWH.OffCycParaLoad < 0.0) {
    1741           0 :             ShowSevereError(state, format("{}=\"{}\",", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    1742           0 :             ShowContinueError(state,
    1743           0 :                               format("{} must be >= 0. {}{}",
    1744           0 :                                      hpwhNumericFieldNames[7 + nNumericOffset],
    1745           0 :                                      hpwhNumericFieldNames[2 + nNumericOffset],
    1746           0 :                                      format(" = {:.2T}", hpwhNumeric[7 + nNumericOffset])));
    1747           0 :             ErrorsFound = true;
    1748             :         }
    1749             : 
    1750             :         // Parasitic Heat Rejection Location
    1751          23 :         if (Util::SameString(hpwhAlpha[25 + nAlphaOffset], "Zone")) {
    1752           8 :             HPWH.ParasiticTempIndicator = WTTAmbientTemp::TempZone;
    1753           8 :             if (HPWH.InletAirConfiguration == WTTAmbientTemp::OutsideAir || HPWH.InletAirConfiguration == WTTAmbientTemp::Schedule) {
    1754           0 :                 ShowSevereError(state, format("{}=\"{}\",", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    1755           0 :                 ShowContinueError(state, format("{} must be ZoneAirOnly or ZoneAndOutdoorAir", hpwhAlphaFieldNames[25 + nAlphaOffset]));
    1756           0 :                 ShowContinueError(state, " when parasitic heat rejection location equals Zone.");
    1757           0 :                 ErrorsFound = true;
    1758             :             }
    1759          15 :         } else if (Util::SameString(hpwhAlpha[25 + nAlphaOffset], "Outdoors")) {
    1760          15 :             HPWH.ParasiticTempIndicator = WTTAmbientTemp::OutsideAir;
    1761             :         } else {
    1762           0 :             ShowSevereError(state, format("{}=\"{}\":", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    1763           0 :             ShowContinueError(state, " parasitic heat rejection location must be either Zone or Outdoors.");
    1764           0 :             ErrorsFound = true;
    1765             :         }
    1766             : 
    1767             :         // Inlet Air Mixer Node
    1768             :         // get mixer/splitter nodes only when Inlet Air Configuration is ZoneAndOutdoorAir
    1769          23 :         if (!hpwhAlphaBlank[26 + nAlphaOffset]) {
    1770             :             // For the inlet air mixer node, NodeConnectionType is outlet from the HPWH inlet air node
    1771           3 :             if (HPWH.InletAirConfiguration == WTTAmbientTemp::ZoneAndOA) {
    1772           3 :                 HPWH.InletAirMixerNode = NodeInputManager::GetOnlySingleNode(state,
    1773           3 :                                                                              hpwhAlpha[26 + nAlphaOffset],
    1774             :                                                                              ErrorsFound,
    1775             :                                                                              objType,
    1776           6 :                                                                              HPWH.Name + "-INLET AIR MIXER",
    1777             :                                                                              DataLoopNode::NodeFluidType::Air,
    1778             :                                                                              DataLoopNode::ConnectionType::Outlet,
    1779             :                                                                              NodeInputManager::CompFluidStream::Primary,
    1780             :                                                                              DataLoopNode::ObjectIsNotParent);
    1781             :             } else {
    1782           0 :                 ShowWarningError(state, format("{}=\"{}\":", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    1783           0 :                 ShowContinueError(state,
    1784             :                                   "Inlet air mixer node name specified but only required when Inlet Air Configuration is selected as "
    1785             :                                   "Zone and OutdoorAir. Node name disregarded and simulation continues.");
    1786             :             }
    1787          20 :         } else if (hpwhAlphaBlank[26 + nAlphaOffset] && HPWH.InletAirConfiguration == WTTAmbientTemp::ZoneAndOA) {
    1788           0 :             ShowSevereError(state, format("{}=\"{}\":", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    1789           0 :             ShowContinueError(state, "Inlet air mixer node name required when Inlet Air Configuration is selected as ZoneAndOutdoorAir.");
    1790           0 :             ErrorsFound = true;
    1791             :         }
    1792             : 
    1793             :         // Outlet Air Splitter Node
    1794          23 :         if (!hpwhAlphaBlank[27 + nAlphaOffset]) {
    1795             :             //  For the outlet air splitter node, NodeConnectionType is inlet to the HPWH outlet air node
    1796           3 :             if (HPWH.InletAirConfiguration == WTTAmbientTemp::ZoneAndOA) {
    1797           3 :                 HPWH.OutletAirSplitterNode = NodeInputManager::GetOnlySingleNode(state,
    1798           3 :                                                                                  hpwhAlpha[27 + nAlphaOffset],
    1799             :                                                                                  ErrorsFound,
    1800             :                                                                                  objType,
    1801           6 :                                                                                  HPWH.Name + "-OUTLET AIR SPLITTER",
    1802             :                                                                                  DataLoopNode::NodeFluidType::Air,
    1803             :                                                                                  DataLoopNode::ConnectionType::Inlet,
    1804             :                                                                                  NodeInputManager::CompFluidStream::Primary,
    1805             :                                                                                  DataLoopNode::ObjectIsNotParent);
    1806             :             } else {
    1807           0 :                 ShowWarningError(state, format("{}=\"{}\":", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    1808           0 :                 ShowContinueError(state,
    1809             :                                   "Outlet air splitter node name specified but only required when Inlet Air Configuration is selected as "
    1810             :                                   "ZoneAndOutdoorAir. Node name disregarded and simulation continues.");
    1811             :             }
    1812          20 :         } else if (hpwhAlphaBlank[27 + nAlphaOffset] && HPWH.InletAirConfiguration == WTTAmbientTemp::ZoneAndOA) {
    1813           0 :             ShowSevereError(state, format("{}=\"{}\":", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    1814           0 :             ShowContinueError(state, "Outlet air splitter node name required when Inlet Air Configuration is selected as ZoneAndOutdoorAir.");
    1815           0 :             ErrorsFound = true;
    1816             :         }
    1817             : 
    1818             :         // get node data for HPWH
    1819          23 :         if (HPWH.InletAirMixerNode != 0) {
    1820             :             // when mixer/splitter nodes are used the HPWH's inlet/outlet node are set up as DataLoopNode::ObjectIsNotParent
    1821             : 
    1822           3 :             HPWH.HeatPumpAirInletNode = NodeInputManager::GetOnlySingleNode(state,
    1823           3 :                                                                             hpwhAlpha[7 + nAlphaOffset],
    1824             :                                                                             ErrorsFound,
    1825             :                                                                             objType,
    1826           6 :                                                                             HPWH.Name + "-INLET AIR MIXER",
    1827             :                                                                             DataLoopNode::NodeFluidType::Air,
    1828             :                                                                             DataLoopNode::ConnectionType::Inlet,
    1829             :                                                                             NodeInputManager::CompFluidStream::Primary,
    1830             :                                                                             DataLoopNode::ObjectIsNotParent);
    1831             : 
    1832           3 :             HPWH.HeatPumpAirOutletNode = NodeInputManager::GetOnlySingleNode(state,
    1833           3 :                                                                              hpwhAlpha[8 + nAlphaOffset],
    1834             :                                                                              ErrorsFound,
    1835             :                                                                              objType,
    1836           6 :                                                                              HPWH.Name + "-OUTLET AIR SPLITTER",
    1837             :                                                                              DataLoopNode::NodeFluidType::Air,
    1838             :                                                                              DataLoopNode::ConnectionType::Outlet,
    1839             :                                                                              NodeInputManager::CompFluidStream::Primary,
    1840             :                                                                              DataLoopNode::ObjectIsNotParent);
    1841             : 
    1842           3 :             HPWH.OutsideAirNode = NodeInputManager::GetOnlySingleNode(state,
    1843           3 :                                                                       hpwhAlpha[9 + nAlphaOffset],
    1844             :                                                                       ErrorsFound,
    1845             :                                                                       objType,
    1846           3 :                                                                       HPWH.Name,
    1847             :                                                                       DataLoopNode::NodeFluidType::Air,
    1848             :                                                                       DataLoopNode::ConnectionType::OutsideAirReference,
    1849             :                                                                       NodeInputManager::CompFluidStream::Primary,
    1850             :                                                                       DataLoopNode::ObjectIsParent);
    1851           3 :             if (!hpwhAlpha[9 + nAlphaOffset].empty()) {
    1852             :                 bool Okay;
    1853           3 :                 OutAirNodeManager::CheckAndAddAirNodeNumber(state, HPWH.OutsideAirNode, Okay);
    1854           3 :                 if (!Okay) {
    1855           0 :                     ShowWarningError(state,
    1856           0 :                                      format("{}=\"{}\": Adding outdoor air node={}",
    1857           0 :                                             state.dataIPShortCut->cCurrentModuleObject,
    1858           0 :                                             HPWH.Name,
    1859           0 :                                             hpwhAlpha[9 + nAlphaOffset]));
    1860             :                 }
    1861             :             }
    1862             : 
    1863           3 :             HPWH.ExhaustAirNode = NodeInputManager::GetOnlySingleNode(state,
    1864           3 :                                                                       hpwhAlpha[10 + nAlphaOffset],
    1865             :                                                                       ErrorsFound,
    1866             :                                                                       objType,
    1867           3 :                                                                       HPWH.Name,
    1868             :                                                                       DataLoopNode::NodeFluidType::Air,
    1869             :                                                                       DataLoopNode::ConnectionType::ReliefAir,
    1870             :                                                                       NodeInputManager::CompFluidStream::Primary,
    1871             :                                                                       DataLoopNode::ObjectIsParent);
    1872             : 
    1873             :         } else {
    1874             :             // when mixer/splitter nodes are NOT used the HPWH's inlet/outlet nodes are set up as DataLoopNode::ObjectIsParent
    1875          20 :             if (HPWH.InletAirConfiguration == WTTAmbientTemp::Schedule) {
    1876             :                 // for scheduled HPWH's the inlet node is not on any branch or parent object, make it an outlet node
    1877             :                 // to avoid node connection errors
    1878           3 :                 HPWH.HeatPumpAirInletNode = NodeInputManager::GetOnlySingleNode(state,
    1879           3 :                                                                                 hpwhAlpha[7 + nAlphaOffset],
    1880             :                                                                                 ErrorsFound,
    1881             :                                                                                 objType,
    1882           3 :                                                                                 HPWH.Name,
    1883             :                                                                                 DataLoopNode::NodeFluidType::Air,
    1884             :                                                                                 DataLoopNode::ConnectionType::Outlet,
    1885             :                                                                                 NodeInputManager::CompFluidStream::Primary,
    1886             :                                                                                 DataLoopNode::ObjectIsParent);
    1887             : 
    1888           3 :                 HPWH.HeatPumpAirOutletNode = NodeInputManager::GetOnlySingleNode(state,
    1889           3 :                                                                                  hpwhAlpha[8 + nAlphaOffset],
    1890             :                                                                                  ErrorsFound,
    1891             :                                                                                  objType,
    1892           3 :                                                                                  HPWH.Name,
    1893             :                                                                                  DataLoopNode::NodeFluidType::Air,
    1894             :                                                                                  DataLoopNode::ConnectionType::Outlet,
    1895             :                                                                                  NodeInputManager::CompFluidStream::Primary,
    1896             :                                                                                  DataLoopNode::ObjectIsParent);
    1897             : 
    1898             :             } else { // HPWH is connected to a zone with no mixer/splitter nodes
    1899          17 :                 if (HPWH.InletAirConfiguration == WTTAmbientTemp::TempZone) {
    1900           7 :                     HPWH.HeatPumpAirInletNode = NodeInputManager::GetOnlySingleNode(state,
    1901           7 :                                                                                     hpwhAlpha[7 + nAlphaOffset],
    1902             :                                                                                     ErrorsFound,
    1903             :                                                                                     objType,
    1904           7 :                                                                                     HPWH.Name,
    1905             :                                                                                     DataLoopNode::NodeFluidType::Air,
    1906             :                                                                                     DataLoopNode::ConnectionType::Inlet,
    1907             :                                                                                     NodeInputManager::CompFluidStream::Primary,
    1908             :                                                                                     DataLoopNode::ObjectIsParent);
    1909             : 
    1910           7 :                     HPWH.HeatPumpAirOutletNode = NodeInputManager::GetOnlySingleNode(state,
    1911           7 :                                                                                      hpwhAlpha[8 + nAlphaOffset],
    1912             :                                                                                      ErrorsFound,
    1913             :                                                                                      objType,
    1914           7 :                                                                                      HPWH.Name,
    1915             :                                                                                      DataLoopNode::NodeFluidType::Air,
    1916             :                                                                                      DataLoopNode::ConnectionType::Outlet,
    1917             :                                                                                      NodeInputManager::CompFluidStream::Primary,
    1918             :                                                                                      DataLoopNode::ObjectIsParent);
    1919             :                 } else { // HPWH is located outdoors
    1920          10 :                     HPWH.OutsideAirNode = NodeInputManager::GetOnlySingleNode(state,
    1921          10 :                                                                               hpwhAlpha[9 + nAlphaOffset],
    1922             :                                                                               ErrorsFound,
    1923             :                                                                               objType,
    1924          10 :                                                                               HPWH.Name,
    1925             :                                                                               DataLoopNode::NodeFluidType::Air,
    1926             :                                                                               DataLoopNode::ConnectionType::OutsideAirReference,
    1927             :                                                                               NodeInputManager::CompFluidStream::Primary,
    1928             :                                                                               DataLoopNode::ObjectIsParent);
    1929          10 :                     if (!hpwhAlphaBlank[9 + nAlphaOffset]) {
    1930             :                         bool Okay;
    1931          10 :                         OutAirNodeManager::CheckAndAddAirNodeNumber(state, HPWH.OutsideAirNode, Okay);
    1932          10 :                         if (!Okay) {
    1933           0 :                             ShowWarningError(state,
    1934           0 :                                              format("{}=\"{}\": Adding outdoor air node ={}",
    1935           0 :                                                     state.dataIPShortCut->cCurrentModuleObject,
    1936           0 :                                                     HPWH.Name,
    1937           0 :                                                     hpwhAlpha[9 + nAlphaOffset]));
    1938             :                         }
    1939             :                     }
    1940             : 
    1941          10 :                     HPWH.ExhaustAirNode = NodeInputManager::GetOnlySingleNode(state,
    1942          10 :                                                                               hpwhAlpha[10 + nAlphaOffset],
    1943             :                                                                               ErrorsFound,
    1944             :                                                                               objType,
    1945          10 :                                                                               HPWH.Name,
    1946             :                                                                               DataLoopNode::NodeFluidType::Air,
    1947             :                                                                               DataLoopNode::ConnectionType::ReliefAir,
    1948             :                                                                               NodeInputManager::CompFluidStream::Primary,
    1949             :                                                                               DataLoopNode::ObjectIsParent);
    1950             :                 }
    1951             :             }
    1952             :         }
    1953             :         // check that required node names are present
    1954          23 :         if (HPWH.InletAirConfiguration == WTTAmbientTemp::Schedule || HPWH.InletAirConfiguration == WTTAmbientTemp::TempZone) {
    1955          10 :             if (HPWH.HeatPumpAirInletNode == 0 || HPWH.HeatPumpAirOutletNode == 0) {
    1956           0 :                 ShowSevereError(state, format("{}=\"{}\":", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    1957           0 :                 ShowContinueError(state, format("When {}=\"{}\".", hpwhAlphaFieldNames[6 + nAlphaOffset], hpwhAlpha[6 + nAlphaOffset]));
    1958           0 :                 ShowContinueError(
    1959           0 :                     state, format("{} and {} must be specified.", hpwhAlphaFieldNames[7 + nAlphaOffset], hpwhAlphaFieldNames[8 + nAlphaOffset]));
    1960           0 :                 ErrorsFound = true;
    1961             :             }
    1962          13 :         } else if (HPWH.InletAirConfiguration == WTTAmbientTemp::OutsideAir) {
    1963          10 :             if (HPWH.OutsideAirNode == 0 || HPWH.ExhaustAirNode == 0) {
    1964           0 :                 ShowSevereError(state, format("{}=\"{}\":", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    1965           0 :                 ShowContinueError(state, format("When {}=\"{}\".", hpwhAlphaFieldNames[6 + nAlphaOffset], hpwhAlpha[6 + nAlphaOffset]));
    1966           0 :                 ShowContinueError(
    1967           0 :                     state, format("{} and {} must be specified.", hpwhAlphaFieldNames[9 + nAlphaOffset], hpwhAlphaFieldNames[10 + nAlphaOffset]));
    1968           0 :                 ErrorsFound = true;
    1969             :             }
    1970           3 :         } else if (HPWH.InletAirMixerNode > 0 && HPWH.OutletAirSplitterNode > 0 && HPWH.InletAirConfiguration == WTTAmbientTemp::ZoneAndOA) {
    1971           3 :             if (HPWH.HeatPumpAirInletNode == 0 || HPWH.HeatPumpAirOutletNode == 0 || HPWH.OutsideAirNode == 0 || HPWH.ExhaustAirNode == 0) {
    1972           0 :                 ShowSevereError(state, format("{}=\"{}\":", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    1973           0 :                 ShowContinueError(state, format("When {}=\"{}\".", hpwhAlphaFieldNames[6 + nAlphaOffset], hpwhAlpha[6 + nAlphaOffset]));
    1974           0 :                 if (HPWH.HeatPumpAirInletNode == 0 || HPWH.HeatPumpAirOutletNode == 0) {
    1975           0 :                     ShowContinueError(
    1976           0 :                         state, format("{} and {} must be specified.", hpwhAlphaFieldNames[7 + nAlphaOffset], hpwhAlphaFieldNames[8 + nAlphaOffset]));
    1977             :                 }
    1978           0 :                 if (HPWH.OutsideAirNode == 0 || HPWH.ExhaustAirNode == 0) {
    1979           0 :                     ShowContinueError(
    1980           0 :                         state, format("{} and {} must be specified.", hpwhAlphaFieldNames[9 + nAlphaOffset], hpwhAlphaFieldNames[10 + nAlphaOffset]));
    1981             :                 }
    1982           0 :                 ErrorsFound = true;
    1983             :             }
    1984             :         }
    1985             : 
    1986             :         // check that the HPWH inlet and outlet nodes are in the same zone (ZoneHVAC:EquipmentConnections) when
    1987             :         // Inlet Air Configuration is Zone Air Only or Zone and Outdoor Air
    1988          23 :         if ((HPWH.InletAirConfiguration == WTTAmbientTemp::TempZone || HPWH.InletAirConfiguration == WTTAmbientTemp::ZoneAndOA) &&
    1989          10 :             HPWH.AmbientTempZone > 0) {
    1990          10 :             if (allocated(state.dataZoneEquip->ZoneEquipConfig)) {
    1991          10 :                 bool FoundInletNode = false;
    1992          10 :                 bool FoundOutletNode = false;
    1993          10 :                 int ZoneNum = HPWH.AmbientTempZone;
    1994          10 :                 if (ZoneNum <= state.dataGlobal->NumOfZones) {
    1995          37 :                     for (int SupAirIn = 1; SupAirIn <= state.dataZoneEquip->ZoneEquipConfig(ZoneNum).NumInletNodes; ++SupAirIn) {
    1996          27 :                         if (HPWH.HeatPumpAirOutletNode != state.dataZoneEquip->ZoneEquipConfig(ZoneNum).InletNode(SupAirIn)) continue;
    1997          10 :                         FoundOutletNode = true;
    1998             :                     }
    1999          27 :                     for (int ExhAirOut = 1; ExhAirOut <= state.dataZoneEquip->ZoneEquipConfig(ZoneNum).NumExhaustNodes; ++ExhAirOut) {
    2000          17 :                         if (HPWH.HeatPumpAirInletNode != state.dataZoneEquip->ZoneEquipConfig(ZoneNum).ExhaustNode(ExhAirOut)) continue;
    2001          10 :                         FoundInletNode = true;
    2002             :                     }
    2003          10 :                     if (!FoundInletNode) {
    2004           0 :                         ShowSevereError(state, format("{}=\"{}\":", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    2005           0 :                         ShowContinueError(state,
    2006           0 :                                           format("The HPWH's air inlet node name = {} was not properly specified ", hpwhAlpha[7 + nAlphaOffset]));
    2007           0 :                         ShowContinueError(
    2008             :                             state,
    2009           0 :                             format("as an exhaust air node for zone = {} in a ZoneHVAC:EquipmentConnections object.", hpwhAlpha[13 + nAlphaOffset]));
    2010           0 :                         ErrorsFound = true;
    2011             :                     }
    2012          10 :                     if (!FoundOutletNode) {
    2013           0 :                         ShowSevereError(state, format("{}=\"{}\":", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    2014           0 :                         ShowContinueError(state,
    2015           0 :                                           format("The HPWH's air outlet node name = {} was not properly specified ", hpwhAlpha[8 + nAlphaOffset]));
    2016           0 :                         ShowContinueError(
    2017             :                             state,
    2018           0 :                             format("as an inlet air node for zone = {} in a ZoneHVAC:EquipmentConnections object.", hpwhAlpha[13 + nAlphaOffset]));
    2019           0 :                         ErrorsFound = true;
    2020             :                     }
    2021             :                 }
    2022             :             } else {
    2023           0 :                 ShowSevereError(state, format("{}=\"{}\":", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    2024           0 :                 ShowContinueError(state,
    2025             :                                   "Heat pump water heater air inlet node name and air outlet node name must be listed in a "
    2026             :                                   "ZoneHVAC:EquipmentConnections object when Inlet Air Configuration is equal to ZoneAirOnly or "
    2027             :                                   "ZoneAndOutdoorAir.");
    2028           0 :                 ErrorsFound = true;
    2029             :             }
    2030             :         }
    2031             : 
    2032             :         // only get the inlet air mixer schedule if the inlet air configuration is zone and outdoor air
    2033          23 :         if (!hpwhAlphaBlank[28 + nAlphaOffset] && HPWH.InletAirConfiguration == WTTAmbientTemp::ZoneAndOA) {
    2034           3 :             HPWH.InletAirMixerSchPtr = ScheduleManager::GetScheduleIndex(state, hpwhAlpha[28 + nAlphaOffset]);
    2035           3 :             if (HPWH.InletAirMixerSchPtr == 0) {
    2036           0 :                 ShowSevereError(state, format("{}=\"{}\", not found", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    2037           0 :                 ShowContinueError(state, format("{}=\"{}\",", hpwhAlphaFieldNames[28 + nAlphaOffset], hpwhAlpha[28 + nAlphaOffset]));
    2038           0 :                 ErrorsFound = true;
    2039             :             } else {
    2040           3 :                 bool ValidScheduleValue = ScheduleManager::CheckScheduleValueMinMax(state, HPWH.InletAirMixerSchPtr, ">=", 0.0, "<=", 1.0);
    2041           3 :                 if (!ValidScheduleValue) {
    2042           0 :                     ShowSevereError(state, format("{}=\"{}\", not found", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    2043           0 :                     ShowContinueError(state,
    2044           0 :                                       format("{} values out of range of 0 to 1, Schedule=\"{}\".",
    2045           0 :                                              hpwhAlphaFieldNames[28 + nAlphaOffset],
    2046           0 :                                              hpwhAlpha[28 + nAlphaOffset]));
    2047           0 :                     ErrorsFound = true;
    2048             :                 }
    2049             :                 //           set outlet air splitter schedule index equal to inlet air mixer schedule index
    2050             :                 //           (place holder for when zone pressurization/depressurization is allowed and different schedules can be used)
    2051           3 :                 HPWH.OutletAirSplitterSchPtr = ScheduleManager::GetScheduleIndex(state, hpwhAlpha[28 + nAlphaOffset]);
    2052             :             }
    2053             :         }
    2054             : 
    2055             :         // set fan outlet node variable for use in setting Node(FanOutletNode)%MassFlowRateMax for fan object
    2056          23 :         if (HPWH.fanPlace == HVAC::FanPlace::DrawThru) {
    2057          11 :             if (HPWH.OutletAirSplitterNode != 0) {
    2058           3 :                 HPWH.FanOutletNode = HPWH.OutletAirSplitterNode;
    2059             :             } else {
    2060           8 :                 if (HPWH.InletAirConfiguration == WTTAmbientTemp::OutsideAir) {
    2061           1 :                     HPWH.FanOutletNode = HPWH.ExhaustAirNode;
    2062             :                 } else {
    2063           7 :                     HPWH.FanOutletNode = HPWH.HeatPumpAirOutletNode;
    2064             :                 }
    2065             :             }
    2066          12 :         } else if (HPWH.fanPlace == HVAC::FanPlace::BlowThru) {
    2067             :             // set fan outlet node variable for use in setting Node(FanOutletNode)%MassFlowRateMax for fan object
    2068          12 :             if (bIsVScoil) {
    2069           5 :                 if (HPWH.bIsIHP) {
    2070           1 :                     HPWH.FanOutletNode = IntegratedHeatPump::GetDWHCoilInletNodeIHP(state, HPWH.DXCoilType, HPWH.DXCoilName, DXCoilErrFlag);
    2071             :                 } else {
    2072           4 :                     HPWH.FanOutletNode = VariableSpeedCoils::GetCoilInletNodeVariableSpeed(state, HPWH.DXCoilType, HPWH.DXCoilName, DXCoilErrFlag);
    2073             :                 }
    2074             :             } else {
    2075           7 :                 HPWH.FanOutletNode = state.dataDXCoils->DXCoil(HPWH.DXCoilNum).AirInNode;
    2076             :             }
    2077             :         }
    2078             : 
    2079             :         // check that fan outlet node is indeed correct
    2080          23 :         int FanOutletNodeNum = state.dataFans->fans(HPWH.FanNum)->outletNodeNum;
    2081             : 
    2082          23 :         if (FanOutletNodeNum != HPWH.FanOutletNode) {
    2083           0 :             ShowSevereError(state, format("{}=\"{}\":", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    2084           0 :             ShowContinueError(state, "Heat pump water heater fan outlet node name does not match next connected component.");
    2085           0 :             if (FanOutletNodeNum != 0) {
    2086           0 :                 ShowContinueError(state, format("Fan outlet node name = {}", state.dataLoopNodes->NodeID(FanOutletNodeNum)));
    2087             :             }
    2088           0 :             if (HPWH.FanOutletNode != 0) {
    2089           0 :                 ShowContinueError(state, format("Expected fan outlet node name = {}", state.dataLoopNodes->NodeID(HPWH.FanOutletNode)));
    2090             :             }
    2091           0 :             ErrorsFound = true;
    2092             :         }
    2093          23 :         int FanInletNodeNum = state.dataFans->fans(HPWH.FanNum)->inletNodeNum;
    2094             : 
    2095          23 :         int HPWHFanInletNodeNum(0);
    2096          23 :         if (HPWH.InletAirMixerNode != 0) {
    2097           3 :             HPWHFanInletNodeNum = HPWH.InletAirMixerNode;
    2098             :         } else {
    2099          20 :             if (HPWH.InletAirConfiguration == WTTAmbientTemp::OutsideAir) {
    2100          10 :                 HPWHFanInletNodeNum = HPWH.OutsideAirNode;
    2101             :             } else {
    2102          10 :                 HPWHFanInletNodeNum = HPWH.HeatPumpAirInletNode;
    2103             :             }
    2104             :         }
    2105          23 :         if (HPWH.fanPlace == HVAC::FanPlace::BlowThru) {
    2106          12 :             if (FanInletNodeNum != HPWHFanInletNodeNum) {
    2107           0 :                 ShowSevereError(state, format("{}=\"{}\":", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    2108           0 :                 ShowContinueError(state, "Heat pump water heater fan inlet node name does not match previous connected component.");
    2109           0 :                 if (FanOutletNodeNum != 0) {
    2110           0 :                     ShowContinueError(state, format("Fan inlet node name = {}", state.dataLoopNodes->NodeID(FanInletNodeNum)));
    2111             :                 }
    2112           0 :                 if (HPWH.FanOutletNode != 0) {
    2113           0 :                     ShowContinueError(state, format("Expected fan inlet node name = {}", state.dataLoopNodes->NodeID(HPWHFanInletNodeNum)));
    2114             :                 }
    2115           0 :                 ErrorsFound = true;
    2116             :             }
    2117             :         }
    2118             : 
    2119          23 :         int DXCoilAirOutletNodeNum(0);
    2120          23 :         if ((HPWH.DXCoilNum > 0) && (bIsVScoil)) {
    2121           7 :             if (HPWH.bIsIHP) {
    2122           1 :                 DXCoilAirOutletNodeNum = IntegratedHeatPump::GetDWHCoilOutletNodeIHP(state, HPWH.DXCoilType, HPWH.DXCoilName, DXCoilErrFlag);
    2123             :             } else {
    2124           6 :                 DXCoilAirOutletNodeNum = VariableSpeedCoils::GetCoilOutletNodeVariableSpeed(state, HPWH.DXCoilType, HPWH.DXCoilName, DXCoilErrFlag);
    2125             :             }
    2126             : 
    2127          16 :         } else if (HPWH.DXCoilNum > 0) {
    2128          16 :             DXCoilAirOutletNodeNum = state.dataDXCoils->DXCoil(HPWH.DXCoilNum).AirOutNode;
    2129             :         }
    2130          23 :         if (HPWH.fanPlace == HVAC::FanPlace::DrawThru) {
    2131          11 :             if (FanInletNodeNum != DXCoilAirOutletNodeNum) {
    2132           0 :                 ShowSevereError(state, format("{}=\"{}\":", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    2133           0 :                 ShowContinueError(state, "Heat pump water heater fan inlet node name does not match previous connected component.");
    2134           0 :                 if (FanInletNodeNum != 0) {
    2135           0 :                     ShowContinueError(state, format("Fan inlet node name = {}", state.dataLoopNodes->NodeID(FanInletNodeNum)));
    2136             :                 }
    2137           0 :                 if (DXCoilAirOutletNodeNum != 0) {
    2138           0 :                     ShowContinueError(state, format("Expected fan inlet node name = {}", state.dataLoopNodes->NodeID(DXCoilAirOutletNodeNum)));
    2139             :                 }
    2140           0 :                 ErrorsFound = true;
    2141             :             }
    2142          12 :         } else if (HPWH.fanPlace == HVAC::FanPlace::BlowThru) {
    2143          12 :             int HPWHCoilOutletNodeNum(0);
    2144          12 :             if (HPWH.OutletAirSplitterNode != 0) {
    2145           0 :                 HPWHCoilOutletNodeNum = HPWH.OutletAirSplitterNode;
    2146             :             } else {
    2147          12 :                 if (HPWH.InletAirConfiguration == WTTAmbientTemp::OutsideAir) {
    2148           9 :                     HPWHCoilOutletNodeNum = HPWH.ExhaustAirNode;
    2149             :                 } else {
    2150           3 :                     HPWHCoilOutletNodeNum = HPWH.HeatPumpAirOutletNode;
    2151             :                 }
    2152             :             }
    2153          12 :             if (DXCoilAirOutletNodeNum != HPWHCoilOutletNodeNum) {
    2154           0 :                 ShowSevereError(state, format("{}=\"{}\":", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    2155           0 :                 ShowContinueError(state, "Heat pump water heater coil outlet node name does not match next connected component.");
    2156           0 :                 if (DXCoilAirOutletNodeNum != 0) {
    2157           0 :                     ShowContinueError(state, format("Coil outlet node name = {}", state.dataLoopNodes->NodeID(DXCoilAirOutletNodeNum)));
    2158             :                 }
    2159           0 :                 if (HPWHCoilOutletNodeNum != 0) {
    2160           0 :                     ShowContinueError(state, format("Expected coil outlet node name = {}", state.dataLoopNodes->NodeID(HPWHCoilOutletNodeNum)));
    2161             :                 }
    2162           0 :                 ErrorsFound = true;
    2163             :             }
    2164             :         }
    2165             : 
    2166             :         // set the max mass flow rate for outdoor fans
    2167          23 :         if (HPWH.FanOutletNode > 0)
    2168          23 :             state.dataLoopNodes->Node(HPWH.FanOutletNode).MassFlowRateMax =
    2169          46 :                 HPWH.OperatingAirFlowRate * Psychrometrics::PsyRhoAirFnPbTdbW(state, state.dataEnvrn->OutBaroPress, 20.0, 0.0);
    2170             : 
    2171          23 :         if (HPWH.fanPlace == HVAC::FanPlace::BlowThru) {
    2172          12 :             if (HPWH.InletAirMixerNode > 0) {
    2173           0 :                 HPWH.FanInletNode_str = hpwhAlpha[26 + nAlphaOffset];
    2174           0 :                 HPWH.FanOutletNode_str = "UNDEFINED";
    2175             :             } else {
    2176          12 :                 if (HPWH.OutsideAirNode == 0) {
    2177           3 :                     HPWH.FanInletNode_str = hpwhAlpha[7 + nAlphaOffset];
    2178           3 :                     HPWH.FanOutletNode_str = "UNDEFINED";
    2179             :                 } else {
    2180           9 :                     HPWH.FanInletNode_str = hpwhAlpha[9 + nAlphaOffset];
    2181           9 :                     HPWH.FanOutletNode_str = "UNDEFINED";
    2182             :                 }
    2183             :             }
    2184          12 :             if (HPWH.OutletAirSplitterNode > 0) {
    2185           0 :                 HPWH.CoilInletNode_str = "UNDEFINED";
    2186           0 :                 HPWH.CoilOutletNode_str = hpwhAlpha[27 + nAlphaOffset];
    2187             :             } else {
    2188          12 :                 if (HPWH.OutsideAirNode == 0) {
    2189           3 :                     HPWH.CoilInletNode_str = "UNDEFINED";
    2190           3 :                     HPWH.CoilOutletNode_str = hpwhAlpha[8 + nAlphaOffset];
    2191             :                 } else {
    2192           9 :                     HPWH.CoilInletNode_str = "UNDEFINED";
    2193           9 :                     HPWH.CoilOutletNode_str = hpwhAlpha[10 + nAlphaOffset];
    2194             :                 }
    2195             :             }
    2196             :         } else {
    2197          11 :             if (HPWH.InletAirMixerNode > 0) {
    2198           3 :                 HPWH.CoilInletNode_str = hpwhAlpha[26 + nAlphaOffset];
    2199           3 :                 HPWH.CoilOutletNode_str = "UNDEFINED";
    2200             :             } else {
    2201           8 :                 if (HPWH.OutsideAirNode == 0) {
    2202           7 :                     HPWH.CoilInletNode_str = hpwhAlpha[7 + nAlphaOffset];
    2203           7 :                     HPWH.CoilOutletNode_str = "UNDEFINED";
    2204             :                 } else {
    2205           1 :                     HPWH.CoilInletNode_str = hpwhAlpha[9 + nAlphaOffset];
    2206           1 :                     HPWH.CoilOutletNode_str = "UNDEFINED";
    2207             :                 }
    2208             :             }
    2209          11 :             if (HPWH.OutletAirSplitterNode > 0) {
    2210           3 :                 HPWH.FanInletNode_str = "UNDEFINED";
    2211           3 :                 HPWH.FanOutletNode_str = hpwhAlpha[27 + nAlphaOffset];
    2212             :             } else {
    2213           8 :                 if (HPWH.OutsideAirNode == 0) {
    2214           7 :                     HPWH.FanInletNode_str = "UNDEFINED";
    2215           7 :                     HPWH.FanOutletNode_str = hpwhAlpha[8 + nAlphaOffset];
    2216             :                 } else {
    2217           1 :                     HPWH.FanInletNode_str = "UNDEFINED";
    2218           1 :                     HPWH.FanOutletNode_str = hpwhAlpha[10 + nAlphaOffset];
    2219             :                 }
    2220             :             }
    2221             :         }
    2222             : 
    2223             :         // set up comp set for air side nodes (can be blow thru or draw thru, may or may not have damper nodes)
    2224          23 :         if (HPWH.bIsIHP) {
    2225           2 :             BranchNodeConnections::SetUpCompSets(
    2226           2 :                 state, HPWH.Type, HPWH.Name, HPWH.DXCoilType, HPWH.DXCoilName + " Outdoor Coil", HPWH.CoilInletNode_str, HPWH.CoilOutletNode_str);
    2227             :         } else {
    2228          22 :             BranchNodeConnections::SetUpCompSets(
    2229             :                 state, HPWH.Type, HPWH.Name, HPWH.DXCoilType, HPWH.DXCoilName, HPWH.CoilInletNode_str, HPWH.CoilOutletNode_str);
    2230             :         }
    2231             : 
    2232          46 :         BranchNodeConnections::SetUpCompSets(
    2233          23 :             state, HPWH.Type, HPWH.Name, HVAC::fanTypeNames[(int)HPWH.fanType], HPWH.FanName, HPWH.FanInletNode_str, HPWH.FanOutletNode_str);
    2234             : 
    2235             :         // Control Logic Flag
    2236          23 :         std::string CtrlLogicFlag = hpwhAlphaBlank[29 + nAlphaOffset] ? "SIMULTANEOUS" : hpwhAlpha[29 + nAlphaOffset];
    2237          23 :         if (Util::SameString(CtrlLogicFlag, "SIMULTANEOUS")) {
    2238          20 :             HPWH.AllowHeatingElementAndHeatPumpToRunAtSameTime = true;
    2239           3 :         } else if (Util::SameString(CtrlLogicFlag, "MUTUALLYEXCLUSIVE")) {
    2240           3 :             HPWH.AllowHeatingElementAndHeatPumpToRunAtSameTime = false;
    2241             :         } else {
    2242           0 :             ShowSevereError(state, format("{}=\"{}\":", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    2243           0 :             ShowContinueError(state, format("{} is not a valid value for field Tank Element Control Logic.", CtrlLogicFlag));
    2244           0 :             ErrorsFound = true;
    2245             :         }
    2246             : 
    2247             :         // Control Sensor 1 Location In Stratified Tank
    2248          23 :         if (!hpwhNumericBlank[8 + nNumericOffset]) {
    2249          11 :             HPWH.ControlSensor1Height = hpwhNumeric[8 + nNumericOffset];
    2250             :         } else {
    2251             :             // use heater1 location, which we don't know right now
    2252          12 :             HPWH.ControlSensor1Height = -1.0;
    2253             :         }
    2254             : 
    2255             :         // Control Sensor 1 Weight
    2256          23 :         HPWH.ControlSensor1Weight = hpwhNumericBlank[9 + nNumericOffset] ? 1.0 : hpwhNumeric[9 + nNumericOffset];
    2257             : 
    2258             :         // Control Sensor 2 Location In Stratified Tank
    2259          23 :         if (!hpwhNumericBlank[10 + nNumericOffset]) {
    2260          23 :             HPWH.ControlSensor2Height = hpwhNumeric[10 + nNumericOffset];
    2261             :         } else {
    2262           0 :             HPWH.ControlSensor2Height = -1.0;
    2263             :         }
    2264             : 
    2265             :         // Control Sensor 2 Weight
    2266          23 :         HPWH.ControlSensor2Weight = 1.0 - HPWH.ControlSensor1Weight;
    2267          23 :     }
    2268             : 
    2269           9 :     return ErrorsFound;
    2270             : }
    2271             : 
    2272         123 : bool getWaterHeaterMixedInputs(EnergyPlusData &state)
    2273             : {
    2274         123 :     bool ErrorsFound = false;
    2275         123 :     state.dataIPShortCut->cCurrentModuleObject = cMixedWHModuleObj;
    2276             :     static constexpr std::string_view RoutineName = "getWaterHeaterMixedInputs";
    2277             : 
    2278         299 :     for (int WaterThermalTankNum = 1; WaterThermalTankNum <= state.dataWaterThermalTanks->numWaterHeaterMixed; ++WaterThermalTankNum) {
    2279             :         int NumAlphas;
    2280             :         int NumNums;
    2281             :         int IOStat;
    2282         352 :         state.dataInputProcessing->inputProcessor->getObjectItem(state,
    2283         176 :                                                                  state.dataIPShortCut->cCurrentModuleObject,
    2284             :                                                                  WaterThermalTankNum,
    2285         176 :                                                                  state.dataIPShortCut->cAlphaArgs,
    2286             :                                                                  NumAlphas,
    2287         176 :                                                                  state.dataIPShortCut->rNumericArgs,
    2288             :                                                                  NumNums,
    2289             :                                                                  IOStat,
    2290         176 :                                                                  state.dataIPShortCut->lNumericFieldBlanks,
    2291         176 :                                                                  state.dataIPShortCut->lAlphaFieldBlanks,
    2292         176 :                                                                  state.dataIPShortCut->cAlphaFieldNames,
    2293         176 :                                                                  state.dataIPShortCut->cNumericFieldNames);
    2294         176 :         GlobalNames::VerifyUniqueInterObjectName(state,
    2295         176 :                                                  state.dataWaterThermalTanks->UniqueWaterThermalTankNames,
    2296         176 :                                                  state.dataIPShortCut->cAlphaArgs(1),
    2297         176 :                                                  state.dataIPShortCut->cCurrentModuleObject,
    2298         176 :                                                  state.dataIPShortCut->cAlphaFieldNames(1),
    2299             :                                                  ErrorsFound);
    2300             : 
    2301         176 :         auto &Tank = state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum);
    2302             : 
    2303         176 :         Tank.Name = state.dataIPShortCut->cAlphaArgs(1);
    2304         176 :         Tank.Type = state.dataIPShortCut->cCurrentModuleObject;
    2305         176 :         Tank.WaterThermalTankType = DataPlant::PlantEquipmentType::WtrHeaterMixed;
    2306         176 :         Tank.FluidIndex = Tank.waterIndex;
    2307             : 
    2308             :         // default to always on
    2309         176 :         Tank.SourceSideAvailSchedNum = ScheduleManager::ScheduleAlwaysOn;
    2310         176 :         Tank.UseSideAvailSchedNum = ScheduleManager::ScheduleAlwaysOn;
    2311             : 
    2312             :         // A user field will be added in a later release
    2313         176 :         Tank.EndUseSubcategoryName = "Water Heater";
    2314             : 
    2315         176 :         Tank.Volume = state.dataIPShortCut->rNumericArgs(1);
    2316         176 :         if (Tank.Volume == DataSizing::AutoSize) {
    2317           2 :             Tank.VolumeWasAutoSized = true;
    2318             :         }
    2319         176 :         if (state.dataIPShortCut->rNumericArgs(1) == 0.0) {
    2320             :             // Set volume to a really small number to simulate a tankless/instantaneous water heater
    2321           0 :             Tank.Volume = 0.000001; // = 1 cm3
    2322             :         }
    2323             : 
    2324         176 :         Tank.SetPointTempSchedule = ScheduleManager::GetScheduleIndex(state, state.dataIPShortCut->cAlphaArgs(2));
    2325         176 :         if (state.dataIPShortCut->lAlphaFieldBlanks(2)) {
    2326           0 :             ShowSevereError(
    2327             :                 state,
    2328           0 :                 format("{}{}=\"{}\", missing data.", RoutineName, state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
    2329           0 :             ShowContinueError(state, format("blank field, missing {} is required", state.dataIPShortCut->cAlphaFieldNames(2)));
    2330           0 :             ErrorsFound = true;
    2331         176 :         } else if (Tank.SetPointTempSchedule == 0) {
    2332           0 :             ShowSevereError(state,
    2333           0 :                             format("{} = {}:  {} not found = {}",
    2334           0 :                                    state.dataIPShortCut->cCurrentModuleObject,
    2335           0 :                                    state.dataIPShortCut->cAlphaArgs(1),
    2336           0 :                                    state.dataIPShortCut->cAlphaFieldNames(2),
    2337           0 :                                    state.dataIPShortCut->cAlphaArgs(2)));
    2338           0 :             ErrorsFound = true;
    2339             :         }
    2340             : 
    2341         176 :         if (state.dataIPShortCut->rNumericArgs(2) > 0.0001) {
    2342         170 :             Tank.DeadBandDeltaTemp = state.dataIPShortCut->rNumericArgs(2);
    2343             :         } else {
    2344             :             // Default to very small number (however it can't be TINY or it will break the algorithm)
    2345           6 :             Tank.DeadBandDeltaTemp = 0.5;
    2346             :         }
    2347             : 
    2348         176 :         if (state.dataIPShortCut->rNumericArgs(3) > 0.0) {
    2349         176 :             Tank.TankTempLimit = state.dataIPShortCut->rNumericArgs(3);
    2350             :         } else {
    2351             :             // Default to very large number
    2352             :             // BG comment why a large number here why not boilng point of water?
    2353           0 :             Tank.TankTempLimit = 100.0; // 1.0E9
    2354             :         }
    2355             : 
    2356         176 :         Tank.MaxCapacity = state.dataIPShortCut->rNumericArgs(4);
    2357         176 :         if (Tank.MaxCapacity == DataSizing::AutoSize) {
    2358           1 :             Tank.MaxCapacityWasAutoSized = true;
    2359             :         }
    2360             : 
    2361         176 :         if ((state.dataIPShortCut->rNumericArgs(5) > Tank.MaxCapacity) && (!Tank.MaxCapacityWasAutoSized)) {
    2362           0 :             ShowSevereError(state,
    2363           0 :                             format("{} = {}:  Heater Minimum Capacity cannot be greater than Heater Maximum Capacity",
    2364           0 :                                    state.dataIPShortCut->cCurrentModuleObject,
    2365           0 :                                    state.dataIPShortCut->cAlphaArgs(1)));
    2366           0 :             ErrorsFound = true;
    2367             :         } else {
    2368         176 :             Tank.MinCapacity = state.dataIPShortCut->rNumericArgs(5);
    2369             :         }
    2370             : 
    2371             :         // Validate Heater Control Type
    2372         176 :         Tank.ControlType =
    2373         176 :             static_cast<HeaterControlMode>(getEnumValue(HeaterControlModeNamesUC, Util::makeUPPER(state.dataIPShortCut->cAlphaArgs(3))));
    2374         176 :         switch (Tank.ControlType) {
    2375         171 :         case HeaterControlMode::Cycle: {
    2376         171 :             Tank.MinCapacity = Tank.MaxCapacity;
    2377         171 :             break;
    2378             :         }
    2379           5 :         case HeaterControlMode::Modulate: {
    2380             : 
    2381             :             // CASE ('MODULATE WITH OVERHEAT')  ! Not yet implemented
    2382             : 
    2383             :             // CASE ('MODULATE WITH UNDERHEAT')  ! Not yet implemented
    2384             : 
    2385           5 :             break;
    2386             :         }
    2387           0 :         default: {
    2388           0 :             ShowSevereError(state,
    2389           0 :                             format("{} = {}:  Invalid Control Type entered={}",
    2390           0 :                                    state.dataIPShortCut->cCurrentModuleObject,
    2391           0 :                                    state.dataIPShortCut->cAlphaArgs(1),
    2392           0 :                                    state.dataIPShortCut->cAlphaArgs(3)));
    2393           0 :             ErrorsFound = true;
    2394           0 :             break;
    2395             :         }
    2396             :         }
    2397             : 
    2398         176 :         Tank.VolFlowRateMin = state.dataIPShortCut->rNumericArgs(6);
    2399         176 :         Tank.VolFlowRateMin = max(0.0, Tank.VolFlowRateMin);
    2400         176 :         Tank.IgnitionDelay = state.dataIPShortCut->rNumericArgs(7); // Not yet implemented
    2401             : 
    2402             :         // Validate Heater Fuel Type
    2403         176 :         Tank.FuelType = static_cast<Constant::eFuel>(getEnumValue(Constant::eFuelNamesUC, state.dataIPShortCut->cAlphaArgs(4)));
    2404         176 :         switch (Tank.FuelType) {
    2405           0 :         case Constant::eFuel::Invalid: {
    2406           0 :             ShowSevereError(state,
    2407           0 :                             format("{} = {}:  Invalid Heater Fuel Type entered={}",
    2408           0 :                                    state.dataIPShortCut->cCurrentModuleObject,
    2409           0 :                                    state.dataIPShortCut->cAlphaArgs(1),
    2410           0 :                                    state.dataIPShortCut->cAlphaArgs(4)));
    2411             :             // Set to Electric to avoid errors when setting up output variables
    2412           0 :             Tank.FuelType = Constant::eFuel::Electricity;
    2413           0 :             ErrorsFound = true;
    2414           0 :             break;
    2415             :         }
    2416         176 :         default:
    2417         176 :             break;
    2418             :         }
    2419             : 
    2420         176 :         if (state.dataIPShortCut->rNumericArgs(8) > 0.0) {
    2421         176 :             Tank.Efficiency = state.dataIPShortCut->rNumericArgs(8);
    2422         176 :             if (state.dataIPShortCut->rNumericArgs(8) > 1.0) {
    2423           0 :                 ShowWarningError(state,
    2424           0 :                                  fmt::format("{} = {}: {}={} should not typically be greater than 1.",
    2425           0 :                                              state.dataIPShortCut->cCurrentModuleObject,
    2426           0 :                                              state.dataIPShortCut->cAlphaArgs(1),
    2427           0 :                                              state.dataIPShortCut->cNumericFieldNames(8),
    2428           0 :                                              state.dataIPShortCut->rNumericArgs(8)));
    2429             :             }
    2430             :         } else {
    2431           0 :             ShowSevereError(state,
    2432           0 :                             format("{} = {}:  Heater Thermal Efficiency must be greater than zero",
    2433           0 :                                    state.dataIPShortCut->cCurrentModuleObject,
    2434           0 :                                    state.dataIPShortCut->cAlphaArgs(1)));
    2435           0 :             ErrorsFound = true;
    2436             :         }
    2437             : 
    2438         176 :         if (!state.dataIPShortCut->cAlphaArgs(5).empty()) {
    2439           0 :             Tank.PLFCurve = Curve::GetCurveIndex(state, state.dataIPShortCut->cAlphaArgs(5));
    2440           0 :             if (Tank.PLFCurve == 0) {
    2441           0 :                 ShowSevereError(state,
    2442           0 :                                 format("{} = {}:  Part Load Factor curve not found = {}",
    2443           0 :                                        state.dataIPShortCut->cCurrentModuleObject,
    2444           0 :                                        state.dataIPShortCut->cAlphaArgs(1),
    2445           0 :                                        state.dataIPShortCut->cAlphaArgs(5)));
    2446           0 :                 ErrorsFound = true;
    2447             :             } else {
    2448             :                 bool IsValid;
    2449           0 :                 EnergyPlus::WaterThermalTanks::WaterThermalTankData::ValidatePLFCurve(state, Tank.PLFCurve, IsValid);
    2450             : 
    2451           0 :                 if (!IsValid) {
    2452           0 :                     ShowSevereError(
    2453             :                         state,
    2454           0 :                         format("{} = {}:  Part Load Factor curve failed to evaluate to greater than zero for all numbers in the domain of 0 to 1",
    2455           0 :                                state.dataIPShortCut->cCurrentModuleObject,
    2456           0 :                                state.dataIPShortCut->cAlphaArgs(1)));
    2457           0 :                     ErrorsFound = true;
    2458             :                 }
    2459             : 
    2460           0 :                 ErrorsFound |= Curve::CheckCurveDims(state,
    2461             :                                                      Tank.PLFCurve,                              // Curve index
    2462             :                                                      {1},                                        // Valid dimensions
    2463             :                                                      RoutineName,                                // Routine name
    2464           0 :                                                      state.dataIPShortCut->cCurrentModuleObject, // Object Type
    2465             :                                                      Tank.Name,                                  // Object Name
    2466           0 :                                                      state.dataIPShortCut->cAlphaFieldNames(5)); // Field Name
    2467             :             }
    2468             :         }
    2469             : 
    2470         176 :         Tank.OffCycParaLoad = state.dataIPShortCut->rNumericArgs(9);
    2471             : 
    2472             :         // Validate Off-Cycle Parasitic Fuel Type
    2473         176 :         Tank.OffCycParaFuelType = static_cast<Constant::eFuel>(getEnumValue(Constant::eFuelNamesUC, state.dataIPShortCut->cAlphaArgs(6)));
    2474         176 :         switch (Tank.OffCycParaFuelType) {
    2475          16 :         case Constant::eFuel::Invalid:
    2476          16 :             if (state.dataIPShortCut->cAlphaArgs(6).empty()) { // If blank, default to Fuel Type for heater
    2477          16 :                 Tank.OffCycParaFuelType = Tank.FuelType;
    2478             :             } else { // could have been an unsupported value
    2479           0 :                 ShowSevereError(state,
    2480           0 :                                 format("{} = {}:  Invalid Off-Cycle Parasitic Fuel Type entered={}",
    2481           0 :                                        state.dataIPShortCut->cCurrentModuleObject,
    2482           0 :                                        state.dataIPShortCut->cAlphaArgs(1),
    2483           0 :                                        state.dataIPShortCut->cAlphaArgs(6)));
    2484             :                 // Set to Electric to avoid errors when setting up output variables
    2485           0 :                 Tank.OffCycParaFuelType = Constant::eFuel::Electricity;
    2486           0 :                 ErrorsFound = true;
    2487             :             }
    2488          16 :             break;
    2489         160 :         default:
    2490         160 :             break;
    2491             :         }
    2492             : 
    2493         176 :         Tank.OffCycParaFracToTank = state.dataIPShortCut->rNumericArgs(10);
    2494             : 
    2495         176 :         Tank.OnCycParaLoad = state.dataIPShortCut->rNumericArgs(11);
    2496             : 
    2497             :         // Validate On-Cycle Parasitic Fuel Type
    2498         176 :         Tank.OnCycParaFuelType = static_cast<Constant::eFuel>(getEnumValue(Constant::eFuelNamesUC, state.dataIPShortCut->cAlphaArgs(7)));
    2499         176 :         switch (Tank.OnCycParaFuelType) {
    2500          56 :         case Constant::eFuel::Invalid:
    2501          56 :             if (state.dataIPShortCut->cAlphaArgs(7).empty()) { // If blank, default to Fuel Type for heater
    2502          56 :                 Tank.OnCycParaFuelType = Tank.FuelType;
    2503             :             } else { // could have been an unsupported value
    2504           0 :                 ShowSevereError(state,
    2505           0 :                                 format("{} = {}:  Invalid On-Cycle Parasitic Fuel Type entered={}",
    2506           0 :                                        state.dataIPShortCut->cCurrentModuleObject,
    2507           0 :                                        state.dataIPShortCut->cAlphaArgs(1),
    2508           0 :                                        state.dataIPShortCut->cAlphaArgs(7)));
    2509             :                 // Set to Electric to avoid errors when setting up output variables
    2510           0 :                 Tank.OnCycParaFuelType = Constant::eFuel::Electricity;
    2511           0 :                 ErrorsFound = true;
    2512             :             }
    2513          56 :             break;
    2514         120 :         default:
    2515         120 :             break;
    2516             :         }
    2517             : 
    2518         176 :         Tank.OnCycParaFracToTank = state.dataIPShortCut->rNumericArgs(12);
    2519             : 
    2520         176 :         Tank.AmbientTempIndicator =
    2521         176 :             static_cast<WTTAmbientTemp>(getEnumValue(TankAmbientTempNamesUC, Util::makeUPPER(state.dataIPShortCut->cAlphaArgs(8))));
    2522         176 :         switch (Tank.AmbientTempIndicator) {
    2523          99 :         case WTTAmbientTemp::Schedule: {
    2524          99 :             Tank.AmbientTempSchedule = ScheduleManager::GetScheduleIndex(state, state.dataIPShortCut->cAlphaArgs(9));
    2525          99 :             if (Tank.AmbientTempSchedule == 0) {
    2526           0 :                 ShowSevereError(state,
    2527           0 :                                 format("{} = {}:  Ambient Temperature Schedule not found = {}",
    2528           0 :                                        state.dataIPShortCut->cCurrentModuleObject,
    2529           0 :                                        state.dataIPShortCut->cAlphaArgs(1),
    2530           0 :                                        state.dataIPShortCut->cAlphaArgs(9)));
    2531           0 :                 ErrorsFound = true;
    2532             :             }
    2533             : 
    2534          99 :             break;
    2535             :         }
    2536          70 :         case WTTAmbientTemp::TempZone: {
    2537          70 :             Tank.AmbientTempZone = Util::FindItemInList(state.dataIPShortCut->cAlphaArgs(10), state.dataHeatBal->Zone);
    2538          70 :             if (Tank.AmbientTempZone == 0) {
    2539           0 :                 ShowSevereError(state,
    2540           0 :                                 format("{} = {}:  Ambient Temperature Zone not found = {}",
    2541           0 :                                        state.dataIPShortCut->cCurrentModuleObject,
    2542           0 :                                        state.dataIPShortCut->cAlphaArgs(1),
    2543           0 :                                        state.dataIPShortCut->cAlphaArgs(10)));
    2544           0 :                 ErrorsFound = true;
    2545             :             }
    2546             : 
    2547          70 :             break;
    2548             :         }
    2549           7 :         case WTTAmbientTemp::OutsideAir: {
    2550           7 :             Tank.AmbientTempOutsideAirNode = NodeInputManager::GetOnlySingleNode(state,
    2551           7 :                                                                                  state.dataIPShortCut->cAlphaArgs(11),
    2552             :                                                                                  ErrorsFound,
    2553             :                                                                                  DataLoopNode::ConnectionObjectType::WaterHeaterMixed,
    2554           7 :                                                                                  state.dataIPShortCut->cAlphaArgs(1),
    2555             :                                                                                  DataLoopNode::NodeFluidType::Air,
    2556             :                                                                                  DataLoopNode::ConnectionType::OutsideAirReference,
    2557             :                                                                                  NodeInputManager::CompFluidStream::Primary,
    2558             :                                                                                  DataLoopNode::ObjectIsNotParent);
    2559           7 :             if (!state.dataIPShortCut->cAlphaArgs(11).empty()) {
    2560           7 :                 if (!OutAirNodeManager::CheckOutAirNodeNumber(state, Tank.AmbientTempOutsideAirNode)) {
    2561           0 :                     ShowSevereError(state,
    2562           0 :                                     format("{} = {}: Outdoor Air Node not on OutdoorAir:NodeList or OutdoorAir:Node",
    2563           0 :                                            state.dataIPShortCut->cCurrentModuleObject,
    2564           0 :                                            state.dataIPShortCut->cAlphaArgs(1)));
    2565           0 :                     ShowContinueError(state, format("...Referenced Node Name={}", state.dataIPShortCut->cAlphaArgs(11)));
    2566           0 :                     ErrorsFound = true;
    2567             :                 }
    2568             :             } else {
    2569           0 :                 ShowSevereError(state, format("{} = {}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
    2570           0 :                 ShowContinueError(state, "An Ambient Outdoor Air Node name must be used when the Ambient Temperature Indicator is Outdoors.");
    2571           0 :                 ErrorsFound = true;
    2572             :             }
    2573             : 
    2574           7 :             break;
    2575             :         }
    2576           0 :         default: {
    2577           0 :             ShowSevereError(state,
    2578           0 :                             format("{} = {}:  Invalid Ambient Temperature Indicator entered={}",
    2579           0 :                                    state.dataIPShortCut->cCurrentModuleObject,
    2580           0 :                                    state.dataIPShortCut->cAlphaArgs(1),
    2581           0 :                                    state.dataIPShortCut->cAlphaArgs(8)));
    2582           0 :             ShowContinueError(state, " Valid entries are SCHEDULE, ZONE, and OUTDOORS.");
    2583           0 :             ErrorsFound = true;
    2584           0 :             break;
    2585             :         }
    2586             :         }
    2587             : 
    2588         176 :         Tank.OffCycLossCoeff = state.dataIPShortCut->rNumericArgs(13);
    2589         176 :         Tank.OffCycLossFracToZone = state.dataIPShortCut->rNumericArgs(14);
    2590             : 
    2591         176 :         Tank.OnCycLossCoeff = state.dataIPShortCut->rNumericArgs(15);
    2592         176 :         Tank.OnCycLossFracToZone = state.dataIPShortCut->rNumericArgs(16);
    2593         176 :         Real64 rho = FluidProperties::GetDensityGlycol(state, fluidNameWater, Constant::InitConvTemp, Tank.FluidIndex, RoutineName);
    2594         176 :         Tank.MassFlowRateMax = state.dataIPShortCut->rNumericArgs(17) * rho;
    2595             : 
    2596         176 :         if ((state.dataIPShortCut->cAlphaArgs(14).empty()) && (state.dataIPShortCut->cAlphaArgs(15).empty())) {
    2597          61 :             if (!state.dataIPShortCut->cAlphaArgs(12).empty()) {
    2598          61 :                 Tank.FlowRateSchedule = ScheduleManager::GetScheduleIndex(state, state.dataIPShortCut->cAlphaArgs(12));
    2599          61 :                 if (Tank.FlowRateSchedule == 0) {
    2600           0 :                     ShowSevereError(state,
    2601           0 :                                     format("{} = {}:  Flow Rate Schedule not found = {}",
    2602           0 :                                            state.dataIPShortCut->cCurrentModuleObject,
    2603           0 :                                            state.dataIPShortCut->cAlphaArgs(1),
    2604           0 :                                            state.dataIPShortCut->cAlphaArgs(12)));
    2605           0 :                     ErrorsFound = true;
    2606             :                 }
    2607             :             }
    2608             :         }
    2609             : 
    2610         176 :         if (!state.dataIPShortCut->cAlphaArgs(13).empty()) {
    2611           9 :             Tank.UseInletTempSchedule = ScheduleManager::GetScheduleIndex(state, state.dataIPShortCut->cAlphaArgs(13));
    2612           9 :             if (Tank.UseInletTempSchedule == 0) {
    2613           0 :                 ShowSevereError(state,
    2614           0 :                                 format("{} = {}:  Cold Water Supply Temperature Schedule not found = {}",
    2615           0 :                                        state.dataIPShortCut->cCurrentModuleObject,
    2616           0 :                                        state.dataIPShortCut->cAlphaArgs(1),
    2617           0 :                                        state.dataIPShortCut->cAlphaArgs(13)));
    2618           0 :                 ErrorsFound = true;
    2619             :             }
    2620             :         }
    2621             : 
    2622         176 :         if (NumNums > 17) {
    2623         131 :             if ((state.dataIPShortCut->rNumericArgs(18) > 1) || (state.dataIPShortCut->rNumericArgs(18) < 0)) {
    2624           0 :                 ShowSevereError(state,
    2625           0 :                                 format("{} = {}:  Use Side Effectiveness is out of bounds (0 to 1)",
    2626           0 :                                        state.dataIPShortCut->cCurrentModuleObject,
    2627           0 :                                        state.dataIPShortCut->cAlphaArgs(1)));
    2628           0 :                 ErrorsFound = true;
    2629             :             }
    2630         131 :             Tank.UseEffectiveness = state.dataIPShortCut->rNumericArgs(18);
    2631             :         } else {
    2632          45 :             Tank.UseEffectiveness = 1.0; // Default for stand-alone mode
    2633             :         }
    2634             : 
    2635         176 :         if (NumNums > 18) {
    2636         131 :             if ((state.dataIPShortCut->rNumericArgs(19) > 1) || (state.dataIPShortCut->rNumericArgs(19) <= 0)) {
    2637           0 :                 ShowSevereError(state,
    2638           0 :                                 format("{} = {}:  Source Side Effectiveness is out of bounds (>0 to 1)",
    2639           0 :                                        state.dataIPShortCut->cCurrentModuleObject,
    2640           0 :                                        state.dataIPShortCut->cAlphaArgs(1)));
    2641           0 :                 ErrorsFound = true;
    2642             :             }
    2643         131 :             Tank.SourceEffectiveness = state.dataIPShortCut->rNumericArgs(19);
    2644             :         } else {
    2645          45 :             Tank.SourceEffectiveness = 1.0;
    2646             :         }
    2647             : 
    2648             :         // If no plant nodes are connected, simulate in stand-alone mode.
    2649         298 :         if (state.dataIPShortCut->cAlphaArgs(14).empty() && state.dataIPShortCut->cAlphaArgs(15).empty() &&
    2650         298 :             state.dataIPShortCut->cAlphaArgs(16).empty() && state.dataIPShortCut->cAlphaArgs(17).empty()) {
    2651          47 :             Tank.StandAlone = true;
    2652             :         }
    2653             : 
    2654         176 :         if (!state.dataIPShortCut->lNumericFieldBlanks(20)) {
    2655         115 :             Tank.UseDesignVolFlowRate = state.dataIPShortCut->rNumericArgs(20);
    2656         115 :             if (Tank.UseDesignVolFlowRate == DataSizing::AutoSize) {
    2657         109 :                 Tank.UseDesignVolFlowRateWasAutoSized = true;
    2658             :             }
    2659             :         } else {
    2660          61 :             Tank.UseDesignVolFlowRate = 0.0;
    2661             :         }
    2662         176 :         Tank.UseSidePlantLoc.loopSideNum = DataPlant::LoopSideLocation::Invalid;
    2663             : 
    2664         176 :         if (!state.dataIPShortCut->lNumericFieldBlanks(21)) {
    2665         108 :             Tank.SourceDesignVolFlowRate = state.dataIPShortCut->rNumericArgs(21);
    2666         108 :             if (Tank.SourceDesignVolFlowRate == DataSizing::AutoSize) {
    2667          98 :                 Tank.SourceDesignVolFlowRateWasAutoSized = true;
    2668             :             }
    2669             :         } else {
    2670          68 :             Tank.SourceDesignVolFlowRate = 0.0;
    2671             :         }
    2672         176 :         Tank.SrcSidePlantLoc.loopSideNum = DataPlant::LoopSideLocation::Invalid;
    2673             : 
    2674         176 :         if (!state.dataIPShortCut->lNumericFieldBlanks(22)) {
    2675          94 :             Tank.SizingRecoveryTime = state.dataIPShortCut->rNumericArgs(22);
    2676             :         } else {
    2677          82 :             Tank.SizingRecoveryTime = 1.5;
    2678             :         }
    2679             : 
    2680         176 :         if ((!state.dataIPShortCut->cAlphaArgs(14).empty()) || (!state.dataIPShortCut->cAlphaArgs(15).empty())) {
    2681         115 :             Tank.UseInletNode = NodeInputManager::GetOnlySingleNode(state,
    2682         115 :                                                                     state.dataIPShortCut->cAlphaArgs(14),
    2683             :                                                                     ErrorsFound,
    2684             :                                                                     DataLoopNode::ConnectionObjectType::WaterHeaterMixed,
    2685         115 :                                                                     state.dataIPShortCut->cAlphaArgs(1),
    2686             :                                                                     DataLoopNode::NodeFluidType::Water,
    2687             :                                                                     DataLoopNode::ConnectionType::Inlet,
    2688             :                                                                     NodeInputManager::CompFluidStream::Primary,
    2689             :                                                                     DataLoopNode::ObjectIsNotParent);
    2690         115 :             Tank.InletNodeName1 = state.dataIPShortCut->cAlphaArgs(14);
    2691         115 :             Tank.UseOutletNode = NodeInputManager::GetOnlySingleNode(state,
    2692         115 :                                                                      state.dataIPShortCut->cAlphaArgs(15),
    2693             :                                                                      ErrorsFound,
    2694             :                                                                      DataLoopNode::ConnectionObjectType::WaterHeaterMixed,
    2695         115 :                                                                      state.dataIPShortCut->cAlphaArgs(1),
    2696             :                                                                      DataLoopNode::NodeFluidType::Water,
    2697             :                                                                      DataLoopNode::ConnectionType::Outlet,
    2698             :                                                                      NodeInputManager::CompFluidStream::Primary,
    2699             :                                                                      DataLoopNode::ObjectIsNotParent);
    2700         115 :             Tank.OutletNodeName1 = state.dataIPShortCut->cAlphaArgs(15);
    2701             : 
    2702         115 :             if (state.dataIPShortCut->rNumericArgs(17) > 0) {
    2703           0 :                 ShowWarningError(state,
    2704           0 :                                  format("{} = {}:  Use side nodes are specified; Peak Volumetric Use Flow Rate will not be used",
    2705           0 :                                         state.dataIPShortCut->cCurrentModuleObject,
    2706           0 :                                         state.dataIPShortCut->cAlphaArgs(1)));
    2707             :             }
    2708             : 
    2709         115 :             if (Tank.FlowRateSchedule > 0) {
    2710           0 :                 ShowWarningError(state,
    2711           0 :                                  format("{} = {}:  Use side nodes are specified; Use Flow Rate Fraction Schedule will not be used",
    2712           0 :                                         state.dataIPShortCut->cCurrentModuleObject,
    2713           0 :                                         state.dataIPShortCut->cAlphaArgs(1)));
    2714             :             }
    2715             : 
    2716         115 :             if (Tank.UseInletTempSchedule > 0) {
    2717           0 :                 ShowWarningError(state,
    2718           0 :                                  format("{} = {}:  Use side nodes are specified; Cold Water Supply Temperature Schedule will not be used",
    2719           0 :                                         state.dataIPShortCut->cCurrentModuleObject,
    2720           0 :                                         state.dataIPShortCut->cAlphaArgs(1)));
    2721             :             }
    2722             :         }
    2723             : 
    2724         176 :         if ((!state.dataIPShortCut->cAlphaArgs(16).empty()) || (!state.dataIPShortCut->cAlphaArgs(17).empty())) {
    2725          33 :             Tank.SourceInletNode = NodeInputManager::GetOnlySingleNode(state,
    2726          33 :                                                                        state.dataIPShortCut->cAlphaArgs(16),
    2727             :                                                                        ErrorsFound,
    2728             :                                                                        DataLoopNode::ConnectionObjectType::WaterHeaterMixed,
    2729          33 :                                                                        state.dataIPShortCut->cAlphaArgs(1),
    2730             :                                                                        DataLoopNode::NodeFluidType::Water,
    2731             :                                                                        DataLoopNode::ConnectionType::Inlet,
    2732             :                                                                        NodeInputManager::CompFluidStream::Secondary,
    2733             :                                                                        DataLoopNode::ObjectIsNotParent);
    2734          33 :             Tank.InletNodeName2 = state.dataIPShortCut->cAlphaArgs(16);
    2735          33 :             Tank.SourceOutletNode = NodeInputManager::GetOnlySingleNode(state,
    2736          33 :                                                                         state.dataIPShortCut->cAlphaArgs(17),
    2737             :                                                                         ErrorsFound,
    2738             :                                                                         DataLoopNode::ConnectionObjectType::WaterHeaterMixed,
    2739          33 :                                                                         state.dataIPShortCut->cAlphaArgs(1),
    2740             :                                                                         DataLoopNode::NodeFluidType::Water,
    2741             :                                                                         DataLoopNode::ConnectionType::Outlet,
    2742             :                                                                         NodeInputManager::CompFluidStream::Secondary,
    2743             :                                                                         DataLoopNode::ObjectIsNotParent);
    2744          33 :             Tank.OutletNodeName2 = state.dataIPShortCut->cAlphaArgs(17);
    2745             :         }
    2746             : 
    2747         176 :         if (!state.dataIPShortCut->lAlphaFieldBlanks(18)) {
    2748           1 :             Tank.SourceSideControlMode =
    2749           1 :                 static_cast<SourceSideControl>(getEnumValue(SourceSideControlNamesUC, Util::makeUPPER(state.dataIPShortCut->cAlphaArgs(18))));
    2750           1 :             if (Tank.SourceSideControlMode == SourceSideControl::Invalid) {
    2751           0 :                 ShowSevereError(state,
    2752           0 :                                 format("{} = {}:  Invalid Control Mode entered={}",
    2753           0 :                                        state.dataIPShortCut->cCurrentModuleObject,
    2754           0 :                                        state.dataIPShortCut->cAlphaArgs(1),
    2755           0 :                                        state.dataIPShortCut->cAlphaArgs(18)));
    2756           0 :                 ErrorsFound = true;
    2757             :             }
    2758             :         } else {
    2759         175 :             Tank.SourceSideControlMode = SourceSideControl::IndirectHeatPrimarySetpoint;
    2760             :         }
    2761             : 
    2762         176 :         if (!state.dataIPShortCut->lAlphaFieldBlanks(19)) {
    2763           0 :             Tank.SourceSideAltSetpointSchedNum = ScheduleManager::GetScheduleIndex(state, state.dataIPShortCut->cAlphaArgs(19));
    2764           0 :             if (Tank.SourceSideAltSetpointSchedNum == 0) {
    2765           0 :                 ShowSevereError(state,
    2766           0 :                                 format("{} = {}:  {} not found = {}",
    2767           0 :                                        state.dataIPShortCut->cCurrentModuleObject,
    2768           0 :                                        state.dataIPShortCut->cAlphaArgs(1),
    2769           0 :                                        state.dataIPShortCut->cAlphaFieldNames(19),
    2770           0 :                                        state.dataIPShortCut->cAlphaArgs(19)));
    2771           0 :                 ErrorsFound = true;
    2772             :             }
    2773             :         }
    2774         176 :         if (NumAlphas > 19) {
    2775           1 :             Tank.EndUseSubcategoryName = state.dataIPShortCut->cAlphaArgs(20);
    2776             :         }
    2777             : 
    2778             :     } // WaterThermalTankNum
    2779             : 
    2780         123 :     return ErrorsFound;
    2781             : }
    2782             : 
    2783          10 : bool getWaterHeaterStratifiedInput(EnergyPlusData &state)
    2784             : {
    2785          10 :     bool ErrorsFound = false;
    2786             :     static constexpr std::string_view RoutineName = "getWaterHeaterStratifiedInput";
    2787             : 
    2788          10 :     state.dataIPShortCut->cCurrentModuleObject = cStratifiedWHModuleObj; //'WaterHeater:Stratified'
    2789             : 
    2790          26 :     for (int WaterThermalTankNum = state.dataWaterThermalTanks->numWaterHeaterMixed + 1;
    2791          26 :          WaterThermalTankNum <= state.dataWaterThermalTanks->numWaterHeaterMixed + state.dataWaterThermalTanks->numWaterHeaterStratified;
    2792             :          ++WaterThermalTankNum) {
    2793             :         int NumAlphas;
    2794             :         int NumNums;
    2795             :         int IOStat;
    2796          32 :         state.dataInputProcessing->inputProcessor->getObjectItem(state,
    2797          16 :                                                                  state.dataIPShortCut->cCurrentModuleObject,
    2798          16 :                                                                  WaterThermalTankNum - state.dataWaterThermalTanks->numWaterHeaterMixed,
    2799          16 :                                                                  state.dataIPShortCut->cAlphaArgs,
    2800             :                                                                  NumAlphas,
    2801          16 :                                                                  state.dataIPShortCut->rNumericArgs,
    2802             :                                                                  NumNums,
    2803             :                                                                  IOStat,
    2804          16 :                                                                  state.dataIPShortCut->lNumericFieldBlanks,
    2805          16 :                                                                  state.dataIPShortCut->lAlphaFieldBlanks,
    2806          16 :                                                                  state.dataIPShortCut->cAlphaFieldNames,
    2807          16 :                                                                  state.dataIPShortCut->cNumericFieldNames);
    2808          16 :         GlobalNames::VerifyUniqueInterObjectName(state,
    2809          16 :                                                  state.dataWaterThermalTanks->UniqueWaterThermalTankNames,
    2810          16 :                                                  state.dataIPShortCut->cAlphaArgs(1),
    2811          16 :                                                  state.dataIPShortCut->cCurrentModuleObject,
    2812          16 :                                                  state.dataIPShortCut->cAlphaFieldNames(1),
    2813             :                                                  ErrorsFound);
    2814             : 
    2815          16 :         auto &Tank = state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum);
    2816             : 
    2817          16 :         Tank.Name = state.dataIPShortCut->cAlphaArgs(1);
    2818          16 :         Tank.Type = state.dataIPShortCut->cCurrentModuleObject;
    2819          16 :         Tank.WaterThermalTankType = DataPlant::PlantEquipmentType::WtrHeaterStratified;
    2820          16 :         Tank.FluidIndex = Tank.waterIndex;
    2821             : 
    2822             :         // default to always on
    2823          16 :         Tank.SourceSideAvailSchedNum = ScheduleManager::ScheduleAlwaysOn;
    2824          16 :         Tank.UseSideAvailSchedNum = ScheduleManager::ScheduleAlwaysOn;
    2825             : 
    2826          16 :         Tank.EndUseSubcategoryName = state.dataIPShortCut->cAlphaArgs(2);
    2827             : 
    2828          16 :         Tank.Volume = state.dataIPShortCut->rNumericArgs(1);
    2829          16 :         if (Tank.Volume == DataSizing::AutoSize) {
    2830           0 :             Tank.VolumeWasAutoSized = true;
    2831             :         }
    2832          16 :         Real64 rho = FluidProperties::GetDensityGlycol(state, fluidNameWater, Constant::InitConvTemp, Tank.FluidIndex, RoutineName);
    2833          16 :         Tank.Mass = Tank.Volume * rho;
    2834          16 :         Tank.Height = state.dataIPShortCut->rNumericArgs(2);
    2835          16 :         if (Tank.Height == DataSizing::AutoSize) {
    2836           0 :             Tank.HeightWasAutoSized = true;
    2837             :         }
    2838             : 
    2839          16 :         Tank.Shape = static_cast<TankShape>(getEnumValue(TankShapeNamesUC, Util::makeUPPER(state.dataIPShortCut->cAlphaArgs(3))));
    2840          16 :         switch (Tank.Shape) {
    2841          16 :         case TankShape::HorizCylinder:
    2842             :         case TankShape::VertCylinder: {
    2843          16 :             break;
    2844             :         }
    2845           0 :         case TankShape::Other: {
    2846           0 :             if (state.dataIPShortCut->rNumericArgs(3) > 0.0) {
    2847           0 :                 Tank.Perimeter = state.dataIPShortCut->rNumericArgs(3);
    2848             :             } else {
    2849           0 :                 ShowSevereError(state,
    2850           0 :                                 format("{} = {}:  Tank Perimeter must be greater than zero for Tank Shape=OTHER",
    2851           0 :                                        state.dataIPShortCut->cCurrentModuleObject,
    2852           0 :                                        state.dataIPShortCut->cAlphaArgs(1)));
    2853           0 :                 ErrorsFound = true;
    2854             :             }
    2855             : 
    2856           0 :             break;
    2857             :         }
    2858           0 :         default: {
    2859           0 :             ShowSevereError(state,
    2860           0 :                             format("{} = {}:  Invalid Tank Shape entered={}",
    2861           0 :                                    state.dataIPShortCut->cCurrentModuleObject,
    2862           0 :                                    state.dataIPShortCut->cAlphaArgs(1),
    2863           0 :                                    state.dataIPShortCut->cAlphaArgs(3)));
    2864           0 :             Tank.Shape = TankShape::VertCylinder;
    2865           0 :             ErrorsFound = true;
    2866           0 :             break;
    2867             :         }
    2868             :         }
    2869             : 
    2870          16 :         if (state.dataIPShortCut->rNumericArgs(4) > 0.0) {
    2871          16 :             Tank.TankTempLimit = state.dataIPShortCut->rNumericArgs(4);
    2872             :         } else {
    2873             :             // Default to very large number
    2874           0 :             Tank.TankTempLimit = 1.0e9;
    2875             :         }
    2876             : 
    2877             :         // Validate Heater Priority Control
    2878          16 :         Tank.StratifiedControlMode =
    2879          16 :             static_cast<PriorityControlMode>(getEnumValue(PriorityControlModeNamesUC, Util::makeUPPER(state.dataIPShortCut->cAlphaArgs(4))));
    2880          16 :         if (Tank.StratifiedControlMode == PriorityControlMode::Invalid) {
    2881           0 :             ShowSevereError(state,
    2882           0 :                             format("{} = {}:  Invalid Heater Priority Control entered={}",
    2883           0 :                                    state.dataIPShortCut->cCurrentModuleObject,
    2884           0 :                                    state.dataIPShortCut->cAlphaArgs(1),
    2885           0 :                                    state.dataIPShortCut->cAlphaArgs(4)));
    2886           0 :             ErrorsFound = true;
    2887             :         }
    2888             : 
    2889          16 :         Tank.SetPointTempSchedule = ScheduleManager::GetScheduleIndex(state, state.dataIPShortCut->cAlphaArgs(5));
    2890          16 :         if (state.dataIPShortCut->lAlphaFieldBlanks(5)) {
    2891           0 :             ShowSevereError(
    2892             :                 state,
    2893           0 :                 format("{}{}=\"{}\", missing data.", RoutineName, state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
    2894           0 :             ShowContinueError(state, format("blank field, missing {} is required", state.dataIPShortCut->cAlphaFieldNames(5)));
    2895           0 :             ErrorsFound = true;
    2896          16 :         } else if (Tank.SetPointTempSchedule == 0) {
    2897           0 :             ShowSevereError(state,
    2898           0 :                             format("{} = {}: {} not found = {}",
    2899           0 :                                    state.dataIPShortCut->cCurrentModuleObject,
    2900           0 :                                    state.dataIPShortCut->cAlphaArgs(1),
    2901           0 :                                    state.dataIPShortCut->cAlphaFieldNames(5),
    2902           0 :                                    state.dataIPShortCut->cAlphaArgs(5)));
    2903           0 :             ErrorsFound = true;
    2904             :         }
    2905             : 
    2906          16 :         if (state.dataIPShortCut->rNumericArgs(5) > 0.0) {
    2907          16 :             Tank.DeadBandDeltaTemp = state.dataIPShortCut->rNumericArgs(5);
    2908             :         } else {
    2909             :             // Default to very small number (however it can't be TINY or it will break the algorithm)
    2910           0 :             Tank.DeadBandDeltaTemp = 0.0001;
    2911             :         }
    2912             : 
    2913          16 :         Tank.MaxCapacity = state.dataIPShortCut->rNumericArgs(6);
    2914          16 :         if (Tank.MaxCapacity == DataSizing::AutoSize) {
    2915           2 :             Tank.MaxCapacityWasAutoSized = true;
    2916             :         }
    2917             : 
    2918          16 :         Tank.HeaterHeight1 = state.dataIPShortCut->rNumericArgs(7);
    2919             : 
    2920             :         // adjust tank height used in these calculations for testing heater height
    2921             :         Real64 tankHeightForTesting;
    2922          16 :         if (Tank.Shape == TankShape::HorizCylinder) {
    2923           0 :             tankHeightForTesting = 2.0 * sqrt((Tank.Volume / Tank.Height) / Constant::Pi);
    2924             :         } else {
    2925          16 :             tankHeightForTesting = Tank.Height;
    2926             :         }
    2927             : 
    2928             :         // Test if Heater height is within range
    2929          16 :         if ((!Tank.HeightWasAutoSized) && (Tank.HeaterHeight1 > tankHeightForTesting)) {
    2930           0 :             ShowSevereError(state,
    2931           0 :                             format("{} = {}: Heater 1 is located higher than overall tank height.",
    2932           0 :                                    state.dataIPShortCut->cCurrentModuleObject,
    2933           0 :                                    state.dataIPShortCut->cAlphaArgs(1)));
    2934           0 :             ShowContinueError(state, format("{} = {:.4R}", state.dataIPShortCut->cNumericFieldNames(2), state.dataIPShortCut->rNumericArgs(2)));
    2935           0 :             ShowContinueError(state, format("{} = {:.4R}", state.dataIPShortCut->cNumericFieldNames(7), state.dataIPShortCut->rNumericArgs(7)));
    2936           0 :             ErrorsFound = true;
    2937             :         }
    2938             : 
    2939          16 :         Tank.SetPointTempSchedule2 = ScheduleManager::GetScheduleIndex(state, state.dataIPShortCut->cAlphaArgs(6));
    2940          16 :         if (state.dataIPShortCut->lAlphaFieldBlanks(6)) {
    2941           0 :             ShowSevereError(
    2942             :                 state,
    2943           0 :                 format("{}{}=\"{}\", missing data.", RoutineName, state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
    2944           0 :             ShowContinueError(state, format("blank field, missing {} is required", state.dataIPShortCut->cAlphaFieldNames(6)));
    2945           0 :             ErrorsFound = true;
    2946          16 :         } else if (Tank.SetPointTempSchedule2 == 0) {
    2947           0 :             ShowSevereError(state,
    2948           0 :                             format("{} = {}:  {} not found = {}",
    2949           0 :                                    state.dataIPShortCut->cCurrentModuleObject,
    2950           0 :                                    state.dataIPShortCut->cAlphaArgs(1),
    2951           0 :                                    state.dataIPShortCut->cAlphaFieldNames(6),
    2952           0 :                                    state.dataIPShortCut->cAlphaArgs(6)));
    2953           0 :             ErrorsFound = true;
    2954             :         }
    2955             : 
    2956          16 :         if (state.dataIPShortCut->rNumericArgs(5) > 0.0) {
    2957          16 :             Tank.DeadBandDeltaTemp2 = state.dataIPShortCut->rNumericArgs(8);
    2958             :         } else {
    2959             :             // Default to very small number (however it can't be TINY or it will break the algorithm)
    2960           0 :             Tank.DeadBandDeltaTemp2 = 0.0001;
    2961             :         }
    2962             : 
    2963          16 :         Tank.MaxCapacity2 = state.dataIPShortCut->rNumericArgs(9);
    2964          16 :         Tank.HeaterHeight2 = state.dataIPShortCut->rNumericArgs(10);
    2965             : 
    2966             :         // Test if Heater height is within range
    2967          16 :         if ((!Tank.HeightWasAutoSized) && (Tank.HeaterHeight2 > tankHeightForTesting)) {
    2968           0 :             ShowSevereError(state,
    2969           0 :                             format("{} = {}: Heater 2 is located higher than overall tank height.",
    2970           0 :                                    state.dataIPShortCut->cCurrentModuleObject,
    2971           0 :                                    state.dataIPShortCut->cAlphaArgs(1)));
    2972           0 :             ShowContinueError(state, format("{} = {:.4R}", state.dataIPShortCut->cNumericFieldNames(2), state.dataIPShortCut->rNumericArgs(2)));
    2973           0 :             ShowContinueError(state, format("{} = {:.4R}", state.dataIPShortCut->cNumericFieldNames(10), state.dataIPShortCut->rNumericArgs(10)));
    2974           0 :             ErrorsFound = true;
    2975             :         }
    2976             : 
    2977             :         // Validate Heater Fuel Type
    2978          16 :         Tank.FuelType = static_cast<Constant::eFuel>(
    2979          16 :             getEnumValue(Constant::eFuelNamesUC,
    2980          16 :                          state.dataIPShortCut->cAlphaArgs(
    2981             :                              7))); // returns all kinds of fuels including district heat and cool + steam, returns unassigned if unsupported
    2982          16 :         if (Tank.FuelType == Constant::eFuel::Invalid) {
    2983           0 :             ShowSevereError(state,
    2984           0 :                             format("{} = {}:  Invalid Heater Fuel Type entered={}",
    2985           0 :                                    state.dataIPShortCut->cCurrentModuleObject,
    2986           0 :                                    state.dataIPShortCut->cAlphaArgs(1),
    2987           0 :                                    state.dataIPShortCut->cAlphaArgs(7)));
    2988             :             // Set to Electric to avoid errors when setting up output variables
    2989           0 :             Tank.FuelType = Constant::eFuel::Electricity;
    2990           0 :             ErrorsFound = true;
    2991             :         }
    2992             : 
    2993          16 :         if (state.dataIPShortCut->rNumericArgs(11) > 0.0) {
    2994          16 :             Tank.Efficiency = state.dataIPShortCut->rNumericArgs(11);
    2995          16 :             if (state.dataIPShortCut->rNumericArgs(11) > 1.0) {
    2996           0 :                 ShowWarningError(state,
    2997           0 :                                  fmt::format("{} = {}: {}={} should not typically be greater than 1.",
    2998           0 :                                              state.dataIPShortCut->cCurrentModuleObject,
    2999           0 :                                              state.dataIPShortCut->cAlphaArgs(1),
    3000           0 :                                              state.dataIPShortCut->cNumericFieldNames(11),
    3001           0 :                                              state.dataIPShortCut->rNumericArgs(11)));
    3002             :             }
    3003             :         } else {
    3004           0 :             ShowSevereError(state,
    3005           0 :                             format("{} = {}:  Heater Thermal Efficiency must be greater than zero",
    3006           0 :                                    state.dataIPShortCut->cCurrentModuleObject,
    3007           0 :                                    state.dataIPShortCut->cAlphaArgs(1)));
    3008           0 :             ErrorsFound = true;
    3009             :         }
    3010             : 
    3011          16 :         Tank.OffCycParaLoad = state.dataIPShortCut->rNumericArgs(12);
    3012             : 
    3013             :         // Validate Off-Cycle Parasitic Fuel Type
    3014          16 :         Tank.OffCycParaFuelType = static_cast<Constant::eFuel>(
    3015          16 :             getEnumValue(Constant::eFuelNamesUC,
    3016          16 :                          state.dataIPShortCut->cAlphaArgs(
    3017             :                              8))); // returns all kinds of fuels including district heat and cool + steam, returns unassigned if unsupported
    3018          16 :         if (Tank.OffCycParaFuelType == Constant::eFuel::Invalid) {
    3019           0 :             if (state.dataIPShortCut->cAlphaArgs(8).empty()) {
    3020           0 :                 Tank.OffCycParaFuelType = Tank.FuelType;
    3021             :             } else {
    3022           0 :                 ShowSevereError(state,
    3023           0 :                                 format("{} = {}:  Invalid Off-Cycle Parasitic Fuel Type entered={}",
    3024           0 :                                        state.dataIPShortCut->cCurrentModuleObject,
    3025           0 :                                        state.dataIPShortCut->cAlphaArgs(1),
    3026           0 :                                        state.dataIPShortCut->cAlphaArgs(8)));
    3027             :                 // Set to Electric to avoid errors when setting up output variables
    3028           0 :                 Tank.OffCycParaFuelType = Constant::eFuel::Electricity;
    3029           0 :                 ErrorsFound = true;
    3030             :             }
    3031             :         }
    3032             : 
    3033          16 :         Tank.OffCycParaFracToTank = state.dataIPShortCut->rNumericArgs(13);
    3034          16 :         Tank.OffCycParaHeight = state.dataIPShortCut->rNumericArgs(14);
    3035             : 
    3036          16 :         Tank.OnCycParaLoad = state.dataIPShortCut->rNumericArgs(15);
    3037             : 
    3038             :         // Validate On-Cycle Parasitic Fuel Type
    3039          16 :         Tank.OnCycParaFuelType = static_cast<Constant::eFuel>(
    3040          16 :             getEnumValue(Constant::eFuelNamesUC,
    3041          16 :                          state.dataIPShortCut->cAlphaArgs(
    3042             :                              9))); // returns all kinds of fuels including district heat and cool + steam, returns unassigned if unsupported/empty
    3043          16 :         if (Tank.OnCycParaFuelType == Constant::eFuel::Invalid) {
    3044           0 :             if (state.dataIPShortCut->cAlphaArgs(9).empty()) {
    3045           0 :                 Tank.OnCycParaFuelType = Tank.FuelType;
    3046             :             } else {
    3047           0 :                 ShowSevereError(state,
    3048           0 :                                 format("{} = {}:  Invalid On-Cycle Parasitic Fuel Type entered={}",
    3049           0 :                                        state.dataIPShortCut->cCurrentModuleObject,
    3050           0 :                                        state.dataIPShortCut->cAlphaArgs(1),
    3051           0 :                                        state.dataIPShortCut->cAlphaArgs(9)));
    3052             :                 // Set to Electric to avoid errors when setting up output variables
    3053           0 :                 Tank.OnCycParaFuelType = Constant::eFuel::Electricity;
    3054           0 :                 ErrorsFound = true;
    3055             :             }
    3056             :         }
    3057             : 
    3058          16 :         Tank.OnCycParaFracToTank = state.dataIPShortCut->rNumericArgs(16);
    3059          16 :         Tank.OnCycParaHeight = state.dataIPShortCut->rNumericArgs(17);
    3060             : 
    3061          16 :         Tank.AmbientTempIndicator =
    3062          16 :             static_cast<WTTAmbientTemp>(getEnumValue(TankAmbientTempNamesUC, Util::makeUPPER(state.dataIPShortCut->cAlphaArgs(10))));
    3063          16 :         switch (Tank.AmbientTempIndicator) {
    3064             : 
    3065           8 :         case WTTAmbientTemp::Schedule: {
    3066           8 :             Tank.AmbientTempSchedule = ScheduleManager::GetScheduleIndex(state, state.dataIPShortCut->cAlphaArgs(11));
    3067           8 :             if (Tank.AmbientTempSchedule == 0) {
    3068           0 :                 ShowSevereError(state,
    3069           0 :                                 format("{} = {}:  Ambient Temperature Schedule not found = {}",
    3070           0 :                                        state.dataIPShortCut->cCurrentModuleObject,
    3071           0 :                                        state.dataIPShortCut->cAlphaArgs(1),
    3072           0 :                                        state.dataIPShortCut->cAlphaArgs(11)));
    3073           0 :                 ErrorsFound = true;
    3074             :             }
    3075             : 
    3076           8 :             break;
    3077             :         }
    3078           6 :         case WTTAmbientTemp::TempZone: {
    3079           6 :             Tank.AmbientTempZone = Util::FindItemInList(state.dataIPShortCut->cAlphaArgs(12), state.dataHeatBal->Zone);
    3080           6 :             if (Tank.AmbientTempZone == 0) {
    3081           0 :                 ShowSevereError(state,
    3082           0 :                                 format("{} = {}:  Ambient Temperature Zone not found = {}",
    3083           0 :                                        state.dataIPShortCut->cCurrentModuleObject,
    3084           0 :                                        state.dataIPShortCut->cAlphaArgs(1),
    3085           0 :                                        state.dataIPShortCut->cAlphaArgs(12)));
    3086           0 :                 ErrorsFound = true;
    3087             :             }
    3088             : 
    3089           6 :             break;
    3090             :         }
    3091           2 :         case WTTAmbientTemp::OutsideAir: {
    3092           2 :             Tank.AmbientTempOutsideAirNode = NodeInputManager::GetOnlySingleNode(state,
    3093           2 :                                                                                  state.dataIPShortCut->cAlphaArgs(13),
    3094             :                                                                                  ErrorsFound,
    3095             :                                                                                  DataLoopNode::ConnectionObjectType::WaterHeaterStratified,
    3096           2 :                                                                                  state.dataIPShortCut->cAlphaArgs(1),
    3097             :                                                                                  DataLoopNode::NodeFluidType::Air,
    3098             :                                                                                  DataLoopNode::ConnectionType::Inlet,
    3099             :                                                                                  NodeInputManager::CompFluidStream::Primary,
    3100             :                                                                                  DataLoopNode::ObjectIsNotParent);
    3101           2 :             if (!state.dataIPShortCut->cAlphaArgs(13).empty()) {
    3102           2 :                 if (!OutAirNodeManager::CheckOutAirNodeNumber(state, Tank.AmbientTempOutsideAirNode)) {
    3103           0 :                     ShowSevereError(state,
    3104           0 :                                     format("{} = {}: Outdoor Air Node not on OutdoorAir:NodeList or OutdoorAir:Node",
    3105           0 :                                            state.dataIPShortCut->cCurrentModuleObject,
    3106           0 :                                            state.dataIPShortCut->cAlphaArgs(1)));
    3107           0 :                     ShowContinueError(state, format("...Referenced Node Name={}", state.dataIPShortCut->cAlphaArgs(13)));
    3108           0 :                     ErrorsFound = true;
    3109             :                 }
    3110             :             } else {
    3111           0 :                 ShowSevereError(state, format("{} = {}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
    3112           0 :                 ShowContinueError(state, "An Ambient Outdoor Air Node name must be used when the Ambient Temperature Indicator is Outdoors.");
    3113           0 :                 ErrorsFound = true;
    3114             :             }
    3115             : 
    3116           2 :             break;
    3117             :         }
    3118           0 :         default: {
    3119           0 :             ShowSevereError(state,
    3120           0 :                             format("{} = {}:  Invalid Ambient Temperature Indicator entered={}",
    3121           0 :                                    state.dataIPShortCut->cCurrentModuleObject,
    3122           0 :                                    state.dataIPShortCut->cAlphaArgs(1),
    3123           0 :                                    state.dataIPShortCut->cAlphaArgs(10)));
    3124           0 :             ShowContinueError(state, " Valid entries are Schedule, Zone, and Outdoors.");
    3125           0 :             ErrorsFound = true;
    3126           0 :             break;
    3127             :         }
    3128             :         }
    3129             : 
    3130          16 :         Tank.SkinLossCoeff = state.dataIPShortCut->rNumericArgs(18);
    3131          16 :         Tank.SkinLossFracToZone = state.dataIPShortCut->rNumericArgs(19);
    3132          16 :         Tank.OffCycFlueLossCoeff = state.dataIPShortCut->rNumericArgs(20);
    3133          16 :         Tank.OffCycFlueLossFracToZone = state.dataIPShortCut->rNumericArgs(21);
    3134             : 
    3135             :         // this is temporary until we know fluid type
    3136          16 :         rho = FluidProperties::GetDensityGlycol(state, fluidNameWater, Constant::InitConvTemp, Tank.FluidIndex, RoutineName);
    3137          16 :         Tank.MassFlowRateMax = state.dataIPShortCut->rNumericArgs(22) * rho;
    3138             : 
    3139          16 :         if ((state.dataIPShortCut->cAlphaArgs(16).empty()) && (state.dataIPShortCut->cAlphaArgs(17).empty())) {
    3140           7 :             if (!state.dataIPShortCut->cAlphaArgs(14).empty()) {
    3141           7 :                 Tank.FlowRateSchedule = ScheduleManager::GetScheduleIndex(state, state.dataIPShortCut->cAlphaArgs(14));
    3142           7 :                 if (Tank.FlowRateSchedule == 0) {
    3143           0 :                     ShowSevereError(state,
    3144           0 :                                     format("{} = {}:  Flow Rate Schedule not found = {}",
    3145           0 :                                            state.dataIPShortCut->cCurrentModuleObject,
    3146           0 :                                            state.dataIPShortCut->cAlphaArgs(1),
    3147           0 :                                            state.dataIPShortCut->cAlphaArgs(14)));
    3148           0 :                     ErrorsFound = true;
    3149             :                 }
    3150             :             }
    3151             :         }
    3152             : 
    3153          16 :         if (!state.dataIPShortCut->cAlphaArgs(15).empty()) {
    3154           0 :             Tank.UseInletTempSchedule = ScheduleManager::GetScheduleIndex(state, state.dataIPShortCut->cAlphaArgs(15));
    3155           0 :             if (Tank.UseInletTempSchedule == 0) {
    3156           0 :                 ShowSevereError(state,
    3157           0 :                                 format("{} = {}:  Cold Water Supply Temperature Schedule not found = {}",
    3158           0 :                                        state.dataIPShortCut->cCurrentModuleObject,
    3159           0 :                                        state.dataIPShortCut->cAlphaArgs(1),
    3160           0 :                                        state.dataIPShortCut->cAlphaArgs(15)));
    3161           0 :                 ErrorsFound = true;
    3162             :             }
    3163             :         }
    3164             : 
    3165          16 :         if (NumNums > 22) {
    3166          16 :             Tank.UseEffectiveness = state.dataIPShortCut->rNumericArgs(23);
    3167             :         } else {
    3168           0 :             Tank.UseEffectiveness = 1.0; // Default for stand-alone mode
    3169             :         }
    3170             : 
    3171          16 :         if (NumNums > 23) {
    3172          16 :             Tank.UseInletHeight = state.dataIPShortCut->rNumericArgs(24);
    3173             :         } else {
    3174             :             // Defaults to bottom of tank
    3175           0 :             Tank.UseInletHeight = 0.0;
    3176             :         }
    3177          16 :         if ((!Tank.HeightWasAutoSized) && (Tank.UseInletHeight > Tank.Height)) {
    3178           0 :             ShowSevereError(state,
    3179           0 :                             format("{} = {}: Use inlet is located higher than overall tank height.",
    3180           0 :                                    state.dataIPShortCut->cCurrentModuleObject,
    3181           0 :                                    state.dataIPShortCut->cAlphaArgs(1)));
    3182           0 :             ShowContinueError(state, format("{} = {:.4R}", state.dataIPShortCut->cNumericFieldNames(2), state.dataIPShortCut->rNumericArgs(2)));
    3183           0 :             ShowContinueError(state, format("{} = {:.4R}", state.dataIPShortCut->cNumericFieldNames(24), state.dataIPShortCut->rNumericArgs(24)));
    3184           0 :             ErrorsFound = true;
    3185             :         }
    3186             : 
    3187          16 :         if ((NumNums > 24) && (state.dataIPShortCut->rNumericArgs(25) != Constant::AutoCalculate)) {
    3188           1 :             Tank.UseOutletHeight = state.dataIPShortCut->rNumericArgs(25);
    3189             :         } else {
    3190             :             // Defaults to top of tank
    3191          15 :             Tank.UseOutletHeight = Tank.Height;
    3192             :         }
    3193          16 :         if (Tank.UseOutletHeight == DataSizing::AutoSize) {
    3194           0 :             Tank.UseOutletHeightWasAutoSized = true;
    3195             :         }
    3196          16 :         if ((!Tank.HeightWasAutoSized) && (Tank.UseOutletHeight > Tank.Height)) {
    3197           0 :             ShowSevereError(state,
    3198           0 :                             format("{} = {}: Use outlet is located higher than overall tank height.",
    3199           0 :                                    state.dataIPShortCut->cCurrentModuleObject,
    3200           0 :                                    state.dataIPShortCut->cAlphaArgs(1)));
    3201           0 :             ShowContinueError(state, format("{} = {:.4R}", state.dataIPShortCut->cNumericFieldNames(2), state.dataIPShortCut->rNumericArgs(2)));
    3202           0 :             ShowContinueError(state, format("{} = {:.4R}", state.dataIPShortCut->cNumericFieldNames(25), state.dataIPShortCut->rNumericArgs(25)));
    3203           0 :             ErrorsFound = true;
    3204             :         }
    3205             : 
    3206          16 :         if (NumNums > 25) {
    3207          16 :             if ((state.dataIPShortCut->rNumericArgs(26) > 1) || (state.dataIPShortCut->rNumericArgs(26) <= 0)) {
    3208           0 :                 ShowSevereError(state,
    3209           0 :                                 format("{} = {}:  Source Side Effectiveness is out of bounds (>0 to 1)",
    3210           0 :                                        state.dataIPShortCut->cCurrentModuleObject,
    3211           0 :                                        state.dataIPShortCut->cAlphaArgs(1)));
    3212           0 :                 ErrorsFound = true;
    3213             :             }
    3214          16 :             Tank.SourceEffectiveness = state.dataIPShortCut->rNumericArgs(26);
    3215             :         } else {
    3216           0 :             Tank.SourceEffectiveness = 1.0;
    3217             :         }
    3218             : 
    3219          16 :         if ((NumNums > 26) && (state.dataIPShortCut->rNumericArgs(27) != Constant::AutoCalculate)) {
    3220          11 :             Tank.SourceInletHeight = state.dataIPShortCut->rNumericArgs(27);
    3221             :         } else {
    3222             :             // Defaults to top of tank
    3223           5 :             Tank.SourceInletHeight = Tank.Height;
    3224             :         }
    3225          16 :         if (Tank.SourceInletHeight == DataSizing::AutoSize) {
    3226           0 :             Tank.SourceInletHeightWasAutoSized = true;
    3227             :         }
    3228          16 :         if ((!Tank.HeightWasAutoSized) && (Tank.SourceInletHeight > Tank.Height)) {
    3229           0 :             ShowSevereError(state,
    3230           0 :                             format("{} = {}: Source inlet is located higher than overall tank height.",
    3231           0 :                                    state.dataIPShortCut->cCurrentModuleObject,
    3232           0 :                                    state.dataIPShortCut->cAlphaArgs(1)));
    3233           0 :             ShowContinueError(state, format("{} = {:.4R}", state.dataIPShortCut->cNumericFieldNames(2), state.dataIPShortCut->rNumericArgs(2)));
    3234           0 :             ShowContinueError(state, format("{} = {:.4R}", state.dataIPShortCut->cNumericFieldNames(27), state.dataIPShortCut->rNumericArgs(27)));
    3235           0 :             ErrorsFound = true;
    3236             :         }
    3237             : 
    3238          16 :         if ((NumNums > 27) && (state.dataIPShortCut->rNumericArgs(28) != Constant::AutoCalculate)) {
    3239          16 :             Tank.SourceOutletHeight = state.dataIPShortCut->rNumericArgs(28);
    3240             :         } else {
    3241             :             // Defaults to bottom of tank
    3242           0 :             Tank.SourceOutletHeight = 0.0;
    3243             :         }
    3244          16 :         if ((!Tank.HeightWasAutoSized) && (Tank.SourceOutletHeight > Tank.Height)) {
    3245           0 :             ShowSevereError(state,
    3246           0 :                             format("{} = {}: Source outlet is located higher than overall tank height.",
    3247           0 :                                    state.dataIPShortCut->cCurrentModuleObject,
    3248           0 :                                    state.dataIPShortCut->cAlphaArgs(1)));
    3249           0 :             ShowContinueError(state, format("{} = {:.4R}", state.dataIPShortCut->cNumericFieldNames(2), state.dataIPShortCut->rNumericArgs(2)));
    3250           0 :             ShowContinueError(state, format("{} = {:.4R}", state.dataIPShortCut->cNumericFieldNames(28), state.dataIPShortCut->rNumericArgs(28)));
    3251           0 :             ErrorsFound = true;
    3252             :         }
    3253             : 
    3254             :         // If no plant nodes are connected, simulate in stand-alone mode.
    3255          30 :         if (state.dataIPShortCut->cAlphaArgs(16).empty() && state.dataIPShortCut->cAlphaArgs(17).empty() &&
    3256          30 :             state.dataIPShortCut->cAlphaArgs(18).empty() && state.dataIPShortCut->cAlphaArgs(19).empty())
    3257           2 :             Tank.StandAlone = true;
    3258             : 
    3259          16 :         if (!state.dataIPShortCut->lNumericFieldBlanks(29)) {
    3260           9 :             Tank.UseDesignVolFlowRate = state.dataIPShortCut->rNumericArgs(29);
    3261           9 :             if (Tank.UseDesignVolFlowRate == DataSizing::AutoSize) {
    3262           9 :                 Tank.UseDesignVolFlowRateWasAutoSized = true;
    3263             :             }
    3264             :         } else {
    3265           7 :             Tank.UseDesignVolFlowRate = 0.0;
    3266             :         }
    3267             : 
    3268          16 :         Tank.UseSidePlantLoc.loopSideNum = DataPlant::LoopSideLocation::Invalid;
    3269             : 
    3270          16 :         if (!state.dataIPShortCut->lNumericFieldBlanks(30)) {
    3271           6 :             Tank.SourceDesignVolFlowRate = state.dataIPShortCut->rNumericArgs(30);
    3272           6 :             if (Tank.SourceDesignVolFlowRate == DataSizing::AutoSize) {
    3273           4 :                 Tank.SourceDesignVolFlowRateWasAutoSized = true;
    3274             :             }
    3275             :         } else {
    3276          10 :             Tank.SourceDesignVolFlowRate = 0.0;
    3277             :         }
    3278             : 
    3279          16 :         if (NumNums > 30) {
    3280          16 :             Tank.SizingRecoveryTime = state.dataIPShortCut->rNumericArgs(31);
    3281             :         } else {
    3282           0 :             Tank.SizingRecoveryTime = 1.5;
    3283             :         }
    3284             : 
    3285          16 :         Tank.SrcSidePlantLoc.loopSideNum = DataPlant::LoopSideLocation::Invalid;
    3286             : 
    3287          16 :         if ((!state.dataIPShortCut->cAlphaArgs(16).empty()) || (!state.dataIPShortCut->cAlphaArgs(17).empty())) {
    3288           9 :             Tank.UseInletNode = NodeInputManager::GetOnlySingleNode(state,
    3289           9 :                                                                     state.dataIPShortCut->cAlphaArgs(16),
    3290             :                                                                     ErrorsFound,
    3291             :                                                                     DataLoopNode::ConnectionObjectType::WaterHeaterStratified,
    3292           9 :                                                                     state.dataIPShortCut->cAlphaArgs(1),
    3293             :                                                                     DataLoopNode::NodeFluidType::Water,
    3294             :                                                                     DataLoopNode::ConnectionType::Inlet,
    3295             :                                                                     NodeInputManager::CompFluidStream::Primary,
    3296             :                                                                     DataLoopNode::ObjectIsNotParent);
    3297           9 :             Tank.InletNodeName1 = state.dataIPShortCut->cAlphaArgs(16);
    3298           9 :             Tank.UseOutletNode = NodeInputManager::GetOnlySingleNode(state,
    3299           9 :                                                                      state.dataIPShortCut->cAlphaArgs(17),
    3300             :                                                                      ErrorsFound,
    3301             :                                                                      DataLoopNode::ConnectionObjectType::WaterHeaterStratified,
    3302           9 :                                                                      state.dataIPShortCut->cAlphaArgs(1),
    3303             :                                                                      DataLoopNode::NodeFluidType::Water,
    3304             :                                                                      DataLoopNode::ConnectionType::Outlet,
    3305             :                                                                      NodeInputManager::CompFluidStream::Primary,
    3306             :                                                                      DataLoopNode::ObjectIsNotParent);
    3307           9 :             Tank.OutletNodeName1 = state.dataIPShortCut->cAlphaArgs(17);
    3308             : 
    3309           9 :             if (state.dataIPShortCut->rNumericArgs(22) > 0) {
    3310           0 :                 ShowWarningError(state,
    3311           0 :                                  format("{} = {}:  Use side nodes are specified; Peak Volumetric Use Flow Rate will not be used",
    3312           0 :                                         state.dataIPShortCut->cCurrentModuleObject,
    3313           0 :                                         state.dataIPShortCut->cAlphaArgs(1)));
    3314             :             }
    3315             : 
    3316           9 :             if (Tank.FlowRateSchedule > 0) {
    3317           0 :                 ShowWarningError(state,
    3318           0 :                                  format("{} = {}:  Use side nodes are specified; Use Flow Rate Fraction Schedule will not be used",
    3319           0 :                                         state.dataIPShortCut->cCurrentModuleObject,
    3320           0 :                                         state.dataIPShortCut->cAlphaArgs(1)));
    3321             :             }
    3322             : 
    3323           9 :             if (Tank.UseInletTempSchedule > 0) {
    3324           0 :                 ShowWarningError(state,
    3325           0 :                                  format("{} = {}:  Use side nodes are specified; Cold Water Supply Temperature Schedule will not be used",
    3326           0 :                                         state.dataIPShortCut->cCurrentModuleObject,
    3327           0 :                                         state.dataIPShortCut->cAlphaArgs(1)));
    3328             :             }
    3329             :         }
    3330             : 
    3331          16 :         if ((!state.dataIPShortCut->cAlphaArgs(18).empty()) || (!state.dataIPShortCut->cAlphaArgs(19).empty())) {
    3332          10 :             Tank.SourceInletNode = NodeInputManager::GetOnlySingleNode(state,
    3333          10 :                                                                        state.dataIPShortCut->cAlphaArgs(18),
    3334             :                                                                        ErrorsFound,
    3335             :                                                                        DataLoopNode::ConnectionObjectType::WaterHeaterStratified,
    3336          10 :                                                                        state.dataIPShortCut->cAlphaArgs(1),
    3337             :                                                                        DataLoopNode::NodeFluidType::Water,
    3338             :                                                                        DataLoopNode::ConnectionType::Inlet,
    3339             :                                                                        NodeInputManager::CompFluidStream::Secondary,
    3340             :                                                                        DataLoopNode::ObjectIsNotParent);
    3341          10 :             Tank.InletNodeName2 = state.dataIPShortCut->cAlphaArgs(18);
    3342          10 :             Tank.SourceOutletNode = NodeInputManager::GetOnlySingleNode(state,
    3343          10 :                                                                         state.dataIPShortCut->cAlphaArgs(19),
    3344             :                                                                         ErrorsFound,
    3345             :                                                                         DataLoopNode::ConnectionObjectType::WaterHeaterStratified,
    3346          10 :                                                                         state.dataIPShortCut->cAlphaArgs(1),
    3347             :                                                                         DataLoopNode::NodeFluidType::Water,
    3348             :                                                                         DataLoopNode::ConnectionType::Outlet,
    3349             :                                                                         NodeInputManager::CompFluidStream::Secondary,
    3350             :                                                                         DataLoopNode::ObjectIsNotParent);
    3351          10 :             Tank.OutletNodeName2 = state.dataIPShortCut->cAlphaArgs(19);
    3352             :         }
    3353             : 
    3354             :         // Validate inlet mode
    3355          16 :         Tank.InletMode =
    3356          16 :             static_cast<InletPositionMode>(getEnumValue(InletPositionModeNamesUC, Util::makeUPPER(state.dataIPShortCut->cAlphaArgs(20))));
    3357             : 
    3358          16 :         Tank.Nodes = state.dataIPShortCut->rNumericArgs(32);
    3359          16 :         int specifiedNodes = 0;
    3360          16 :         Tank.AdditionalCond = state.dataIPShortCut->rNumericArgs(33);
    3361             : 
    3362          16 :         Tank.AdditionalLossCoeff.allocate(Tank.Nodes);
    3363          16 :         Tank.AdditionalLossCoeff = 0.0;
    3364          44 :         for (int NodeNum = 1; NodeNum <= 12; ++NodeNum) {
    3365          44 :             int index = 33 + NodeNum;
    3366          44 :             if (NumNums >= index) {
    3367          28 :                 if (NodeNum <= Tank.Nodes) {
    3368          28 :                     ++specifiedNodes;
    3369          28 :                     Tank.AdditionalLossCoeff(NodeNum) = state.dataIPShortCut->rNumericArgs(index);
    3370           0 :                 } else if (!state.dataIPShortCut->lNumericFieldBlanks(index) && (state.dataIPShortCut->rNumericArgs(index) != 0)) {
    3371             :                     // If either blank, or zero (default), then do not warn
    3372           0 :                     ++specifiedNodes;
    3373             :                 }
    3374             :             } else {
    3375          16 :                 break;
    3376             :             }
    3377             :         }
    3378             : 
    3379          16 :         if (specifiedNodes > Tank.Nodes) {
    3380           0 :             ShowWarningError(
    3381             :                 state,
    3382           0 :                 format("{} = {}:  More Additional Loss Coefficients were entered than the number of nodes; extra coefficients will not be used",
    3383           0 :                        state.dataIPShortCut->cCurrentModuleObject,
    3384           0 :                        state.dataIPShortCut->cAlphaArgs(1)));
    3385             :         }
    3386             : 
    3387          16 :         Tank.SetupStratifiedNodes(state);
    3388             : 
    3389          16 :         if (!state.dataIPShortCut->lAlphaFieldBlanks(21)) {
    3390           0 :             Tank.SourceSideControlMode =
    3391           0 :                 static_cast<SourceSideControl>(getEnumValue(SourceSideControlNamesUC, Util::makeUPPER(state.dataIPShortCut->cAlphaArgs(21))));
    3392           0 :             if (Tank.SourceSideControlMode == SourceSideControl::Invalid) {
    3393           0 :                 ShowSevereError(state,
    3394           0 :                                 format("{} = {}:  Invalid Control Mode entered={}",
    3395           0 :                                        state.dataIPShortCut->cCurrentModuleObject,
    3396           0 :                                        state.dataIPShortCut->cAlphaArgs(1),
    3397           0 :                                        state.dataIPShortCut->cAlphaArgs(21)));
    3398           0 :                 ErrorsFound = true;
    3399             :             }
    3400             :         } else {
    3401          16 :             Tank.SourceSideControlMode = SourceSideControl::IndirectHeatPrimarySetpoint;
    3402             :         }
    3403             : 
    3404          16 :         if (!state.dataIPShortCut->lAlphaFieldBlanks(22)) {
    3405           0 :             Tank.SourceSideAltSetpointSchedNum = ScheduleManager::GetScheduleIndex(state, state.dataIPShortCut->cAlphaArgs(22));
    3406           0 :             if (Tank.SourceSideAltSetpointSchedNum == 0) {
    3407           0 :                 ShowSevereError(state,
    3408           0 :                                 format("{} = {}:  {} not found = {}",
    3409           0 :                                        state.dataIPShortCut->cCurrentModuleObject,
    3410           0 :                                        state.dataIPShortCut->cAlphaArgs(1),
    3411           0 :                                        state.dataIPShortCut->cAlphaFieldNames(22),
    3412           0 :                                        state.dataIPShortCut->cAlphaArgs(22)));
    3413           0 :                 ErrorsFound = true;
    3414             :             }
    3415             :         }
    3416             :     }
    3417             : 
    3418          10 :     return ErrorsFound;
    3419             : }
    3420             : 
    3421           4 : bool getWaterTankMixedInput(EnergyPlusData &state)
    3422             : {
    3423           4 :     bool ErrorsFound = false;
    3424             : 
    3425           4 :     state.dataIPShortCut->cCurrentModuleObject = cMixedCWTankModuleObj; // 'ThermalStorage:ChilledWater:Mixed'
    3426           8 :     for (int WaterThermalTankNum = state.dataWaterThermalTanks->numWaterHeaterMixed + state.dataWaterThermalTanks->numWaterHeaterStratified + 1;
    3427           8 :          WaterThermalTankNum <= state.dataWaterThermalTanks->numWaterHeaterMixed + state.dataWaterThermalTanks->numWaterHeaterStratified +
    3428           8 :                                     state.dataWaterThermalTanks->numChilledWaterMixed;
    3429             :          ++WaterThermalTankNum) {
    3430             :         int NumAlphas;
    3431             :         int NumNums;
    3432             :         int IOStat;
    3433           8 :         state.dataInputProcessing->inputProcessor->getObjectItem(
    3434             :             state,
    3435           4 :             state.dataIPShortCut->cCurrentModuleObject,
    3436           4 :             WaterThermalTankNum - (state.dataWaterThermalTanks->numWaterHeaterMixed + state.dataWaterThermalTanks->numWaterHeaterStratified),
    3437           4 :             state.dataIPShortCut->cAlphaArgs,
    3438             :             NumAlphas,
    3439           4 :             state.dataIPShortCut->rNumericArgs,
    3440             :             NumNums,
    3441             :             IOStat,
    3442           4 :             state.dataIPShortCut->lNumericFieldBlanks,
    3443           4 :             state.dataIPShortCut->lAlphaFieldBlanks,
    3444           4 :             state.dataIPShortCut->cAlphaFieldNames,
    3445           4 :             state.dataIPShortCut->cNumericFieldNames);
    3446           4 :         GlobalNames::VerifyUniqueInterObjectName(state,
    3447           4 :                                                  state.dataWaterThermalTanks->UniqueWaterThermalTankNames,
    3448           4 :                                                  state.dataIPShortCut->cAlphaArgs(1),
    3449           4 :                                                  state.dataIPShortCut->cCurrentModuleObject,
    3450           4 :                                                  state.dataIPShortCut->cAlphaFieldNames(1),
    3451             :                                                  ErrorsFound);
    3452             : 
    3453           4 :         auto &Tank = state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum);
    3454             : 
    3455           4 :         Tank.Name = state.dataIPShortCut->cAlphaArgs(1);
    3456           4 :         Tank.Type = state.dataIPShortCut->cCurrentModuleObject;
    3457           4 :         Tank.WaterThermalTankType = DataPlant::PlantEquipmentType::ChilledWaterTankMixed;
    3458           4 :         Tank.FluidIndex = Tank.waterIndex;
    3459           4 :         Tank.IsChilledWaterTank = true;
    3460           4 :         Tank.EndUseSubcategoryName = "Chilled Water Storage";
    3461             : 
    3462           4 :         Tank.Volume = state.dataIPShortCut->rNumericArgs(1);
    3463           4 :         if (Tank.Volume == DataSizing::AutoSize) {
    3464           0 :             Tank.VolumeWasAutoSized = true;
    3465             :         }
    3466             : 
    3467           4 :         if (state.dataIPShortCut->rNumericArgs(1) == 0.0) {
    3468             :             // Set volume to a really small number to continue simulation
    3469           0 :             Tank.Volume = 0.000001; // = 1 cm3
    3470             :         }
    3471             : 
    3472           4 :         Tank.SetPointTempSchedule = ScheduleManager::GetScheduleIndex(state, state.dataIPShortCut->cAlphaArgs(2));
    3473           4 :         if (Tank.SetPointTempSchedule == 0) {
    3474           0 :             ShowSevereError(state, format("Invalid, {} = {}", state.dataIPShortCut->cAlphaFieldNames(2), state.dataIPShortCut->cAlphaArgs(2)));
    3475           0 :             ShowContinueError(state, format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
    3476             : 
    3477           0 :             ErrorsFound = true;
    3478             :         }
    3479             : 
    3480           4 :         if (state.dataIPShortCut->rNumericArgs(2) > 0.0001) {
    3481           4 :             Tank.DeadBandDeltaTemp = state.dataIPShortCut->rNumericArgs(2);
    3482             :         } else {
    3483             :             // Default to very small number (however it can't be TINY or it will break the algorithm)
    3484           0 :             Tank.DeadBandDeltaTemp = 0.5;
    3485             :         }
    3486             : 
    3487           4 :         if (state.dataIPShortCut->rNumericArgs(3) > 0.0) {
    3488           4 :             Tank.TankTempLimit = state.dataIPShortCut->rNumericArgs(3);
    3489             :         } else {
    3490             :             // default to just above freezing
    3491           0 :             Tank.TankTempLimit = 1.0;
    3492             :         }
    3493             : 
    3494           4 :         Tank.MaxCapacity = state.dataIPShortCut->rNumericArgs(4);
    3495           4 :         if (Tank.MaxCapacity == DataSizing::AutoSize) {
    3496           0 :             Tank.MaxCapacityWasAutoSized = true;
    3497             :         }
    3498             : 
    3499           4 :         Tank.MinCapacity = 0.0;
    3500           4 :         Tank.ControlType = HeaterControlMode::Cycle;
    3501             : 
    3502           4 :         Tank.MassFlowRateMin = 0.0;
    3503           4 :         Tank.IgnitionDelay = 0.0;
    3504           4 :         Tank.FuelType = Constant::eFuel::Electricity;
    3505           4 :         Tank.Efficiency = 1.0;
    3506           4 :         Tank.PLFCurve = 0;
    3507           4 :         Tank.OffCycParaLoad = 0.0;
    3508           4 :         Tank.OffCycParaFuelType = Constant::eFuel::Electricity;
    3509           4 :         Tank.OffCycParaFracToTank = 0.0;
    3510           4 :         Tank.OnCycParaLoad = 0.0;
    3511           4 :         Tank.OnCycParaFuelType = Constant::eFuel::Electricity;
    3512           4 :         Tank.OnCycParaFracToTank = 0.0;
    3513             : 
    3514           4 :         Tank.AmbientTempIndicator =
    3515           4 :             static_cast<WTTAmbientTemp>(getEnumValue(TankAmbientTempNamesUC, Util::makeUPPER(state.dataIPShortCut->cAlphaArgs(3))));
    3516           4 :         switch (Tank.AmbientTempIndicator) {
    3517             : 
    3518           0 :         case WTTAmbientTemp::Schedule: {
    3519           0 :             Tank.AmbientTempSchedule = ScheduleManager::GetScheduleIndex(state, state.dataIPShortCut->cAlphaArgs(4));
    3520           0 :             if (Tank.AmbientTempSchedule == 0) {
    3521           0 :                 ShowSevereError(state, format("Invalid, {} = {}", state.dataIPShortCut->cAlphaFieldNames(4), state.dataIPShortCut->cAlphaArgs(4)));
    3522           0 :                 ShowContinueError(state,
    3523           0 :                                   format("Entered in {} = {}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
    3524           0 :                 ShowContinueError(state, "Schedule was not found.");
    3525           0 :                 ErrorsFound = true;
    3526             :             }
    3527             : 
    3528           0 :             break;
    3529             :         }
    3530           3 :         case WTTAmbientTemp::TempZone: {
    3531           3 :             Tank.AmbientTempZone = Util::FindItemInList(state.dataIPShortCut->cAlphaArgs(5), state.dataHeatBal->Zone);
    3532           3 :             if (Tank.AmbientTempZone == 0) {
    3533           0 :                 ShowSevereError(state, format("Invalid, {} = {}", state.dataIPShortCut->cAlphaFieldNames(5), state.dataIPShortCut->cAlphaArgs(5)));
    3534           0 :                 ShowContinueError(state,
    3535           0 :                                   format("Entered in {} = {}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
    3536           0 :                 ShowContinueError(state, "Zone was not found.");
    3537           0 :                 ErrorsFound = true;
    3538             :             }
    3539             : 
    3540           3 :             break;
    3541             :         }
    3542           1 :         case WTTAmbientTemp::OutsideAir: {
    3543           1 :             Tank.AmbientTempOutsideAirNode = NodeInputManager::GetOnlySingleNode(state,
    3544           1 :                                                                                  state.dataIPShortCut->cAlphaArgs(6),
    3545             :                                                                                  ErrorsFound,
    3546             :                                                                                  DataLoopNode::ConnectionObjectType::ThermalStorageChilledWaterMixed,
    3547           1 :                                                                                  state.dataIPShortCut->cAlphaArgs(1),
    3548             :                                                                                  DataLoopNode::NodeFluidType::Air,
    3549             :                                                                                  DataLoopNode::ConnectionType::OutsideAirReference,
    3550             :                                                                                  NodeInputManager::CompFluidStream::Primary,
    3551             :                                                                                  DataLoopNode::ObjectIsNotParent);
    3552           1 :             if (!state.dataIPShortCut->lAlphaFieldBlanks(6)) {
    3553           1 :                 if (!OutAirNodeManager::CheckOutAirNodeNumber(state, Tank.AmbientTempOutsideAirNode)) {
    3554           0 :                     ShowSevereError(state,
    3555           0 :                                     format("Invalid, {} = {}", state.dataIPShortCut->cAlphaFieldNames(6), state.dataIPShortCut->cAlphaArgs(6)));
    3556           0 :                     ShowContinueError(state,
    3557           0 :                                       format("Entered in {} = {}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
    3558           0 :                     ShowContinueError(state, "Outdoor Air Node not on OutdoorAir:NodeList or OutdoorAir:Node");
    3559           0 :                     ErrorsFound = true;
    3560             :                 }
    3561             :             } else {
    3562           0 :                 ShowSevereError(state, format("{} = {}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
    3563           0 :                 ShowContinueError(state, "An Ambient Outdoor Air Node name must be used when the Ambient Temperature Indicator is Outdoors.");
    3564           0 :                 ErrorsFound = true;
    3565             :             }
    3566             : 
    3567           1 :             break;
    3568             :         }
    3569           0 :         default: {
    3570           0 :             ShowSevereError(state,
    3571           0 :                             format("{} = {}:  Invalid Ambient Temperature Indicator entered={}",
    3572           0 :                                    state.dataIPShortCut->cCurrentModuleObject,
    3573           0 :                                    state.dataIPShortCut->cAlphaArgs(1),
    3574           0 :                                    state.dataIPShortCut->cAlphaArgs(3)));
    3575           0 :             ShowContinueError(state, " Valid entries are Schedule, Zone, and Outdoors.");
    3576           0 :             ErrorsFound = true;
    3577           0 :             break;
    3578             :         }
    3579             :         }
    3580             : 
    3581           4 :         Tank.OffCycLossCoeff = state.dataIPShortCut->rNumericArgs(5);
    3582           4 :         Tank.OffCycLossFracToZone = 1.0;
    3583             : 
    3584           4 :         Tank.OnCycLossCoeff = state.dataIPShortCut->rNumericArgs(5);
    3585           4 :         Tank.OnCycLossFracToZone = 1.0;
    3586             : 
    3587           4 :         Tank.MassFlowRateMax = 0.0;
    3588           4 :         Tank.FlowRateSchedule = 0;
    3589           4 :         Tank.UseInletTempSchedule = 0;
    3590             : 
    3591             :         // default to always on
    3592           4 :         Tank.SourceSideAvailSchedNum = ScheduleManager::ScheduleAlwaysOn;
    3593           4 :         Tank.UseSideAvailSchedNum = ScheduleManager::ScheduleAlwaysOn;
    3594             : 
    3595           4 :         if ((state.dataIPShortCut->rNumericArgs(6) > 1) || (state.dataIPShortCut->rNumericArgs(6) < 0)) {
    3596           0 :             ShowSevereError(state,
    3597           0 :                             format("{} = {}:  Use Side Effectiveness is out of bounds (0 to 1)",
    3598           0 :                                    state.dataIPShortCut->cCurrentModuleObject,
    3599           0 :                                    state.dataIPShortCut->cAlphaArgs(1)));
    3600           0 :             ErrorsFound = true;
    3601             :         }
    3602           4 :         Tank.UseEffectiveness = state.dataIPShortCut->rNumericArgs(6);
    3603             : 
    3604           4 :         if ((state.dataIPShortCut->rNumericArgs(8) > 1) || (state.dataIPShortCut->rNumericArgs(8) <= 0)) {
    3605           0 :             ShowSevereError(state,
    3606           0 :                             format("{} = {}:  Source Side Effectiveness is out of bounds (>0 to 1)",
    3607           0 :                                    state.dataIPShortCut->cCurrentModuleObject,
    3608           0 :                                    state.dataIPShortCut->cAlphaArgs(1)));
    3609           0 :             ErrorsFound = true;
    3610             :         }
    3611           4 :         Tank.SourceEffectiveness = state.dataIPShortCut->rNumericArgs(8);
    3612             : 
    3613           4 :         if (state.dataIPShortCut->lNumericFieldBlanks(7)) {
    3614           0 :             Tank.UseDesignVolFlowRate = 0.0;
    3615             :         } else {
    3616           4 :             Tank.UseDesignVolFlowRate = state.dataIPShortCut->rNumericArgs(7);
    3617           4 :             if (Tank.UseDesignVolFlowRate) {
    3618           4 :                 Tank.UseDesignVolFlowRateWasAutoSized = true;
    3619             :             }
    3620             :         }
    3621             : 
    3622           4 :         Tank.UseSidePlantLoc.loopSideNum = DataPlant::LoopSideLocation::Invalid;
    3623             : 
    3624           4 :         if (state.dataIPShortCut->lAlphaFieldBlanks(9)) {
    3625           0 :             Tank.UseSideAvailSchedNum = ScheduleManager::ScheduleAlwaysOn;
    3626             :         } else {
    3627           4 :             Tank.UseSideAvailSchedNum = ScheduleManager::GetScheduleIndex(state, state.dataIPShortCut->cAlphaArgs(9));
    3628           4 :             if (Tank.UseSideAvailSchedNum == 0) {
    3629           0 :                 ShowSevereError(state, format("Invalid, {} = {}", state.dataIPShortCut->cAlphaFieldNames(9), state.dataIPShortCut->cAlphaArgs(9)));
    3630           0 :                 ShowContinueError(state,
    3631           0 :                                   format("Entered in {} = {}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
    3632           0 :                 ShowContinueError(state, "Schedule was not found.");
    3633           0 :                 ErrorsFound = true;
    3634             :             }
    3635             :         }
    3636             : 
    3637           4 :         Tank.SrcSidePlantLoc.loopSideNum = DataPlant::LoopSideLocation::Invalid;
    3638             : 
    3639           4 :         if (state.dataIPShortCut->lNumericFieldBlanks(9)) {
    3640           1 :             Tank.SourceDesignVolFlowRate = 0.0;
    3641             :         } else {
    3642           3 :             Tank.SourceDesignVolFlowRate = state.dataIPShortCut->rNumericArgs(9);
    3643           3 :             if (Tank.SourceDesignVolFlowRate == DataSizing::AutoSize) {
    3644           3 :                 Tank.SourceDesignVolFlowRateWasAutoSized = true;
    3645             :             }
    3646             :         }
    3647             : 
    3648           4 :         if (state.dataIPShortCut->lAlphaFieldBlanks(12)) {
    3649           1 :             Tank.SourceSideAvailSchedNum = ScheduleManager::ScheduleAlwaysOn;
    3650             :         } else {
    3651           3 :             Tank.SourceSideAvailSchedNum = ScheduleManager::GetScheduleIndex(state, state.dataIPShortCut->cAlphaArgs(12));
    3652           3 :             if (Tank.SourceSideAvailSchedNum == 0) {
    3653           0 :                 ShowSevereError(state, format("Invalid, {} = {}", state.dataIPShortCut->cAlphaFieldNames(12), state.dataIPShortCut->cAlphaArgs(12)));
    3654           0 :                 ShowContinueError(state,
    3655           0 :                                   format("Entered in {} = {}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
    3656           0 :                 ShowContinueError(state, "Schedule was not found.");
    3657           0 :                 ErrorsFound = true;
    3658             :             }
    3659             :         }
    3660           4 :         if (state.dataIPShortCut->lNumericFieldBlanks(10)) {
    3661           1 :             Tank.SizingRecoveryTime = 4.0;
    3662             :         } else {
    3663           3 :             Tank.SizingRecoveryTime = state.dataIPShortCut->rNumericArgs(10);
    3664             :         }
    3665             : 
    3666           4 :         if ((!state.dataIPShortCut->lAlphaFieldBlanks(7)) || (!state.dataIPShortCut->lAlphaFieldBlanks(8))) {
    3667           4 :             Tank.UseInletNode = NodeInputManager::GetOnlySingleNode(state,
    3668           4 :                                                                     state.dataIPShortCut->cAlphaArgs(7),
    3669             :                                                                     ErrorsFound,
    3670             :                                                                     DataLoopNode::ConnectionObjectType::ThermalStorageChilledWaterMixed,
    3671           4 :                                                                     state.dataIPShortCut->cAlphaArgs(1),
    3672             :                                                                     DataLoopNode::NodeFluidType::Water,
    3673             :                                                                     DataLoopNode::ConnectionType::Inlet,
    3674             :                                                                     NodeInputManager::CompFluidStream::Primary,
    3675             :                                                                     DataLoopNode::ObjectIsNotParent);
    3676           4 :             Tank.InletNodeName1 = state.dataIPShortCut->cAlphaArgs(7);
    3677           4 :             Tank.UseOutletNode = NodeInputManager::GetOnlySingleNode(state,
    3678           4 :                                                                      state.dataIPShortCut->cAlphaArgs(8),
    3679             :                                                                      ErrorsFound,
    3680             :                                                                      DataLoopNode::ConnectionObjectType::ThermalStorageChilledWaterMixed,
    3681           4 :                                                                      state.dataIPShortCut->cAlphaArgs(1),
    3682             :                                                                      DataLoopNode::NodeFluidType::Water,
    3683             :                                                                      DataLoopNode::ConnectionType::Outlet,
    3684             :                                                                      NodeInputManager::CompFluidStream::Primary,
    3685             :                                                                      DataLoopNode::ObjectIsNotParent);
    3686           4 :             Tank.OutletNodeName1 = state.dataIPShortCut->cAlphaArgs(8);
    3687             :         }
    3688             : 
    3689           4 :         if ((!state.dataIPShortCut->lAlphaFieldBlanks(10)) || (!state.dataIPShortCut->lAlphaFieldBlanks(11))) {
    3690           3 :             Tank.SourceInletNode = NodeInputManager::GetOnlySingleNode(state,
    3691           3 :                                                                        state.dataIPShortCut->cAlphaArgs(10),
    3692             :                                                                        ErrorsFound,
    3693             :                                                                        DataLoopNode::ConnectionObjectType::ThermalStorageChilledWaterMixed,
    3694           3 :                                                                        state.dataIPShortCut->cAlphaArgs(1),
    3695             :                                                                        DataLoopNode::NodeFluidType::Water,
    3696             :                                                                        DataLoopNode::ConnectionType::Inlet,
    3697             :                                                                        NodeInputManager::CompFluidStream::Secondary,
    3698             :                                                                        DataLoopNode::ObjectIsNotParent);
    3699           3 :             Tank.InletNodeName2 = state.dataIPShortCut->cAlphaArgs(10);
    3700           3 :             Tank.SourceOutletNode = NodeInputManager::GetOnlySingleNode(state,
    3701           3 :                                                                         state.dataIPShortCut->cAlphaArgs(11),
    3702             :                                                                         ErrorsFound,
    3703             :                                                                         DataLoopNode::ConnectionObjectType::ThermalStorageChilledWaterMixed,
    3704           3 :                                                                         state.dataIPShortCut->cAlphaArgs(1),
    3705             :                                                                         DataLoopNode::NodeFluidType::Water,
    3706             :                                                                         DataLoopNode::ConnectionType::Outlet,
    3707             :                                                                         NodeInputManager::CompFluidStream::Secondary,
    3708             :                                                                         DataLoopNode::ObjectIsNotParent);
    3709           3 :             Tank.OutletNodeName2 = state.dataIPShortCut->cAlphaArgs(11);
    3710             :         }
    3711             : 
    3712           4 :         if (Tank.UseSidePlantLoc.loopSideNum == DataPlant::LoopSideLocation::Demand && Tank.SourceInletNode != 0) {
    3713           0 :             PlantUtilities::RegisterPlantCompDesignFlow(state, Tank.SourceInletNode, Tank.SourceDesignVolFlowRate);
    3714             :         }
    3715             : 
    3716             :     } // WaterThermalTankNum
    3717             : 
    3718           4 :     return ErrorsFound;
    3719             : }
    3720             : 
    3721           2 : bool getWaterTankStratifiedInput(EnergyPlusData &state)
    3722             : {
    3723           2 :     bool ErrorsFound = false;
    3724             :     static constexpr std::string_view RoutineName = "getWaterTankStratifiedInput";
    3725             : 
    3726           2 :     state.dataIPShortCut->cCurrentModuleObject = cStratifiedCWTankModuleObj; // 'ThermalStorage:ChilledWater:Stratified'
    3727             : 
    3728           4 :     for (int WaterThermalTankNum = state.dataWaterThermalTanks->numWaterHeaterMixed + state.dataWaterThermalTanks->numWaterHeaterStratified +
    3729           2 :                                    state.dataWaterThermalTanks->numChilledWaterMixed + 1;
    3730           4 :          WaterThermalTankNum <= state.dataWaterThermalTanks->numWaterHeaterMixed + state.dataWaterThermalTanks->numWaterHeaterStratified +
    3731           4 :                                     state.dataWaterThermalTanks->numChilledWaterMixed + state.dataWaterThermalTanks->numChilledWaterStratified;
    3732             :          ++WaterThermalTankNum) {
    3733             :         int NumNums;
    3734             :         int NumAlphas;
    3735             :         int IOStat;
    3736           4 :         state.dataInputProcessing->inputProcessor->getObjectItem(state,
    3737           2 :                                                                  state.dataIPShortCut->cCurrentModuleObject,
    3738           2 :                                                                  WaterThermalTankNum - (state.dataWaterThermalTanks->numWaterHeaterMixed +
    3739           2 :                                                                                         state.dataWaterThermalTanks->numWaterHeaterStratified +
    3740           2 :                                                                                         state.dataWaterThermalTanks->numChilledWaterMixed),
    3741           2 :                                                                  state.dataIPShortCut->cAlphaArgs,
    3742             :                                                                  NumAlphas,
    3743           2 :                                                                  state.dataIPShortCut->rNumericArgs,
    3744             :                                                                  NumNums,
    3745             :                                                                  IOStat,
    3746           2 :                                                                  state.dataIPShortCut->lNumericFieldBlanks,
    3747           2 :                                                                  state.dataIPShortCut->lAlphaFieldBlanks,
    3748           2 :                                                                  state.dataIPShortCut->cAlphaFieldNames,
    3749           2 :                                                                  state.dataIPShortCut->cNumericFieldNames);
    3750           2 :         GlobalNames::VerifyUniqueInterObjectName(state,
    3751           2 :                                                  state.dataWaterThermalTanks->UniqueWaterThermalTankNames,
    3752           2 :                                                  state.dataIPShortCut->cAlphaArgs(1),
    3753           2 :                                                  state.dataIPShortCut->cCurrentModuleObject,
    3754           2 :                                                  state.dataIPShortCut->cAlphaFieldNames(1),
    3755             :                                                  ErrorsFound);
    3756             : 
    3757           2 :         auto &Tank = state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum);
    3758             : 
    3759           2 :         Tank.Name = state.dataIPShortCut->cAlphaArgs(1);
    3760           2 :         Tank.Type = state.dataIPShortCut->cCurrentModuleObject;
    3761           2 :         Tank.WaterThermalTankType = DataPlant::PlantEquipmentType::ChilledWaterTankStratified;
    3762           2 :         Tank.FluidIndex = Tank.waterIndex;
    3763           2 :         Tank.IsChilledWaterTank = true;
    3764           2 :         Tank.EndUseSubcategoryName = "Chilled Water Storage";
    3765             : 
    3766           2 :         Tank.Volume = state.dataIPShortCut->rNumericArgs(1);
    3767           2 :         if (Tank.Volume == DataSizing::AutoSize) {
    3768           0 :             Tank.VolumeWasAutoSized = true;
    3769             :         }
    3770           2 :         Real64 rho = FluidProperties::GetDensityGlycol(state, fluidNameWater, Constant::InitConvTemp, Tank.FluidIndex, RoutineName);
    3771           2 :         Tank.Mass = Tank.Volume * rho;
    3772           2 :         Tank.Height = state.dataIPShortCut->rNumericArgs(2);
    3773           2 :         if (Tank.Height == DataSizing::AutoSize) {
    3774           0 :             Tank.HeightWasAutoSized = true;
    3775             :         }
    3776             : 
    3777           2 :         Tank.Shape = static_cast<TankShape>(getEnumValue(TankShapeNamesUC, Util::makeUPPER(state.dataIPShortCut->cAlphaArgs(2))));
    3778           2 :         switch (Tank.Shape) {
    3779           2 :         case TankShape::HorizCylinder:
    3780             :         case TankShape::VertCylinder: {
    3781           2 :             break;
    3782             :         }
    3783           0 :         case TankShape::Other: {
    3784           0 :             if (state.dataIPShortCut->rNumericArgs(3) > 0.0) {
    3785           0 :                 Tank.Perimeter = state.dataIPShortCut->rNumericArgs(3);
    3786             :             } else {
    3787           0 :                 ShowSevereError(state,
    3788           0 :                                 format("{} = {}:  Tank Perimeter must be greater than zero for Tank Shape=OTHER",
    3789           0 :                                        state.dataIPShortCut->cCurrentModuleObject,
    3790           0 :                                        state.dataIPShortCut->cAlphaArgs(1)));
    3791           0 :                 ErrorsFound = true;
    3792             :             }
    3793           0 :             break;
    3794             :         }
    3795           0 :         default: {
    3796           0 :             ShowSevereError(state,
    3797           0 :                             format("{} = {}:  Invalid Tank Shape entered={}",
    3798           0 :                                    state.dataIPShortCut->cCurrentModuleObject,
    3799           0 :                                    state.dataIPShortCut->cAlphaArgs(1),
    3800           0 :                                    state.dataIPShortCut->cAlphaArgs(2)));
    3801           0 :             Tank.Shape = TankShape::VertCylinder;
    3802           0 :             ErrorsFound = true;
    3803           0 :             break;
    3804             :         }
    3805             :         }
    3806             : 
    3807           2 :         if (state.dataIPShortCut->rNumericArgs(6) > 0.0) {
    3808           2 :             Tank.TankTempLimit = state.dataIPShortCut->rNumericArgs(6);
    3809             :         } else {
    3810             :             // default to just above freezing
    3811           0 :             Tank.TankTempLimit = 1.0;
    3812             :         }
    3813             : 
    3814           2 :         Tank.SetPointTempSchedule = ScheduleManager::GetScheduleIndex(state, state.dataIPShortCut->cAlphaArgs(3));
    3815           2 :         if (Tank.SetPointTempSchedule == 0) {
    3816           0 :             ShowSevereError(state, format("Invalid, {} = {}", state.dataIPShortCut->cAlphaFieldNames(3), state.dataIPShortCut->cAlphaArgs(3)));
    3817           0 :             ShowContinueError(state, format("Entered in {} = {}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
    3818           0 :             ShowContinueError(state, "Schedule was not found.");
    3819           0 :             ErrorsFound = true;
    3820             :         }
    3821             : 
    3822           2 :         if (state.dataIPShortCut->rNumericArgs(4) > 0.0) {
    3823           2 :             Tank.DeadBandDeltaTemp = state.dataIPShortCut->rNumericArgs(4);
    3824             :         } else {
    3825             :             // Default to very small number (however it can't be TINY or it will break the algorithm)
    3826           0 :             Tank.DeadBandDeltaTemp = 0.0001;
    3827             :         }
    3828             : 
    3829           2 :         Tank.HeaterHeight1 = state.dataIPShortCut->rNumericArgs(5);
    3830           2 :         Tank.MaxCapacity = state.dataIPShortCut->rNumericArgs(7);
    3831           2 :         if (Tank.MaxCapacity == DataSizing::AutoSize) {
    3832           0 :             Tank.MaxCapacityWasAutoSized = true;
    3833             :         }
    3834             : 
    3835           2 :         Tank.Efficiency = 1.0;
    3836           2 :         Tank.SetPointTempSchedule2 = 0;
    3837           2 :         Tank.MaxCapacity2 = 0.0;
    3838           2 :         Tank.HeaterHeight2 = 0.0;
    3839           2 :         Tank.FuelType = Constant::eFuel::Electricity;
    3840             : 
    3841           2 :         Tank.OffCycParaLoad = 0.0;
    3842           2 :         Tank.OffCycParaFuelType = Constant::eFuel::Electricity;
    3843           2 :         Tank.OffCycParaFracToTank = 0.0;
    3844           2 :         Tank.OffCycParaHeight = 0.0;
    3845           2 :         Tank.OnCycParaLoad = 0.0;
    3846           2 :         Tank.OnCycParaFuelType = Constant::eFuel::Electricity;
    3847           2 :         Tank.OnCycParaFracToTank = 0.0;
    3848           2 :         Tank.OnCycParaHeight = 0.0;
    3849             : 
    3850           2 :         Tank.AmbientTempIndicator =
    3851           2 :             static_cast<WTTAmbientTemp>(getEnumValue(TankAmbientTempNamesUC, Util::makeUPPER(state.dataIPShortCut->cAlphaArgs(4))));
    3852           2 :         switch (Tank.AmbientTempIndicator) {
    3853             : 
    3854           0 :         case WTTAmbientTemp::Schedule: {
    3855           0 :             Tank.AmbientTempSchedule = ScheduleManager::GetScheduleIndex(state, state.dataIPShortCut->cAlphaArgs(5));
    3856           0 :             if (Tank.AmbientTempSchedule == 0) {
    3857           0 :                 ShowSevereError(state, format("Invalid, {} = {}", state.dataIPShortCut->cAlphaFieldNames(5), state.dataIPShortCut->cAlphaArgs(5)));
    3858           0 :                 ShowContinueError(state,
    3859           0 :                                   format("Entered in {} = {}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
    3860           0 :                 ShowContinueError(state, "Schedule was not found.");
    3861           0 :                 ErrorsFound = true;
    3862             :             }
    3863             : 
    3864           0 :             break;
    3865             :         }
    3866           2 :         case WTTAmbientTemp::TempZone: {
    3867           2 :             Tank.AmbientTempZone = Util::FindItemInList(state.dataIPShortCut->cAlphaArgs(6), state.dataHeatBal->Zone);
    3868           2 :             if (Tank.AmbientTempZone == 0) {
    3869           0 :                 ShowSevereError(state, format("Invalid, {} = {}", state.dataIPShortCut->cAlphaFieldNames(6), state.dataIPShortCut->cAlphaArgs(6)));
    3870           0 :                 ShowContinueError(state,
    3871           0 :                                   format("Entered in {} = {}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
    3872           0 :                 ShowContinueError(state, "Zone was not found.");
    3873           0 :                 ErrorsFound = true;
    3874             :             }
    3875           2 :             Tank.OffCycLossFracToZone = 1.0;
    3876             : 
    3877           2 :             break;
    3878             :         }
    3879           0 :         case WTTAmbientTemp::OutsideAir: {
    3880           0 :             Tank.AmbientTempOutsideAirNode =
    3881           0 :                 NodeInputManager::GetOnlySingleNode(state,
    3882           0 :                                                     state.dataIPShortCut->cAlphaArgs(7),
    3883             :                                                     ErrorsFound,
    3884             :                                                     DataLoopNode::ConnectionObjectType::ThermalStorageChilledWaterStratified,
    3885           0 :                                                     state.dataIPShortCut->cAlphaArgs(1),
    3886             :                                                     DataLoopNode::NodeFluidType::Air,
    3887             :                                                     DataLoopNode::ConnectionType::Inlet,
    3888             :                                                     NodeInputManager::CompFluidStream::Primary,
    3889             :                                                     DataLoopNode::ObjectIsNotParent);
    3890           0 :             if (!state.dataIPShortCut->lAlphaFieldBlanks(7)) {
    3891           0 :                 if (!OutAirNodeManager::CheckOutAirNodeNumber(state, Tank.AmbientTempOutsideAirNode)) {
    3892           0 :                     ShowSevereError(state,
    3893           0 :                                     format("Invalid, {} = {}", state.dataIPShortCut->cAlphaFieldNames(7), state.dataIPShortCut->cAlphaArgs(7)));
    3894           0 :                     ShowContinueError(state,
    3895           0 :                                       format("Entered in {} = {}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
    3896           0 :                     ShowContinueError(state, "Outdoor Air Node not on OutdoorAir:NodeList or OutdoorAir:Node");
    3897           0 :                     ErrorsFound = true;
    3898             :                 }
    3899             :             } else {
    3900           0 :                 ShowSevereError(state, format("{} = {}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
    3901           0 :                 ShowContinueError(state, "An Ambient Outdoor Air Node name must be used when the Ambient Temperature Indicator is Outdoors.");
    3902           0 :                 ErrorsFound = true;
    3903             :             }
    3904             : 
    3905           0 :             break;
    3906             :         }
    3907           0 :         default: {
    3908           0 :             ShowSevereError(state,
    3909           0 :                             format("{} = {}:  Invalid Ambient Temperature Indicator entered={}",
    3910           0 :                                    state.dataIPShortCut->cCurrentModuleObject,
    3911           0 :                                    state.dataIPShortCut->cAlphaArgs(1),
    3912           0 :                                    state.dataIPShortCut->cAlphaArgs(4)));
    3913           0 :             ShowContinueError(state, "  Valid entries are Schedule, Zone, and Outdoors.");
    3914           0 :             ErrorsFound = true;
    3915           0 :             break;
    3916             :         }
    3917             :         }
    3918             : 
    3919           2 :         Tank.SkinLossCoeff = state.dataIPShortCut->rNumericArgs(8);
    3920           2 :         Tank.SkinLossFracToZone = 1.0;
    3921           2 :         Tank.OffCycFlueLossCoeff = 0.0;
    3922           2 :         Tank.OffCycFlueLossFracToZone = 0.0;
    3923             : 
    3924           2 :         Tank.MassFlowRateMax = 0.0;
    3925           2 :         Tank.FlowRateSchedule = 0;
    3926           2 :         Tank.UseInletTempSchedule = 0;
    3927           2 :         Tank.UseEffectiveness = state.dataIPShortCut->rNumericArgs(9);
    3928           2 :         Tank.UseInletHeight = state.dataIPShortCut->rNumericArgs(10);
    3929             : 
    3930             :         // default to always on
    3931           2 :         Tank.SourceSideAvailSchedNum = ScheduleManager::ScheduleAlwaysOn;
    3932           2 :         Tank.UseSideAvailSchedNum = ScheduleManager::ScheduleAlwaysOn;
    3933             : 
    3934           2 :         if (state.dataIPShortCut->rNumericArgs(10) == Constant::AutoCalculate) {
    3935           0 :             Tank.UseInletHeight = Tank.Height; // top of tank
    3936             :         }
    3937           2 :         if (Tank.UseInletHeight > Tank.Height) {
    3938           0 :             ShowSevereError(state,
    3939           0 :                             format("{} = {}: Use inlet is located higher than overall tank height.",
    3940           0 :                                    state.dataIPShortCut->cCurrentModuleObject,
    3941           0 :                                    state.dataIPShortCut->cAlphaArgs(1)));
    3942           0 :             ShowContinueError(state, format("{} = {:.4R}", state.dataIPShortCut->cNumericFieldNames(2), state.dataIPShortCut->rNumericArgs(2)));
    3943           0 :             ShowContinueError(state, format("{} = {:.4R}", state.dataIPShortCut->cNumericFieldNames(10), state.dataIPShortCut->rNumericArgs(10)));
    3944           0 :             ErrorsFound = true;
    3945             :         }
    3946             : 
    3947           2 :         Tank.UseOutletHeight = state.dataIPShortCut->rNumericArgs(11);
    3948           2 :         if (Tank.UseOutletHeight > Tank.Height) {
    3949           0 :             ShowSevereError(state,
    3950           0 :                             format("{} = {}: Use outlet is located higher than overall tank height.",
    3951           0 :                                    state.dataIPShortCut->cCurrentModuleObject,
    3952           0 :                                    state.dataIPShortCut->cAlphaArgs(1)));
    3953           0 :             ShowContinueError(state, format("{} = {:.4R}", state.dataIPShortCut->cNumericFieldNames(2), state.dataIPShortCut->rNumericArgs(2)));
    3954           0 :             ShowContinueError(state, format("{} = {:.4R}", state.dataIPShortCut->cNumericFieldNames(11), state.dataIPShortCut->rNumericArgs(11)));
    3955           0 :             ErrorsFound = true;
    3956             :         }
    3957             : 
    3958           2 :         if ((state.dataIPShortCut->rNumericArgs(13) > 1) || (state.dataIPShortCut->rNumericArgs(13) <= 0)) {
    3959           0 :             ShowSevereError(state,
    3960           0 :                             format("{} = {}:  Source Side Effectiveness is out of bounds (>0 to 1)",
    3961           0 :                                    state.dataIPShortCut->cCurrentModuleObject,
    3962           0 :                                    state.dataIPShortCut->cAlphaArgs(1)));
    3963           0 :             ErrorsFound = true;
    3964             :         }
    3965           2 :         Tank.SourceEffectiveness = state.dataIPShortCut->rNumericArgs(13);
    3966             : 
    3967           2 :         Tank.SourceInletHeight = state.dataIPShortCut->rNumericArgs(14);
    3968           2 :         if (Tank.SourceInletHeight > Tank.Height) {
    3969           0 :             ShowSevereError(state,
    3970           0 :                             format("{} = {}: Source inlet is located higher than overall tank height.",
    3971           0 :                                    state.dataIPShortCut->cCurrentModuleObject,
    3972           0 :                                    state.dataIPShortCut->cAlphaArgs(1)));
    3973           0 :             ShowContinueError(state, format("{} = {:.4R}", state.dataIPShortCut->cNumericFieldNames(2), state.dataIPShortCut->rNumericArgs(2)));
    3974           0 :             ShowContinueError(state, format("{} = {:.4R}", state.dataIPShortCut->cNumericFieldNames(14), state.dataIPShortCut->rNumericArgs(14)));
    3975           0 :             ErrorsFound = true;
    3976             :         }
    3977             : 
    3978           2 :         Tank.SourceOutletHeight = state.dataIPShortCut->rNumericArgs(15);
    3979           2 :         if (state.dataIPShortCut->rNumericArgs(15) == Constant::AutoCalculate) {
    3980           0 :             Tank.SourceOutletHeight = Tank.Height; // top of tank
    3981             :         }
    3982           2 :         if (Tank.SourceOutletHeight > Tank.Height) {
    3983           0 :             ShowSevereError(state,
    3984           0 :                             format("{} = {}: Source outlet is located higher than overall tank height.",
    3985           0 :                                    state.dataIPShortCut->cCurrentModuleObject,
    3986           0 :                                    state.dataIPShortCut->cAlphaArgs(1)));
    3987           0 :             ShowContinueError(state, format("{} = {:.4R}", state.dataIPShortCut->cNumericFieldNames(2), state.dataIPShortCut->rNumericArgs(2)));
    3988           0 :             ShowContinueError(state, format("{} = {:.4R}", state.dataIPShortCut->cNumericFieldNames(15), state.dataIPShortCut->rNumericArgs(15)));
    3989           0 :             ErrorsFound = true;
    3990             :         }
    3991             : 
    3992           2 :         Tank.StandAlone = false;
    3993             : 
    3994           2 :         if (state.dataIPShortCut->lNumericFieldBlanks(12)) {
    3995           0 :             Tank.UseDesignVolFlowRate = 0.0;
    3996             :         } else {
    3997           2 :             Tank.UseDesignVolFlowRate = state.dataIPShortCut->rNumericArgs(12);
    3998           2 :             if (Tank.UseDesignVolFlowRate == DataSizing::AutoSize) {
    3999           2 :                 Tank.UseDesignVolFlowRateWasAutoSized = true;
    4000             :             }
    4001             :         }
    4002             : 
    4003           2 :         Tank.UseSidePlantLoc.loopSideNum = DataPlant::LoopSideLocation::Invalid;
    4004             : 
    4005           2 :         if (state.dataIPShortCut->lNumericFieldBlanks(16)) {
    4006           0 :             Tank.SourceDesignVolFlowRate = 0.0;
    4007             :         } else {
    4008           2 :             Tank.SourceDesignVolFlowRate = state.dataIPShortCut->rNumericArgs(16);
    4009           2 :             if (Tank.SourceDesignVolFlowRate == DataSizing::AutoSize) {
    4010           0 :                 Tank.SourceDesignVolFlowRateWasAutoSized = true;
    4011             :             }
    4012             :         }
    4013             : 
    4014           2 :         Tank.SizingRecoveryTime = state.dataIPShortCut->rNumericArgs(17);
    4015             : 
    4016           2 :         Tank.SrcSidePlantLoc.loopSideNum = DataPlant::LoopSideLocation::Invalid;
    4017             : 
    4018           2 :         if ((!state.dataIPShortCut->lAlphaFieldBlanks(8)) || (!state.dataIPShortCut->lAlphaFieldBlanks(9))) {
    4019           2 :             Tank.UseInletNode = NodeInputManager::GetOnlySingleNode(state,
    4020           2 :                                                                     state.dataIPShortCut->cAlphaArgs(8),
    4021             :                                                                     ErrorsFound,
    4022             :                                                                     DataLoopNode::ConnectionObjectType::ThermalStorageChilledWaterStratified,
    4023           2 :                                                                     state.dataIPShortCut->cAlphaArgs(1),
    4024             :                                                                     DataLoopNode::NodeFluidType::Water,
    4025             :                                                                     DataLoopNode::ConnectionType::Inlet,
    4026             :                                                                     NodeInputManager::CompFluidStream::Primary,
    4027             :                                                                     DataLoopNode::ObjectIsNotParent);
    4028           2 :             Tank.InletNodeName1 = state.dataIPShortCut->cAlphaArgs(8);
    4029           2 :             Tank.UseOutletNode = NodeInputManager::GetOnlySingleNode(state,
    4030           2 :                                                                      state.dataIPShortCut->cAlphaArgs(9),
    4031             :                                                                      ErrorsFound,
    4032             :                                                                      DataLoopNode::ConnectionObjectType::ThermalStorageChilledWaterStratified,
    4033           2 :                                                                      state.dataIPShortCut->cAlphaArgs(1),
    4034             :                                                                      DataLoopNode::NodeFluidType::Water,
    4035             :                                                                      DataLoopNode::ConnectionType::Outlet,
    4036             :                                                                      NodeInputManager::CompFluidStream::Primary,
    4037             :                                                                      DataLoopNode::ObjectIsNotParent);
    4038           2 :             Tank.OutletNodeName1 = state.dataIPShortCut->cAlphaArgs(9);
    4039             :         }
    4040             : 
    4041           2 :         if ((!state.dataIPShortCut->lAlphaFieldBlanks(11)) || (!state.dataIPShortCut->lAlphaFieldBlanks(12))) {
    4042           1 :             Tank.SourceInletNode = NodeInputManager::GetOnlySingleNode(state,
    4043           1 :                                                                        state.dataIPShortCut->cAlphaArgs(11),
    4044             :                                                                        ErrorsFound,
    4045             :                                                                        DataLoopNode::ConnectionObjectType::ThermalStorageChilledWaterStratified,
    4046           1 :                                                                        state.dataIPShortCut->cAlphaArgs(1),
    4047             :                                                                        DataLoopNode::NodeFluidType::Water,
    4048             :                                                                        DataLoopNode::ConnectionType::Inlet,
    4049             :                                                                        NodeInputManager::CompFluidStream::Secondary,
    4050             :                                                                        DataLoopNode::ObjectIsNotParent);
    4051           1 :             Tank.InletNodeName2 = state.dataIPShortCut->cAlphaArgs(11);
    4052           1 :             Tank.SourceOutletNode = NodeInputManager::GetOnlySingleNode(state,
    4053           1 :                                                                         state.dataIPShortCut->cAlphaArgs(12),
    4054             :                                                                         ErrorsFound,
    4055             :                                                                         DataLoopNode::ConnectionObjectType::ThermalStorageChilledWaterStratified,
    4056           1 :                                                                         state.dataIPShortCut->cAlphaArgs(1),
    4057             :                                                                         DataLoopNode::NodeFluidType::Water,
    4058             :                                                                         DataLoopNode::ConnectionType::Outlet,
    4059             :                                                                         NodeInputManager::CompFluidStream::Secondary,
    4060             :                                                                         DataLoopNode::ObjectIsNotParent);
    4061           1 :             Tank.OutletNodeName2 = state.dataIPShortCut->cAlphaArgs(12);
    4062             :         }
    4063             : 
    4064           2 :         if (state.dataIPShortCut->lAlphaFieldBlanks(10)) {
    4065           0 :             Tank.UseSideAvailSchedNum = ScheduleManager::ScheduleAlwaysOn;
    4066             :         } else {
    4067           2 :             Tank.UseSideAvailSchedNum = ScheduleManager::GetScheduleIndex(state, state.dataIPShortCut->cAlphaArgs(10));
    4068           2 :             if (Tank.UseSideAvailSchedNum == 0) {
    4069           0 :                 ShowSevereError(state, format("Invalid, {} = {}", state.dataIPShortCut->cAlphaFieldNames(10), state.dataIPShortCut->cAlphaArgs(10)));
    4070           0 :                 ShowContinueError(state,
    4071           0 :                                   format("Entered in {} = {}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
    4072           0 :                 ShowContinueError(state, "Schedule was not found.");
    4073           0 :                 ErrorsFound = true;
    4074             :             }
    4075             :         }
    4076             : 
    4077           2 :         if (Tank.UseSidePlantLoc.loopSideNum == DataPlant::LoopSideLocation::Demand && Tank.SourceInletNode != 0) {
    4078           0 :             PlantUtilities::RegisterPlantCompDesignFlow(state, Tank.SourceInletNode, Tank.SourceDesignVolFlowRate);
    4079             :         }
    4080             : 
    4081           2 :         if (state.dataIPShortCut->lAlphaFieldBlanks(13)) {
    4082           0 :             Tank.SourceSideAvailSchedNum = ScheduleManager::ScheduleAlwaysOn;
    4083             :         } else {
    4084           2 :             Tank.SourceSideAvailSchedNum = ScheduleManager::GetScheduleIndex(state, state.dataIPShortCut->cAlphaArgs(13));
    4085           2 :             if (Tank.SourceSideAvailSchedNum == 0) {
    4086           0 :                 ShowSevereError(state, format("Invalid, {} = {}", state.dataIPShortCut->cAlphaFieldNames(13), state.dataIPShortCut->cAlphaArgs(13)));
    4087           0 :                 ShowContinueError(state,
    4088           0 :                                   format("Entered in {} = {}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
    4089           0 :                 ShowContinueError(state, "Schedule was not found.");
    4090           0 :                 ErrorsFound = true;
    4091             :             }
    4092             :         }
    4093             : 
    4094             :         // Validate inlet mode
    4095           2 :         Tank.InletMode =
    4096           2 :             static_cast<InletPositionMode>(getEnumValue(InletPositionModeNamesUC, Util::makeUPPER(state.dataIPShortCut->cAlphaArgs(14))));
    4097             : 
    4098           2 :         Tank.Nodes = state.dataIPShortCut->rNumericArgs(18);
    4099           2 :         Tank.AdditionalCond = state.dataIPShortCut->rNumericArgs(19);
    4100             : 
    4101           2 :         Tank.AdditionalLossCoeff.allocate(Tank.Nodes);
    4102           2 :         Tank.AdditionalLossCoeff = 0.0;
    4103           2 :         for (int NodeNum = 1; NodeNum <= Tank.Nodes; ++NodeNum) {
    4104           2 :             if (NumNums > 19 + NodeNum) {
    4105           0 :                 Tank.AdditionalLossCoeff(NodeNum) = state.dataIPShortCut->rNumericArgs(19 + NodeNum);
    4106             :             } else {
    4107           2 :                 break;
    4108             :             }
    4109             :         }
    4110             : 
    4111           2 :         if (NumNums > 19 + Tank.Nodes) {
    4112           0 :             ShowWarningError(
    4113             :                 state,
    4114           0 :                 format("{} = {}:  More Additional Loss Coefficients were entered than the number of nodes; extra coefficients will not be used",
    4115           0 :                        state.dataIPShortCut->cCurrentModuleObject,
    4116           0 :                        state.dataIPShortCut->cAlphaArgs(1)));
    4117             :         }
    4118             : 
    4119           2 :         Tank.SetupStratifiedNodes(state);
    4120             :     }
    4121             : 
    4122           2 :     return ErrorsFound;
    4123             : }
    4124             : 
    4125         442 : bool GetWaterThermalTankInput(EnergyPlusData &state)
    4126             : {
    4127             : 
    4128             :     // SUBROUTINE INFORMATION:
    4129             :     //       AUTHOR         Dan Fisher and Brandon Anderson
    4130             :     //       DATE WRITTEN   May 2000
    4131             :     //       MODIFIED       R. Raustad, June 2005, added HPWH and desuperheater water heating coils
    4132             :     //                      B. Griffith, Oct. 2007 extensions for indirect water heaters
    4133             :     //                      B. Griffith, Feb. 2008 extensions for autosizing water heaters
    4134             :     //                      BG Mar 2009.  Trap for bad heater height input for stratified water heater CR7718
    4135             :     //                      B. Shen 12/2014, add air-source variable-speed heat pump water heating
    4136             : 
    4137             :     // PURPOSE OF THIS SUBROUTINE:
    4138             :     // Gets the water heater, HPWH, and/or desuperheater heating coil input from the input file.
    4139             : 
    4140         442 :     bool ErrorsFound = false;
    4141             : 
    4142             :     // Make sure refrigeration input is gotten before this input
    4143         442 :     RefrigeratedCase::CheckRefrigerationInput(state);
    4144             : 
    4145         442 :     if (state.dataWaterThermalTanks->getWaterThermalTankInputFlag) {
    4146         442 :         state.dataWaterThermalTanks->numWaterHeaterMixed = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cMixedWHModuleObj);
    4147         884 :         state.dataWaterThermalTanks->numWaterHeaterStratified =
    4148         442 :             state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cStratifiedWHModuleObj);
    4149         884 :         state.dataWaterThermalTanks->numChilledWaterMixed =
    4150         442 :             state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cMixedCWTankModuleObj);
    4151         884 :         state.dataWaterThermalTanks->numChilledWaterStratified =
    4152         442 :             state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cStratifiedCWTankModuleObj);
    4153         884 :         state.dataWaterThermalTanks->numWaterThermalTank =
    4154         442 :             state.dataWaterThermalTanks->numWaterHeaterMixed + state.dataWaterThermalTanks->numWaterHeaterStratified +
    4155         442 :             state.dataWaterThermalTanks->numChilledWaterMixed + state.dataWaterThermalTanks->numChilledWaterStratified;
    4156         884 :         state.dataWaterThermalTanks->numHeatPumpWaterHeater =
    4157         442 :             state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cHPWHPumpedCondenser) +
    4158         442 :             state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cHPWHWrappedCondenser);
    4159         884 :         state.dataWaterThermalTanks->numWaterHeaterDesuperheater =
    4160         442 :             state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCoilDesuperheater);
    4161             : 
    4162         442 :         if (state.dataWaterThermalTanks->numWaterThermalTank > 0) {
    4163             :             static constexpr std::string_view Format_720(
    4164             :                 "! <Water Heater Information>,Type,Name,Volume {{m3}},Maximum Capacity {{W}},Standard Rated Recovery Efficiency, "
    4165             :                 "Standard Rated Energy Factor\n");
    4166             :             static constexpr std::string_view Format_721(
    4167             :                 "! <Heat Pump Water Heater Information>,Type,Name,Volume {{m3}},Maximum Capacity {{W}},Standard Rated Recovery "
    4168             :                 "Efficiency,Standard Rated Energy Factor,DX Coil Total Cooling Rate {{W}}\n");
    4169             :             static constexpr std::string_view Format_722(
    4170             :                 "! <Water Heater Stratified Node Information>,Node Number,Height {{m}},Volume {{m3}},Maximum Capacity "
    4171             :                 "{{W}},Off-Cycle UA {{W/K}},On-Cycle UA {{W/K}},Number Of Inlets,Number Of Outlets\n");
    4172             :             static constexpr std::string_view Format_725(
    4173             :                 "! <Chilled Water Tank Information>,Type,Name,Volume {{m3}},Use Side Design Flow Rate {{m3/s}}, "
    4174             :                 "Source Side Design Flow Rate {{m3/s}}\n");
    4175             :             static constexpr std::string_view Format_726(
    4176             :                 "! <Chilled Water Tank Stratified Node Information>,Node Number,Height {{m}},Volume {{m3}},UA {{W/K}},Number Of "
    4177             :                 "Inlets,Number Of Outlets\n");
    4178             : 
    4179             :             // Write water heater header for EIO
    4180         132 :             if ((state.dataWaterThermalTanks->numWaterHeaterMixed > 0) || (state.dataWaterThermalTanks->numWaterHeaterStratified > 0))
    4181         132 :                 print(state.files.eio, Format_720);
    4182         132 :             if (state.dataWaterThermalTanks->numHeatPumpWaterHeater > 0) print(state.files.eio, Format_721);
    4183         132 :             if (state.dataWaterThermalTanks->numWaterHeaterStratified > 0) print(state.files.eio, Format_722);
    4184         132 :             if (state.dataWaterThermalTanks->numChilledWaterMixed > 0) print(state.files.eio, Format_725);
    4185         132 :             if (state.dataWaterThermalTanks->numChilledWaterStratified > 0) print(state.files.eio, Format_726);
    4186             :         }
    4187             : 
    4188         442 :         if (state.dataWaterThermalTanks->numWaterThermalTank > 0) {
    4189         132 :             state.dataWaterThermalTanks->WaterThermalTank.allocate(state.dataWaterThermalTanks->numWaterThermalTank);
    4190         132 :             state.dataWaterThermalTanks->UniqueWaterThermalTankNames.reserve(static_cast<unsigned>(state.dataWaterThermalTanks->numWaterThermalTank));
    4191             :         }
    4192         442 :         if (state.dataWaterThermalTanks->numHeatPumpWaterHeater > 0) {
    4193           9 :             state.dataWaterThermalTanks->HPWaterHeater.allocate(state.dataWaterThermalTanks->numHeatPumpWaterHeater);
    4194             :         }
    4195             : 
    4196         442 :         if (state.dataWaterThermalTanks->numWaterHeaterDesuperheater > 0) {
    4197           6 :             state.dataWaterThermalTanks->WaterHeaterDesuperheater.allocate(state.dataWaterThermalTanks->numWaterHeaterDesuperheater);
    4198             :         }
    4199             : 
    4200             :         // =======   Get Coil:WaterHeating:Desuperheater ======================================================================
    4201         442 :         if (state.dataWaterThermalTanks->numWaterHeaterDesuperheater > 0) {
    4202           6 :             ErrorsFound |= getDesuperHtrInput(state);
    4203             :         }
    4204             : 
    4205             :         //  =======   Get HEAT PUMP:WATER HEATER ===============================================================================
    4206         442 :         if (state.dataWaterThermalTanks->numHeatPumpWaterHeater > 0) {
    4207           9 :             ErrorsFound |= getHPWaterHeaterInput(state);
    4208             :         }
    4209             : 
    4210             :         //  =======   Get WATER HEATER:MIXED ===================================================================================
    4211         442 :         if (state.dataWaterThermalTanks->numWaterHeaterMixed > 0) {
    4212         123 :             ErrorsFound |= getWaterHeaterMixedInputs(state);
    4213             :         }
    4214             : 
    4215             :         //  =======   Get WATER HEATER:STRATIFIED ==============================================================================
    4216         442 :         if (state.dataWaterThermalTanks->numWaterHeaterStratified > 0) {
    4217          10 :             ErrorsFound |= getWaterHeaterStratifiedInput(state);
    4218             :         }
    4219             : 
    4220             :         //  =======   Get Chilled Water :MIXED ===================================================================================
    4221         442 :         if (state.dataWaterThermalTanks->numChilledWaterMixed > 0) {
    4222           4 :             ErrorsFound |= getWaterTankMixedInput(state);
    4223             :         }
    4224             : 
    4225             :         //  =======   Get 'ThermalStorage:ChilledWater:Stratified' =======================================================
    4226         442 :         if (state.dataWaterThermalTanks->numChilledWaterStratified > 0) {
    4227           2 :             ErrorsFound |= getWaterTankStratifiedInput(state);
    4228             :         }
    4229             : 
    4230             :         //   Loop through all desuperheating coils and then search all water heaters for the tank connected to the desuperheating coil
    4231         442 :         if (state.dataWaterThermalTanks->numWaterHeaterDesuperheater > 0) {
    4232           6 :             state.dataIPShortCut->cCurrentModuleObject = cCoilDesuperheater;
    4233          12 :             for (int DesuperheaterNum = 1; DesuperheaterNum <= state.dataWaterThermalTanks->numWaterHeaterDesuperheater; ++DesuperheaterNum) {
    4234           6 :                 auto &DesuperHtr = state.dataWaterThermalTanks->WaterHeaterDesuperheater(DesuperheaterNum);
    4235          12 :                 for (int WtrHtrNum = 1; WtrHtrNum <= state.dataWaterThermalTanks->numWaterThermalTank; ++WtrHtrNum) {
    4236           6 :                     auto &Tank = state.dataWaterThermalTanks->WaterThermalTank(WtrHtrNum);
    4237           6 :                     if (!Util::SameString(DesuperHtr.TankName, Tank.Name) || !Util::SameString(DesuperHtr.TankType, Tank.Type)) continue;
    4238           6 :                     Tank.DesuperheaterNum = DesuperheaterNum;
    4239           6 :                     DesuperHtr.WaterHeaterTankNum = WtrHtrNum;
    4240           6 :                     DesuperHtr.TankTypeNum = Tank.WaterThermalTankType;
    4241           6 :                     DesuperHtr.BackupElementCapacity = Tank.MaxCapacity;
    4242           6 :                     if (Tank.UseInletNode == 0 && Tank.UseOutletNode == 0) DesuperHtr.StandAlone = true;
    4243             : 
    4244             :                     //         verify Desuperheater/tank source node connections
    4245           6 :                     if (DesuperHtr.WaterInletNode != Tank.SourceOutletNode) {
    4246           0 :                         ShowSevereError(state, format("{} = {}:", state.dataIPShortCut->cCurrentModuleObject, DesuperHtr.Name));
    4247           0 :                         ShowContinueError(state, "Desuperheater inlet node name does not match thermal tank source outlet node name.");
    4248           0 :                         ShowContinueError(state,
    4249           0 :                                           format("Desuperheater water inlet and outlet node names = {} and {}",
    4250           0 :                                                  DesuperHtr.InletNodeName1,
    4251           0 :                                                  DesuperHtr.OutletNodeName1));
    4252           0 :                         ShowContinueError(state,
    4253           0 :                                           format("Thermal tank source side inlet and outlet node names      = {} and {}",
    4254           0 :                                                  Tank.InletNodeName2,
    4255           0 :                                                  Tank.OutletNodeName2));
    4256           0 :                         ErrorsFound = true;
    4257             :                     }
    4258             : 
    4259           6 :                     if (DesuperHtr.WaterOutletNode != Tank.SourceInletNode) {
    4260           0 :                         ShowSevereError(state, format("{} = {}:", state.dataIPShortCut->cCurrentModuleObject, DesuperHtr.Name));
    4261           0 :                         ShowContinueError(state, "Desuperheater water outlet node name does not match thermal tank source inlet node name.");
    4262           0 :                         ShowContinueError(state,
    4263           0 :                                           format("Desuperheater water inlet and outlet node names = {} and {}",
    4264           0 :                                                  DesuperHtr.InletNodeName1,
    4265           0 :                                                  DesuperHtr.OutletNodeName1));
    4266           0 :                         ShowContinueError(state,
    4267           0 :                                           format("Thermal tank source side inlet and outlet node names      = {} and {}",
    4268           0 :                                                  Tank.InletNodeName2,
    4269           0 :                                                  Tank.OutletNodeName2));
    4270           0 :                         ErrorsFound = true;
    4271             :                     }
    4272             :                 }
    4273             : 
    4274           6 :                 if (DesuperHtr.WaterHeaterTankNum == 0) {
    4275           0 :                     ShowSevereError(state, format("{} = {}:", state.dataIPShortCut->cCurrentModuleObject, DesuperHtr.Name));
    4276           0 :                     ShowContinueError(state, format(" Water heater tank = {} not found.", DesuperHtr.TankName));
    4277           0 :                     ErrorsFound = true;
    4278             :                 }
    4279             :             }
    4280             :         }
    4281             : 
    4282             :         // Loop through HPWH's and then search all water heaters for the tank connected to the HPWH
    4283         442 :         if (state.dataWaterThermalTanks->numHeatPumpWaterHeater > 0) {
    4284             : 
    4285           9 :             int const NumPumpedCondenser = state.dataInputProcessing->inputProcessor->getNumObjectsFound(
    4286             :                 state, cHPWHPumpedCondenser); // number of WaterHeater:HeatPump:PumpedCondenser objects
    4287          32 :             for (int HPWaterHeaterNum = 1; HPWaterHeaterNum <= state.dataWaterThermalTanks->numHeatPumpWaterHeater; ++HPWaterHeaterNum) {
    4288             : 
    4289             :                 // Create reference to current HPWH object in array.
    4290          23 :                 HeatPumpWaterHeaterData &HPWH = state.dataWaterThermalTanks->HPWaterHeater(HPWaterHeaterNum);
    4291          23 :                 if (HPWaterHeaterNum <= NumPumpedCondenser) {
    4292             :                     // Pumped Condenser
    4293          20 :                     state.dataIPShortCut->cCurrentModuleObject = cHPWHPumpedCondenser;
    4294             :                 } else {
    4295             :                     // Wrapped Condenser
    4296           3 :                     state.dataIPShortCut->cCurrentModuleObject = cHPWHWrappedCondenser;
    4297             :                 }
    4298             : 
    4299             :                 // find the tank associated with the heat pump water heater and change its %TYPE to HEAT PUMP:WATER HEATER
    4300         143 :                 for (int CheckWaterHeaterNum = 1; CheckWaterHeaterNum <= state.dataWaterThermalTanks->numWaterThermalTank; ++CheckWaterHeaterNum) {
    4301             : 
    4302         120 :                     auto &Tank = state.dataWaterThermalTanks->WaterThermalTank(CheckWaterHeaterNum);
    4303             : 
    4304         120 :                     if (!(Util::SameString(HPWH.TankName, Tank.Name) && Util::SameString(HPWH.TankType, Tank.Type))) continue;
    4305             : 
    4306             :                     // save backup element and on/off-cycle parasitic properties for use during standard rating procedure
    4307          23 :                     HPWH.BackupElementCapacity = Tank.MaxCapacity;
    4308          23 :                     HPWH.BackupElementEfficiency = Tank.Efficiency;
    4309          23 :                     HPWH.WHOnCycParaLoad = Tank.OnCycParaLoad;
    4310          23 :                     HPWH.WHOffCycParaLoad = Tank.OffCycParaLoad;
    4311          23 :                     HPWH.WHOnCycParaFracToTank = Tank.OnCycParaFracToTank;
    4312          23 :                     HPWH.WHOffCycParaFracToTank = Tank.OffCycParaFracToTank;
    4313          23 :                     HPWH.WHPLFCurve = Tank.PLFCurve;
    4314             : 
    4315          23 :                     if (((Tank.WaterThermalTankType == DataPlant::PlantEquipmentType::WtrHeaterMixed) &&
    4316          12 :                          (HPWH.HPWHType == DataPlant::PlantEquipmentType::HeatPumpWtrHeaterPumped)) ||
    4317          11 :                         (Tank.WaterThermalTankType == DataPlant::PlantEquipmentType::WtrHeaterStratified)) {
    4318          23 :                         HPWH.TankType = Tank.Type;
    4319          23 :                         HPWH.HPWHTankType = Tank.WaterThermalTankType;
    4320             :                     } else {
    4321           0 :                         ShowSevereError(state, format("{} = {}:", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    4322           0 :                         ShowContinueError(state, format("Invalid water heater tank type = {}", Tank.Type));
    4323           0 :                         ErrorsFound = true;
    4324             :                     }
    4325             : 
    4326             :                     // Set up comp set for condenser water side nodes (reverse inlet/outlet for water heater)
    4327          23 :                     if (HPWH.bIsIHP) {
    4328           2 :                         BranchNodeConnections::SetUpCompSets(state,
    4329             :                                                              HPWH.Type,
    4330             :                                                              HPWH.Name,
    4331             :                                                              HPWH.DXCoilType,
    4332           2 :                                                              HPWH.DXCoilName + " Water Coil",
    4333             :                                                              HPWH.InletNodeName1,
    4334             :                                                              HPWH.OutletNodeName1,
    4335             :                                                              "HPWH To Coil");
    4336             :                     } else {
    4337          22 :                         BranchNodeConnections::SetUpCompSets(
    4338             :                             state, HPWH.Type, HPWH.Name, HPWH.DXCoilType, HPWH.DXCoilName, HPWH.InletNodeName1, HPWH.OutletNodeName1, "HPWH To Coil");
    4339             :                     }
    4340          23 :                     BranchNodeConnections::SetUpCompSets(
    4341             :                         state, HPWH.Type, HPWH.Name, HPWH.TankType, HPWH.TankName, HPWH.OutletNodeName1, HPWH.InletNodeName1, "HPWH To Tank");
    4342             : 
    4343             :                     // If WaterHeaterMixed: do not allow modulating control for HPWH's (i.e. modulating control usually used for tankless WH's)
    4344          23 :                     if ((Tank.WaterThermalTankType == DataPlant::PlantEquipmentType::WtrHeaterMixed) &&
    4345          12 :                         (Tank.ControlType == HeaterControlMode::Modulate)) {
    4346           0 :                         ShowSevereError(state, format("{} = {}:", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    4347           0 :                         ShowContinueError(state, format("Heater Control Type for {} = {} must be CYCLE.", Tank.Type, Tank.Name));
    4348           0 :                         ErrorsFound = true;
    4349             :                     }
    4350             : 
    4351          23 :                     Tank.HeatPumpNum = HPWaterHeaterNum;
    4352          23 :                     HPWH.WaterHeaterTankNum = CheckWaterHeaterNum;
    4353          23 :                     HPWH.FoundTank = true;
    4354             : 
    4355          23 :                     if (Tank.DesuperheaterNum > 0) {
    4356           0 :                         ShowSevereError(
    4357             :                             state,
    4358           0 :                             format("{} = {}and Coil:WaterHeating:Desuperheater = {}:  cannot be connected to the same water heater tank = {}",
    4359           0 :                                    state.dataIPShortCut->cCurrentModuleObject,
    4360           0 :                                    HPWH.Name,
    4361           0 :                                    state.dataWaterThermalTanks->WaterHeaterDesuperheater(CheckWaterHeaterNum).Name,
    4362           0 :                                    Tank.Name));
    4363             :                     }
    4364             : 
    4365             :                     // check that water heater source side effectiveness is greater than 0
    4366          23 :                     if (Tank.SourceEffectiveness <= 0.0) {
    4367           0 :                         ShowSevereError(state,
    4368           0 :                                         format("{} = {}:  Invalid source side effectiveness for heat pump water heater = {:.3T}",
    4369           0 :                                                state.dataIPShortCut->cCurrentModuleObject,
    4370           0 :                                                HPWH.Name,
    4371           0 :                                                Tank.SourceEffectiveness));
    4372           0 :                         ShowContinueError(state, " water heater source effectiveness will default to 1.0 and simulation continues.");
    4373           0 :                         Tank.SourceEffectiveness = 1.0;
    4374             :                     }
    4375             : 
    4376             :                     // Set up the source side nodes for wrapped condensers
    4377          23 :                     if (HPWH.HPWHType == DataPlant::PlantEquipmentType::HeatPumpWtrHeaterWrapped) {
    4378           3 :                         if (Tank.SourceInletNode > 0 || Tank.SourceOutletNode > 0) {
    4379           0 :                             ShowSevereError(state, format("{} = {} has a source inlet or outlet node specified,", Tank.Type, Tank.Name));
    4380           0 :                             ShowContinueError(
    4381           0 :                                 state, format("but it is attached to {} = {}, which doesn't permit source side connections.", HPWH.Type, HPWH.Name));
    4382           0 :                             ShowContinueError(state, "Please leave the source side inlet and outlet fields blank.");
    4383           0 :                             ErrorsFound = true;
    4384             :                         } else {
    4385             : 
    4386             :                             DataLoopNode::ConnectionObjectType objType = static_cast<DataLoopNode::ConnectionObjectType>(
    4387           3 :                                 getEnumValue(BranchNodeConnections::ConnectionObjectTypeNamesUC, Util::makeUPPER(Tank.Type)));
    4388             : 
    4389           3 :                             Tank.SourceInletNode = NodeInputManager::GetOnlySingleNode(state,
    4390           3 :                                                                                        HPWH.OutletNodeName1,
    4391             :                                                                                        ErrorsFound,
    4392             :                                                                                        objType,
    4393           3 :                                                                                        Tank.Name,
    4394             :                                                                                        DataLoopNode::NodeFluidType::Water,
    4395             :                                                                                        DataLoopNode::ConnectionType::Inlet,
    4396             :                                                                                        NodeInputManager::CompFluidStream::Secondary,
    4397             :                                                                                        DataLoopNode::ObjectIsNotParent);
    4398           3 :                             Tank.InletNodeName2 = HPWH.OutletNodeName1;
    4399           3 :                             Tank.SourceOutletNode = NodeInputManager::GetOnlySingleNode(state,
    4400           3 :                                                                                         HPWH.InletNodeName1,
    4401             :                                                                                         ErrorsFound,
    4402             :                                                                                         objType,
    4403           3 :                                                                                         Tank.Name,
    4404             :                                                                                         DataLoopNode::NodeFluidType::Water,
    4405             :                                                                                         DataLoopNode::ConnectionType::Outlet,
    4406             :                                                                                         NodeInputManager::CompFluidStream::Secondary,
    4407             :                                                                                         DataLoopNode::ObjectIsNotParent);
    4408           3 :                             Tank.OutletNodeName2 = HPWH.InletNodeName1;
    4409             :                         }
    4410             : 
    4411             :                         // Mark the tank as not stand alone because it is connected now.
    4412           3 :                         Tank.StandAlone = false;
    4413             :                     }
    4414             : 
    4415             :                     // Set HPWH structure variable StandAlone to TRUE if use nodes are not connected
    4416          23 :                     if (Tank.UseInletNode == 0 && Tank.UseOutletNode == 0) HPWH.StandAlone = true;
    4417             : 
    4418          23 :                     if (HPWH.WHUseInletNode != Tank.UseInletNode || HPWH.WHUseOutletNode != Tank.UseOutletNode) {
    4419           0 :                         ShowSevereError(state, format("{} = {}:", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    4420           0 :                         ShowContinueError(state,
    4421           0 :                                           format("Heat pump water heater tank use side inlet and outlet node names must match the use side inlet and "
    4422             :                                                  "outlet node names for water heater tank = {}: {}",
    4423           0 :                                                  HPWH.TankType,
    4424           0 :                                                  HPWH.TankName));
    4425           0 :                         ShowContinueError(state,
    4426           0 :                                           format("Heat pump water heater use side inlet and outlet node names = {} and {}",
    4427           0 :                                                  HPWH.InletNodeName2,
    4428           0 :                                                  HPWH.OutletNodeName2));
    4429           0 :                         ShowContinueError(state,
    4430           0 :                                           format("Water heater tank use side inlet and outlet node names      = {} and {}",
    4431           0 :                                                  Tank.InletNodeName1,
    4432           0 :                                                  Tank.OutletNodeName1));
    4433           0 :                         ErrorsFound = true;
    4434             :                     } else {
    4435          23 :                         if (!HPWH.StandAlone) {
    4436          10 :                             BranchNodeConnections::TestCompSet(state, HPWH.Type, HPWH.Name, Tank.InletNodeName1, Tank.OutletNodeName1, "Water Nodes");
    4437             :                         }
    4438             :                     }
    4439             : 
    4440             :                     // verify HP/tank source node connections
    4441          23 :                     if (HPWH.CondWaterInletNode != Tank.SourceOutletNode) {
    4442           0 :                         ShowSevereError(state, format("{} = {}:", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    4443           0 :                         ShowContinueError(state,
    4444             :                                           "Heat Pump condenser water inlet node name does not match water heater tank source outlet node name.");
    4445           0 :                         ShowContinueError(
    4446             :                             state,
    4447           0 :                             format("Heat pump condenser water inlet and outlet node names = {} and {}", HPWH.InletNodeName1, HPWH.OutletNodeName1));
    4448           0 :                         ShowContinueError(state,
    4449           0 :                                           format("Water heater tank source side inlet and outlet node names      = {} and {}",
    4450           0 :                                                  Tank.InletNodeName2,
    4451           0 :                                                  Tank.OutletNodeName2));
    4452           0 :                         ErrorsFound = true;
    4453             :                     }
    4454             : 
    4455          23 :                     if (HPWH.CondWaterOutletNode != Tank.SourceInletNode) {
    4456           0 :                         ShowSevereError(state, format("{} = {}:", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    4457           0 :                         ShowContinueError(state,
    4458             :                                           "Heat Pump condenser water outlet node name does not match water heater tank source inlet node name.");
    4459           0 :                         ShowContinueError(
    4460             :                             state,
    4461           0 :                             format("Heat pump condenser water inlet and outlet node names = {} and {}", HPWH.InletNodeName1, HPWH.OutletNodeName1));
    4462           0 :                         ShowContinueError(state,
    4463           0 :                                           format("Water heater tank source side inlet and outlet node names      = {} and {}",
    4464           0 :                                                  Tank.InletNodeName2,
    4465           0 :                                                  Tank.OutletNodeName2));
    4466           0 :                         ErrorsFound = true;
    4467             :                     }
    4468             : 
    4469             :                     // verify wrapped condenser location
    4470          23 :                     if (HPWH.HPWHType == DataPlant::PlantEquipmentType::HeatPumpWtrHeaterWrapped) {
    4471             :                         // make sure the top of the condenser is not above the tank height.
    4472           3 :                         if (HPWH.WrappedCondenserTopLocation > Tank.Height) {
    4473           0 :                             ShowSevereError(state, format("{} = {}:", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    4474           0 :                             ShowContinueError(state, "The height of the top of the wrapped condenser is greater than the height of the tank.");
    4475           0 :                             ErrorsFound = true;
    4476             :                         }
    4477             :                     }
    4478             : 
    4479             :                     // Verify tank name is in a zone equipment list if HPWH Inlet Air Configuration is Zone Air Only or Zone and Outdoor Air
    4480          23 :                     if (HPWH.InletAirConfiguration == WTTAmbientTemp::TempZone || HPWH.InletAirConfiguration == WTTAmbientTemp::ZoneAndOA) {
    4481          10 :                         if (allocated(state.dataZoneEquip->ZoneEquipConfig) && allocated(state.dataZoneEquip->ZoneEquipList)) {
    4482          10 :                             bool FoundTankInList = false;
    4483          10 :                             bool TankNotLowestPriority = false;
    4484          10 :                             int ZoneEquipConfigNum = HPWH.AmbientTempZone;
    4485          10 :                             int ZoneEquipListNum = state.dataZoneEquip->ZoneEquipConfig(ZoneEquipConfigNum).EquipListIndex;
    4486          10 :                             int TankCoolingPriority = 0;
    4487          10 :                             int TankHeatingPriority = 0;
    4488          10 :                             auto const &zoneEquipList = state.dataZoneEquip->ZoneEquipList(ZoneEquipListNum);
    4489          19 :                             for (int EquipmentTypeNum = 1; EquipmentTypeNum <= zoneEquipList.NumOfEquipTypes; ++EquipmentTypeNum) {
    4490          19 :                                 if (zoneEquipList.EquipName(EquipmentTypeNum) != HPWH.Name) continue;
    4491          10 :                                 FoundTankInList = true;
    4492          10 :                                 TankCoolingPriority = zoneEquipList.CoolingPriority(EquipmentTypeNum);
    4493          10 :                                 TankHeatingPriority = zoneEquipList.HeatingPriority(EquipmentTypeNum);
    4494          10 :                                 break;
    4495             :                             } // EquipmentTypeNum
    4496          10 :                             if (!FoundTankInList) {
    4497           0 :                                 ShowSevereError(state, format("{} = {}:", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    4498           0 :                                 ShowContinueError(state,
    4499             :                                                   "Heat pump water heater type and name must be listed in the correct "
    4500             :                                                   "ZoneHVAC:EquipmentList object when Inlet Air Configuration is equal to "
    4501             :                                                   "ZoneAirOnly or ZoneAndOutdoorAir.");
    4502           0 :                                 ErrorsFound = true;
    4503             :                             }
    4504             :                             //                     check that tank has lower priority than all other non-HPWH objects in Zone
    4505             :                             //                     Equipment List
    4506          39 :                             for (int EquipmentTypeNum = 1; EquipmentTypeNum <= zoneEquipList.NumOfEquipTypes; ++EquipmentTypeNum) {
    4507          29 :                                 if (Util::SameString(zoneEquipList.EquipTypeName(EquipmentTypeNum), state.dataIPShortCut->cCurrentModuleObject))
    4508          14 :                                     continue;
    4509          30 :                                 if (TankCoolingPriority > zoneEquipList.CoolingPriority(EquipmentTypeNum) ||
    4510          15 :                                     TankHeatingPriority > zoneEquipList.HeatingPriority(EquipmentTypeNum)) {
    4511           0 :                                     TankNotLowestPriority = true;
    4512             :                                 }
    4513             :                             } // EquipmentTypeNum
    4514          10 :                             if (TankNotLowestPriority && FoundTankInList) {
    4515           0 :                                 ShowWarningError(state, format("{} = {}:", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    4516           0 :                                 ShowContinueError(state,
    4517             :                                                   "Heat pump water heaters should be simulated first, before other space "
    4518             :                                                   "conditioning equipment.");
    4519           0 :                                 ShowContinueError(state,
    4520             :                                                   "Poor temperature control may result if the Heating/Cooling sequence number is "
    4521             :                                                   "not 1 in the ZoneHVAC:EquipmentList.");
    4522             :                             }
    4523             :                         } else {
    4524           0 :                             ShowSevereError(state, format("{} = {}:", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    4525           0 :                             ShowContinueError(state,
    4526             :                                               "ZoneHVAC:EquipmentList and ZoneHVAC:EquipmentConnections objects are required when Inlet Air "
    4527             :                                               "Configuration is either ZoneAirOnly or ZoneAndOutdoorAir.");
    4528           0 :                             ErrorsFound = true;
    4529             :                         } // ALLOCATED
    4530             :                     }     // InletAirConfiguration
    4531             : 
    4532          23 :                     if (Tank.WaterThermalTankType == DataPlant::PlantEquipmentType::WtrHeaterStratified) {
    4533             : 
    4534             :                         // Nodal heat distribution fraction for stratified tank wrapped condensers
    4535          11 :                         if (HPWH.HPWHType == DataPlant::PlantEquipmentType::HeatPumpWtrHeaterWrapped) {
    4536           3 :                             if (Tank.Shape == TankShape::HorizCylinder) {
    4537           0 :                                 ShowWarningError(state, format("{} = {}:", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    4538           0 :                                 ShowContinueError(state, "A wrapped condenser HPWH model should not be used with a horizontal stratified tank.");
    4539           0 :                                 ShowContinueError(
    4540             :                                     state, "Ignoring condenser location and distributing heat evenly throughout the tank. Simulation continues.");
    4541           0 :                                 Real64 const SameFrac = 1.0 / Tank.Nodes;
    4542           0 :                                 for (int NodeNum = 1; NodeNum <= Tank.Nodes; ++NodeNum) {
    4543           0 :                                     Tank.Node(NodeNum).HPWHWrappedCondenserHeatingFrac = SameFrac;
    4544             :                                 }
    4545             :                             } else {
    4546           3 :                                 Real64 H0 = Tank.Height; // height of top of node
    4547             :                                 Real64 H;                // height of bottom of node
    4548           3 :                                 Real64 SumFrac(0.0);
    4549             :                                 // Get the fraction of each stratified node that is wrapped by the condenser
    4550          17 :                                 for (int NodeNum = 1; NodeNum <= Tank.Nodes; ++NodeNum) {
    4551          14 :                                     StratifiedNodeData &CurNode = Tank.Node(NodeNum);
    4552          14 :                                     if (NodeNum == Tank.Nodes) {
    4553           3 :                                         H = 0.0;
    4554             :                                     } else {
    4555          11 :                                         H = H0 - CurNode.Height;
    4556             :                                     }
    4557          14 :                                     if (H < HPWH.WrappedCondenserBottomLocation && H0 > HPWH.WrappedCondenserBottomLocation) {
    4558             :                                         // The bottom of the condenser starts partway through this node.
    4559           3 :                                         CurNode.HPWHWrappedCondenserHeatingFrac = 1.0 - (HPWH.WrappedCondenserBottomLocation - H) / CurNode.Height;
    4560          11 :                                     } else if (H >= HPWH.WrappedCondenserBottomLocation && H <= HPWH.WrappedCondenserTopLocation) {
    4561           6 :                                         if (H0 > HPWH.WrappedCondenserTopLocation) {
    4562             :                                             // the top of the condenser ends partway through this node.
    4563           1 :                                             CurNode.HPWHWrappedCondenserHeatingFrac = (HPWH.WrappedCondenserTopLocation - H) / CurNode.Height;
    4564             :                                         } else {
    4565             :                                             // the entire node is wrapped by the condenser
    4566           5 :                                             CurNode.HPWHWrappedCondenserHeatingFrac = 1.0;
    4567             :                                         }
    4568             :                                     } else {
    4569           5 :                                         CurNode.HPWHWrappedCondenserHeatingFrac = 0.0;
    4570             :                                     }
    4571          14 :                                     SumFrac += CurNode.HPWHWrappedCondenserHeatingFrac;
    4572          14 :                                     H0 = H;
    4573             :                                 }
    4574             :                                 // Normalize the fractions so they sum to 1.
    4575          17 :                                 for (int NodeNum = 1; NodeNum <= Tank.Nodes; ++NodeNum) {
    4576          14 :                                     Tank.Node(NodeNum).HPWHWrappedCondenserHeatingFrac /= SumFrac;
    4577             :                                 }
    4578             :                             }
    4579             :                         }
    4580             : 
    4581             :                         // Stratified Tank HPWH control sensor node locations
    4582          11 :                         if (HPWH.ControlSensor1Height < 0.0) {
    4583             :                             // default to heater 1
    4584           0 :                             HPWH.ControlSensor1Height = Tank.HeaterHeight1;
    4585             :                         }
    4586          11 :                         if (HPWH.ControlSensor2Height < 0.0) {
    4587             :                             // default to heater 2
    4588           0 :                             HPWH.ControlSensor2Height = Tank.HeaterHeight2;
    4589             :                         }
    4590             : 
    4591             :                         // Get the vertical tank height depending on the type of tank
    4592             :                         Real64 TankHeight;
    4593          11 :                         if (Tank.Shape == TankShape::VertCylinder || Tank.Shape == TankShape::Other) {
    4594          11 :                             TankHeight = Tank.Height;
    4595             :                         } else {
    4596           0 :                             assert(Tank.Shape == TankShape::HorizCylinder);
    4597             :                             // For horizontal cylinders, the tank "height" is actually the length.
    4598             :                             // We need to calculate the height.
    4599           0 :                             Real64 EndArea = Tank.Volume / Tank.Height;
    4600           0 :                             Real64 Radius = std::sqrt(EndArea / Constant::Pi);
    4601           0 :                             TankHeight = 2.0 * Radius; // actual vertical height
    4602             :                         }
    4603             : 
    4604             :                         // Make sure the control sensor locations are in the tank
    4605          11 :                         if (HPWH.ControlSensor1Height < 0.0 || HPWH.ControlSensor1Height > TankHeight) {
    4606           0 :                             ShowSevereError(state, format("{} = {}:", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    4607           0 :                             ShowContinueError(state, "Control Sensor 1 is located outside the tank.");
    4608           0 :                             ErrorsFound = true;
    4609             :                         }
    4610          11 :                         if (HPWH.ControlSensor2Height < 0.0 || HPWH.ControlSensor2Height > TankHeight) {
    4611           0 :                             ShowSevereError(state, format("{} = {}:", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    4612           0 :                             ShowContinueError(state, "Control Sensor 2 is located outside the tank.");
    4613           0 :                             ErrorsFound = true;
    4614             :                         }
    4615             : 
    4616             :                         // Assign the control sensors to the appropriate nodes
    4617          11 :                         Real64 H0 = TankHeight;
    4618             :                         Real64 H;
    4619          97 :                         for (int NodeNum = 1; NodeNum <= Tank.Nodes; ++NodeNum) {
    4620          86 :                             StratifiedNodeData const &TankNode = Tank.Node(NodeNum);
    4621          86 :                             if (NodeNum == Tank.Nodes) {
    4622          11 :                                 H = -1.0; // Avoids rounding errors and ensures that anything at height 0.0 goes into the bottom node
    4623             :                             } else {
    4624          75 :                                 H = H0 - TankNode.Height;
    4625             :                             }
    4626             : 
    4627             :                             // Control Sensor 1 Node
    4628          86 :                             if (HPWH.ControlSensor1Height <= H0 && HPWH.ControlSensor1Height > H) {
    4629          11 :                                 HPWH.ControlSensor1Node = NodeNum;
    4630             :                             }
    4631             : 
    4632             :                             // Control Sensor 2 Node
    4633          86 :                             if (HPWH.ControlSensor2Height <= H0 && HPWH.ControlSensor2Height > H) {
    4634          11 :                                 HPWH.ControlSensor2Node = NodeNum;
    4635             :                             }
    4636             : 
    4637          86 :                             H0 = H;
    4638             :                         }
    4639             :                     }
    4640             : 
    4641             :                 } // DO CheckWaterHeaterNum = 1, NumWaterHeater
    4642             : 
    4643          23 :                 if (!HPWH.FoundTank) {
    4644           0 :                     ShowSevereError(state, format("{} = {}:", state.dataIPShortCut->cCurrentModuleObject, HPWH.Name));
    4645           0 :                     ShowContinueError(state, format("Water heater tank object not found = {}, {}", HPWH.TankType, HPWH.TankName));
    4646           0 :                     ErrorsFound = true;
    4647             :                 }
    4648             : 
    4649             :             } // DO HPWaterHeaterNum = 1, NumHeatPumpWaterHeater
    4650             :         }
    4651             : 
    4652             :         // Get water heater sizing input.
    4653         442 :         state.dataIPShortCut->cCurrentModuleObject = "WaterHeater:Sizing";
    4654         884 :         state.dataWaterThermalTanks->numWaterHeaterSizing =
    4655         442 :             state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, state.dataIPShortCut->cCurrentModuleObject);
    4656             : 
    4657         442 :         if (state.dataWaterThermalTanks->numWaterHeaterSizing > 0) {
    4658             : 
    4659          10 :             for (int WHsizingNum = 1; WHsizingNum <= state.dataWaterThermalTanks->numWaterHeaterSizing; ++WHsizingNum) {
    4660             :                 int NumAlphas;
    4661             :                 int NumNums;
    4662             :                 int IOStat;
    4663          10 :                 state.dataInputProcessing->inputProcessor->getObjectItem(state,
    4664           5 :                                                                          state.dataIPShortCut->cCurrentModuleObject,
    4665             :                                                                          WHsizingNum,
    4666           5 :                                                                          state.dataIPShortCut->cAlphaArgs,
    4667             :                                                                          NumAlphas,
    4668           5 :                                                                          state.dataIPShortCut->rNumericArgs,
    4669             :                                                                          NumNums,
    4670             :                                                                          IOStat);
    4671             : 
    4672             :                 // find which water heater this object is for
    4673           5 :                 int WaterThermalTankNum = Util::FindItemInList(state.dataIPShortCut->cAlphaArgs(1), state.dataWaterThermalTanks->WaterThermalTank);
    4674           5 :                 if (WaterThermalTankNum == 0) {
    4675             :                     // did not match name throw warning.
    4676           0 :                     ShowSevereError(state,
    4677           0 :                                     format("{} object name: {} does not match any of the water heaters defined in the file",
    4678           0 :                                            state.dataIPShortCut->cCurrentModuleObject,
    4679           0 :                                            state.dataIPShortCut->cAlphaArgs(1)));
    4680           0 :                     ErrorsFound = true;
    4681           0 :                     continue;
    4682             :                 } else { // we have a match
    4683             :                     // store the sizing data in "sizing" nested derived type for the correct water heater
    4684             : 
    4685           5 :                     if (Util::SameString(state.dataIPShortCut->cAlphaArgs(2), "PeakDraw")) {
    4686           2 :                         state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.DesignMode = SizingMode::PeakDraw;
    4687           3 :                     } else if (Util::SameString(state.dataIPShortCut->cAlphaArgs(2), "ResidentialHUD-FHAMinimum")) {
    4688           3 :                         state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.DesignMode = SizingMode::ResidentialMin;
    4689           0 :                     } else if (Util::SameString(state.dataIPShortCut->cAlphaArgs(2), "PerPerson")) {
    4690           0 :                         state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.DesignMode = SizingMode::PerPerson;
    4691           0 :                     } else if (Util::SameString(state.dataIPShortCut->cAlphaArgs(2), "PerFloorArea")) {
    4692           0 :                         state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.DesignMode = SizingMode::PerFloorArea;
    4693           0 :                     } else if (Util::SameString(state.dataIPShortCut->cAlphaArgs(2), "PerUnit")) {
    4694           0 :                         state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.DesignMode = SizingMode::PerUnit;
    4695           0 :                     } else if (Util::SameString(state.dataIPShortCut->cAlphaArgs(2), "PerSolarCollectorArea")) {
    4696           0 :                         state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.DesignMode = SizingMode::PerSolarColArea;
    4697             :                     } else {
    4698             :                         // wrong design mode entered, throw error
    4699           0 :                         ShowSevereError(state,
    4700           0 :                                         format("{} object named: {} contains an incorrect Design Mode of: {}",
    4701           0 :                                                state.dataIPShortCut->cCurrentModuleObject,
    4702           0 :                                                state.dataIPShortCut->cAlphaArgs(1),
    4703           0 :                                                state.dataIPShortCut->cAlphaArgs(2)));
    4704           0 :                         ErrorsFound = true;
    4705             :                     }
    4706             : 
    4707           5 :                     state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.TankDrawTime = state.dataIPShortCut->rNumericArgs(1);
    4708           5 :                     state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.RecoveryTime = state.dataIPShortCut->rNumericArgs(2);
    4709           5 :                     state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.NominalVolForSizingDemandSideFlow =
    4710           5 :                         state.dataIPShortCut->rNumericArgs(3);
    4711           5 :                     state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.NumberOfBedrooms =
    4712           5 :                         int(state.dataIPShortCut->rNumericArgs(4));
    4713           5 :                     state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.NumberOfBathrooms =
    4714           5 :                         int(state.dataIPShortCut->rNumericArgs(5));
    4715           5 :                     state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.TankCapacityPerPerson =
    4716           5 :                         state.dataIPShortCut->rNumericArgs(6);
    4717           5 :                     state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.RecoveryCapacityPerPerson =
    4718           5 :                         state.dataIPShortCut->rNumericArgs(7);
    4719           5 :                     state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.TankCapacityPerArea =
    4720           5 :                         state.dataIPShortCut->rNumericArgs(8);
    4721           5 :                     state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.RecoveryCapacityPerArea =
    4722           5 :                         state.dataIPShortCut->rNumericArgs(9);
    4723           5 :                     state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.NumberOfUnits = state.dataIPShortCut->rNumericArgs(10);
    4724           5 :                     state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.TankCapacityPerUnit =
    4725           5 :                         state.dataIPShortCut->rNumericArgs(11);
    4726           5 :                     state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.RecoveryCapacityPerUnit =
    4727           5 :                         state.dataIPShortCut->rNumericArgs(12);
    4728           5 :                     state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.TankCapacityPerCollectorArea =
    4729           5 :                         state.dataIPShortCut->rNumericArgs(13);
    4730           5 :                     state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.HeightAspectRatio =
    4731           5 :                         state.dataIPShortCut->rNumericArgs(14);
    4732             : 
    4733           5 :                     switch (state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.DesignMode) {
    4734             : 
    4735           0 :                     case SizingMode::Invalid: {
    4736             :                         // do nothing, error thrown if design mode not found
    4737           0 :                         break;
    4738             :                     }
    4739           2 :                     case SizingMode::PeakDraw: { // need to have entered a reasonable value for TankDrawTime
    4740           2 :                         if (state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.TankDrawTime <= 0.0) {
    4741           0 :                             ShowSevereError(state,
    4742           0 :                                             format("{}, named {}, design mode set to Peak Draw but needs a positive value for tank draw time",
    4743           0 :                                                    state.dataIPShortCut->cCurrentModuleObject,
    4744           0 :                                                    state.dataIPShortCut->cAlphaArgs(1)));
    4745           0 :                             ErrorsFound = true;
    4746             :                         }
    4747             :                         // constrain crazy sizes by limiting to 10 years or 8760*10
    4748           2 :                         if (state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.TankDrawTime > 87600.0) {
    4749           0 :                             ShowWarningError(state,
    4750           0 :                                              format("{}, named {},  has input with an unreasonably large Tank Draw Time, more than 10 years",
    4751           0 :                                                     state.dataIPShortCut->cCurrentModuleObject,
    4752           0 :                                                     state.dataIPShortCut->cAlphaArgs(1)));
    4753           0 :                             ErrorsFound = true;
    4754             :                         }
    4755             :                         // if both volume and demand side flow connections are autosized, must be a good NominalVolForSizingDemandSideFlow
    4756           2 :                         if ((state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).UseSidePlantLoc.loopSideNum ==
    4757           2 :                              DataPlant::LoopSideLocation::Demand) &&
    4758           0 :                             (state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).UseDesignVolFlowRateWasAutoSized)) {
    4759           0 :                             if (state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.NominalVolForSizingDemandSideFlow <= 0.0) {
    4760           0 :                                 ShowWarningError(state,
    4761           0 :                                                  format("{}, named {} needs a value for Nominal Tank Volume for Autosizing Plant Connections",
    4762           0 :                                                         state.dataIPShortCut->cCurrentModuleObject,
    4763           0 :                                                         state.dataIPShortCut->cAlphaArgs(1)));
    4764           0 :                                 ErrorsFound = true;
    4765             :                             }
    4766             :                         }
    4767           2 :                         if ((state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).SrcSidePlantLoc.loopSideNum ==
    4768           2 :                              DataPlant::LoopSideLocation::Demand) &&
    4769           0 :                             (state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).SourceDesignVolFlowRateWasAutoSized)) {
    4770           0 :                             if (state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.NominalVolForSizingDemandSideFlow <= 0.0) {
    4771           0 :                                 ShowWarningError(state,
    4772           0 :                                                  format("{}, named {} needs a value for Nominal Tank Volume for Autosizing Plant Connections",
    4773           0 :                                                         state.dataIPShortCut->cCurrentModuleObject,
    4774           0 :                                                         state.dataIPShortCut->cAlphaArgs(1)));
    4775           0 :                                 ErrorsFound = true;
    4776             :                             }
    4777             :                         }
    4778             : 
    4779           2 :                         break;
    4780             :                     }
    4781           3 :                     case SizingMode::ResidentialMin: {
    4782             :                         // it would have to have at least on bedroom and any more than 10 is crazy for this mode
    4783           3 :                         if (state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.NumberOfBedrooms < 1) {
    4784           0 :                             ShowSevereError(state,
    4785           0 :                                             format("{}, named {}, mode needs at least one bedroom",
    4786           0 :                                                    state.dataIPShortCut->cCurrentModuleObject,
    4787           0 :                                                    state.dataIPShortCut->cAlphaArgs(1)));
    4788           0 :                             ErrorsFound = true;
    4789             :                         }
    4790           3 :                         if (state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.NumberOfBedrooms > 10) {
    4791           0 :                             ShowWarningError(state,
    4792           0 :                                              format("{}, named {}, probably has too many bedrooms for the selected design mode",
    4793           0 :                                                     state.dataIPShortCut->cCurrentModuleObject,
    4794           0 :                                                     state.dataIPShortCut->cAlphaArgs(1)));
    4795             :                         }
    4796             : 
    4797           3 :                         break;
    4798             :                     }
    4799           0 :                     case SizingMode::PerPerson: {
    4800             : 
    4801           0 :                         if ((state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).VolumeWasAutoSized) &&
    4802           0 :                             (state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.TankCapacityPerPerson <= 0.0)) {
    4803           0 :                             ShowSevereError(state,
    4804           0 :                                             format("{}, named {}, PerPerson mode needs positive value input for storage capacity per person",
    4805           0 :                                                    state.dataIPShortCut->cCurrentModuleObject,
    4806           0 :                                                    state.dataIPShortCut->cAlphaArgs(1)));
    4807           0 :                             ErrorsFound = true;
    4808             :                         }
    4809             : 
    4810           0 :                         if ((state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).MaxCapacityWasAutoSized) &&
    4811           0 :                             (state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.RecoveryCapacityPerPerson <= 0.0)) {
    4812           0 :                             ShowSevereError(state,
    4813           0 :                                             format("{}, named {}, PerPerson mode needs positive value input for recovery capacity per person",
    4814           0 :                                                    state.dataIPShortCut->cCurrentModuleObject,
    4815           0 :                                                    state.dataIPShortCut->cAlphaArgs(1)));
    4816           0 :                             ErrorsFound = true;
    4817             :                         }
    4818             : 
    4819           0 :                         break;
    4820             :                     }
    4821           0 :                     case SizingMode::PerFloorArea: {
    4822           0 :                         if ((state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).VolumeWasAutoSized) &&
    4823           0 :                             (state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.TankCapacityPerArea <= 0.0)) {
    4824           0 :                             ShowSevereError(state,
    4825           0 :                                             format("{}, named {}, PerArea mode needs positive value input for storage capacity per floor area",
    4826           0 :                                                    state.dataIPShortCut->cCurrentModuleObject,
    4827           0 :                                                    state.dataIPShortCut->cAlphaArgs(1)));
    4828           0 :                             ErrorsFound = true;
    4829             :                         }
    4830           0 :                         if ((state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).MaxCapacityWasAutoSized) &&
    4831           0 :                             (state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.RecoveryCapacityPerArea <= 0.0)) {
    4832           0 :                             ShowSevereError(state,
    4833           0 :                                             format("{}, named {}, PerArea mode needs positive value input for recovery capacity per floor area",
    4834           0 :                                                    state.dataIPShortCut->cCurrentModuleObject,
    4835           0 :                                                    state.dataIPShortCut->cAlphaArgs(1)));
    4836           0 :                             ErrorsFound = true;
    4837             :                         }
    4838             : 
    4839           0 :                         break;
    4840             :                     }
    4841           0 :                     case SizingMode::PerUnit: {
    4842           0 :                         if ((state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).VolumeWasAutoSized) &&
    4843           0 :                             (state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.TankCapacityPerUnit <= 0.0)) {
    4844           0 :                             ShowSevereError(state,
    4845           0 :                                             format("{}, named {}, PerUnit mode needs positive value input for storage capacity per unit",
    4846           0 :                                                    state.dataIPShortCut->cCurrentModuleObject,
    4847           0 :                                                    state.dataIPShortCut->cAlphaArgs(1)));
    4848           0 :                             ErrorsFound = true;
    4849             :                         }
    4850           0 :                         if ((state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).VolumeWasAutoSized) &&
    4851           0 :                             (state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.NumberOfUnits <= 0.0)) {
    4852           0 :                             ShowSevereError(state,
    4853           0 :                                             format("{}, named {}, PerUnit mode needs positive value input for number of units",
    4854           0 :                                                    state.dataIPShortCut->cCurrentModuleObject,
    4855           0 :                                                    state.dataIPShortCut->cAlphaArgs(1)));
    4856           0 :                             ErrorsFound = true;
    4857             :                         }
    4858           0 :                         if ((state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).MaxCapacityWasAutoSized) &&
    4859           0 :                             (state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.RecoveryCapacityPerUnit <= 0.0)) {
    4860           0 :                             ShowSevereError(state,
    4861           0 :                                             format("{}, named {}, PerUnit mode needs positive value input for recovery capacity per unit",
    4862           0 :                                                    state.dataIPShortCut->cCurrentModuleObject,
    4863           0 :                                                    state.dataIPShortCut->cAlphaArgs(1)));
    4864           0 :                             ErrorsFound = true;
    4865             :                         }
    4866           0 :                         if ((state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).MaxCapacityWasAutoSized) &&
    4867           0 :                             (state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.NumberOfUnits <= 0.0)) {
    4868           0 :                             ShowSevereError(state,
    4869           0 :                                             format("{}, named {}, PerUnit mode needs positive value input for number of units",
    4870           0 :                                                    state.dataIPShortCut->cCurrentModuleObject,
    4871           0 :                                                    state.dataIPShortCut->cAlphaArgs(1)));
    4872           0 :                             ErrorsFound = true;
    4873             :                         }
    4874           0 :                         break;
    4875             :                     }
    4876           0 :                     case SizingMode::PerSolarColArea: {
    4877           0 :                         if ((state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).VolumeWasAutoSized) &&
    4878           0 :                             (state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.TankCapacityPerCollectorArea <= 0.0)) {
    4879           0 :                             ShowSevereError(
    4880             :                                 state,
    4881           0 :                                 format("{}, named {}, PerSolarCollectorArea mode needs positive value input for storage capacity per collector area",
    4882           0 :                                        state.dataIPShortCut->cCurrentModuleObject,
    4883           0 :                                        state.dataIPShortCut->cAlphaArgs(1)));
    4884           0 :                             ErrorsFound = true;
    4885             :                         }
    4886           0 :                         break;
    4887             :                     }
    4888           0 :                     default:
    4889           0 :                         break;
    4890             :                     }
    4891             : 
    4892             :                 } // found water heater num okay
    4893             :             }     // loop over sizing objects
    4894             : 
    4895             :         } // any water heater sizing objects
    4896             : 
    4897             :         // now check that if water heater fields were autosized, that there was also a sizing object for that water heater
    4898         442 :         if (state.dataWaterThermalTanks->numWaterThermalTank > 0) {
    4899         330 :             for (int WaterThermalTankNum = 1; WaterThermalTankNum <= state.dataWaterThermalTanks->numWaterThermalTank; ++WaterThermalTankNum) {
    4900             : 
    4901         200 :                 if ((state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).VolumeWasAutoSized) &&
    4902           2 :                     (state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.DesignMode == SizingMode::Invalid)) {
    4903           0 :                     ShowWarningError(
    4904             :                         state,
    4905           0 :                         format("Water heater named {}has tank volume set to AUTOSIZE but it is missing associated WaterHeater:Sizing object",
    4906           0 :                                state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Name));
    4907           0 :                     ErrorsFound = true;
    4908             :                 }
    4909         201 :                 if ((state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).MaxCapacityWasAutoSized) &&
    4910           3 :                     (state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.DesignMode == SizingMode::Invalid)) {
    4911           0 :                     ShowWarningError(
    4912             :                         state,
    4913           0 :                         format("Water heater named {}has heater capacity set to AUTOSIZE but it is missing associated WaterHeater:Sizing object",
    4914           0 :                                state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Name));
    4915           0 :                     ErrorsFound = true;
    4916             :                 }
    4917         198 :                 if ((state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).HeightWasAutoSized) &&
    4918           0 :                     (state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Sizing.DesignMode == SizingMode::Invalid)) {
    4919           0 :                     ShowWarningError(
    4920             :                         state,
    4921           0 :                         format("Water heater named {}has tank height set to AUTOSIZE but it is missing associated WaterHeater:Sizing object",
    4922           0 :                                state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Name));
    4923           0 :                     ErrorsFound = true;
    4924             :                 }
    4925             :             }
    4926             :         }
    4927             : 
    4928             :         //    now do calls to TestCompSet for tanks, depending on nodes and heat pump water heater
    4929         442 :         if (state.dataWaterThermalTanks->numWaterThermalTank > 0) {
    4930         330 :             for (int WaterThermalTankNum = 1; WaterThermalTankNum <= state.dataWaterThermalTanks->numWaterThermalTank; ++WaterThermalTankNum) {
    4931         328 :                 if (state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).UseInletNode > 0 &&
    4932         130 :                     state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).UseOutletNode > 0) {
    4933         130 :                     if (state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).HeatPumpNum > 0) {
    4934             :                         // do nothing, Use nodes are tested for HeatPump:WaterHeater not tank
    4935             :                     } else {
    4936         240 :                         BranchNodeConnections::TestCompSet(state,
    4937         120 :                                                            state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Type,
    4938         120 :                                                            state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Name,
    4939         120 :                                                            state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).InletNodeName1,
    4940         120 :                                                            state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).OutletNodeName1,
    4941             :                                                            "Use Side Water Nodes");
    4942             :                     }
    4943             :                 }
    4944         248 :                 if (state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).SourceInletNode > 0 &&
    4945          50 :                     state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).SourceOutletNode > 0) {
    4946             : 
    4947         100 :                     BranchNodeConnections::TestCompSet(state,
    4948          50 :                                                        state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Type,
    4949          50 :                                                        state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).Name,
    4950          50 :                                                        state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).InletNodeName2,
    4951          50 :                                                        state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).OutletNodeName2,
    4952             :                                                        "Source Side Water Nodes");
    4953             :                 }
    4954             :             }
    4955             :         }
    4956             : 
    4957         442 :         if (state.dataWaterThermalTanks->numWaterThermalTank > 0) {
    4958         330 :             for (int WaterThermalTankNum = 1; WaterThermalTankNum <= state.dataWaterThermalTanks->numWaterThermalTank; ++WaterThermalTankNum) {
    4959             : 
    4960         198 :                 state.dataWaterThermalTanks->WaterThermalTank(WaterThermalTankNum).setupZoneInternalGains(state);
    4961             : 
    4962             :             } // WaterThermalTankNum
    4963             :         }
    4964             :     } // get input flag
    4965             : 
    4966         442 :     return ErrorsFound;
    4967             : }
    4968             : 
    4969         197 : void WaterThermalTankData::setupOutputVars(EnergyPlusData &state)
    4970             : {
    4971         197 :     if ((this->WaterThermalTankType == DataPlant::PlantEquipmentType::ChilledWaterTankMixed) ||
    4972         193 :         (this->WaterThermalTankType == DataPlant::PlantEquipmentType::ChilledWaterTankStratified)) {
    4973           6 :         this->setupChilledWaterTankOutputVars(state);
    4974             :     } else {
    4975             :         // moving setupWaterHeaterOutputVars to here causes big table diffs...
    4976         191 :         this->setupWaterHeaterOutputVars(state);
    4977             :     }
    4978             :     // moving setupZoneInternalGains to here causes math and table diffs...
    4979             :     // this->setupZoneInternalGains();
    4980         197 : }
    4981             : 
    4982           6 : void WaterThermalTankData::setupChilledWaterTankOutputVars(EnergyPlusData &state)
    4983             : {
    4984             : 
    4985             :     // CurrentModuleObject='ThermalStorage:ChilledWater:Mixed/ThermalStorage:ChilledWater:Stratified'
    4986          12 :     SetupOutputVariable(state,
    4987             :                         "Chilled Water Thermal Storage Tank Temperature",
    4988             :                         Constant::Units::C,
    4989           6 :                         this->TankTempAvg,
    4990             :                         OutputProcessor::TimeStepType::System,
    4991             :                         OutputProcessor::StoreType::Average,
    4992           6 :                         this->Name);
    4993             : 
    4994          12 :     SetupOutputVariable(state,
    4995             :                         "Chilled Water Thermal Storage Final Tank Temperature",
    4996             :                         Constant::Units::C,
    4997           6 :                         this->TankTemp,
    4998             :                         OutputProcessor::TimeStepType::System,
    4999             :                         OutputProcessor::StoreType::Average,
    5000           6 :                         this->Name);
    5001             : 
    5002          12 :     SetupOutputVariable(state,
    5003             :                         "Chilled Water Thermal Storage Tank Heat Gain Rate",
    5004             :                         Constant::Units::W,
    5005           6 :                         this->LossRate,
    5006             :                         OutputProcessor::TimeStepType::System,
    5007             :                         OutputProcessor::StoreType::Average,
    5008           6 :                         this->Name);
    5009          12 :     SetupOutputVariable(state,
    5010             :                         "Chilled Water Thermal Storage Tank Heat Gain Energy",
    5011             :                         Constant::Units::J,
    5012           6 :                         this->LossEnergy,
    5013             :                         OutputProcessor::TimeStepType::System,
    5014             :                         OutputProcessor::StoreType::Sum,
    5015           6 :                         this->Name);
    5016             : 
    5017          12 :     SetupOutputVariable(state,
    5018             :                         "Chilled Water Thermal Storage Use Side Mass Flow Rate",
    5019             :                         Constant::Units::kg_s,
    5020           6 :                         this->UseMassFlowRate,
    5021             :                         OutputProcessor::TimeStepType::System,
    5022             :                         OutputProcessor::StoreType::Average,
    5023           6 :                         this->Name);
    5024             : 
    5025          12 :     SetupOutputVariable(state,
    5026             :                         "Chilled Water Thermal Storage Use Side Inlet Temperature",
    5027             :                         Constant::Units::C,
    5028           6 :                         this->UseInletTemp,
    5029             :                         OutputProcessor::TimeStepType::System,
    5030             :                         OutputProcessor::StoreType::Average,
    5031           6 :                         this->Name);
    5032             : 
    5033          12 :     SetupOutputVariable(state,
    5034             :                         "Chilled Water Thermal Storage Use Side Outlet Temperature",
    5035             :                         Constant::Units::C,
    5036           6 :                         this->UseOutletTemp,
    5037             :                         OutputProcessor::TimeStepType::System,
    5038             :                         OutputProcessor::StoreType::Average,
    5039           6 :                         this->Name);
    5040             : 
    5041          12 :     SetupOutputVariable(state,
    5042             :                         "Chilled Water Thermal Storage Use Side Heat Transfer Rate",
    5043             :                         Constant::Units::W,
    5044           6 :                         this->UseRate,
    5045             :                         OutputProcessor::TimeStepType::System,
    5046             :                         OutputProcessor::StoreType::Average,
    5047           6 :                         this->Name);
    5048          12 :     SetupOutputVariable(state,
    5049             :                         "Chilled Water Thermal Storage Use Side Heat Transfer Energy",
    5050             :                         Constant::Units::J,
    5051           6 :                         this->UseEnergy,
    5052             :                         OutputProcessor::TimeStepType::System,
    5053             :                         OutputProcessor::StoreType::Sum,
    5054           6 :                         this->Name);
    5055             : 
    5056          12 :     SetupOutputVariable(state,
    5057             :                         "Chilled Water Thermal Storage Source Side Mass Flow Rate",
    5058             :                         Constant::Units::kg_s,
    5059           6 :                         this->SourceMassFlowRate,
    5060             :                         OutputProcessor::TimeStepType::System,
    5061             :                         OutputProcessor::StoreType::Average,
    5062           6 :                         this->Name);
    5063             : 
    5064          12 :     SetupOutputVariable(state,
    5065             :                         "Chilled Water Thermal Storage Source Side Inlet Temperature",
    5066             :                         Constant::Units::C,
    5067           6 :                         this->SourceInletTemp,
    5068             :                         OutputProcessor::TimeStepType::System,
    5069             :                         OutputProcessor::StoreType::Average,
    5070           6 :                         this->Name);
    5071             : 
    5072          12 :     SetupOutputVariable(state,
    5073             :                         "Chilled Water Thermal Storage Source Side Outlet Temperature",
    5074             :                         Constant::Units::C,
    5075           6 :                         this->SourceOutletTemp,
    5076             :                         OutputProcessor::TimeStepType::System,
    5077             :                         OutputProcessor::StoreType::Average,
    5078           6 :                         this->Name);
    5079             : 
    5080          12 :     SetupOutputVariable(state,
    5081             :                         "Chilled Water Thermal Storage Source Side Heat Transfer Rate",
    5082             :                         Constant::Units::W,
    5083           6 :                         this->SourceRate,
    5084             :                         OutputProcessor::TimeStepType::System,
    5085             :                         OutputProcessor::StoreType::Average,
    5086           6 :                         this->Name);
    5087          12 :     SetupOutputVariable(state,
    5088             :                         "Chilled Water Thermal Storage Source Side Heat Transfer Energy",
    5089             :                         Constant::Units::J,
    5090           6 :                         this->SourceEnergy,
    5091             :                         OutputProcessor::TimeStepType::System,
    5092             :                         OutputProcessor::StoreType::Sum,
    5093           6 :                         this->Name);
    5094             : 
    5095           6 :     if (this->WaterThermalTankType == DataPlant::PlantEquipmentType::ChilledWaterTankStratified) {
    5096             : 
    5097          14 :         for (int NodeNum = 1; NodeNum <= this->Nodes; ++NodeNum) {
    5098          36 :             SetupOutputVariable(state,
    5099          24 :                                 format("Chilled Water Thermal Storage Temperature Node {}", NodeNum),
    5100             :                                 Constant::Units::C,
    5101          12 :                                 this->Node(NodeNum).TempAvg,
    5102             :                                 OutputProcessor::TimeStepType::System,
    5103             :                                 OutputProcessor::StoreType::Average,
    5104          12 :                                 this->Name);
    5105             :         }
    5106             : 
    5107          14 :         for (int NodeNum = 1; NodeNum <= this->Nodes; ++NodeNum) {
    5108          36 :             SetupOutputVariable(state,
    5109          24 :                                 format("Chilled Water Thermal Storage Final Temperature Node {}", NodeNum),
    5110             :                                 Constant::Units::C,
    5111          12 :                                 this->Node(NodeNum).Temp,
    5112             :                                 OutputProcessor::TimeStepType::System,
    5113             :                                 OutputProcessor::StoreType::Average,
    5114          12 :                                 this->Name);
    5115             :         }
    5116             :     }
    5117             : 
    5118           6 :     if (this->WaterThermalTankType == DataPlant::PlantEquipmentType::ChilledWaterTankStratified) {
    5119             : 
    5120          14 :         for (int NodeNum = 1; NodeNum <= this->Nodes; ++NodeNum) {
    5121             :             static constexpr std::string_view Format_724("Chilled Water Tank Stratified Node Information,{},{:.4T},{:.4T},{:.4T},{},{}\n");
    5122             : 
    5123          12 :             print(state.files.eio,
    5124             :                   Format_724,
    5125             :                   NodeNum,
    5126          12 :                   this->Node(NodeNum).Height,
    5127          12 :                   this->Node(NodeNum).Volume,
    5128          12 :                   this->Node(NodeNum).OffCycLossCoeff,
    5129          12 :                   this->Node(NodeNum).Inlets,
    5130          12 :                   this->Node(NodeNum).Outlets);
    5131             :         }
    5132             :     }
    5133           6 : }
    5134             : 
    5135         198 : void WaterThermalTankData::setupZoneInternalGains(EnergyPlusData &state)
    5136             : {
    5137             :     // set up internal gains if tank is in a thermal zone
    5138         198 :     if (this->AmbientTempZone > 0) {
    5139          81 :         switch (this->WaterThermalTankType) {
    5140          70 :         case DataPlant::PlantEquipmentType::WtrHeaterMixed: {
    5141          70 :             SetupZoneInternalGain(state, this->AmbientTempZone, this->Name, DataHeatBalance::IntGainType::WaterHeaterMixed, &this->AmbientZoneGain);
    5142          70 :             break;
    5143             :         }
    5144           6 :         case DataPlant::PlantEquipmentType::WtrHeaterStratified: {
    5145           6 :             SetupZoneInternalGain(
    5146             :                 state, this->AmbientTempZone, this->Name, DataHeatBalance::IntGainType::WaterHeaterStratified, &this->AmbientZoneGain);
    5147           6 :             break;
    5148             :         }
    5149           3 :         case DataPlant::PlantEquipmentType::ChilledWaterTankMixed: {
    5150           3 :             SetupZoneInternalGain(
    5151             :                 state, this->AmbientTempZone, this->Name, DataHeatBalance::IntGainType::ThermalStorageChilledWaterMixed, &this->AmbientZoneGain);
    5152           3 :             break;
    5153             :         }
    5154           2 :         case DataPlant::PlantEquipmentType::ChilledWaterTankStratified: {
    5155           2 :             SetupZoneInternalGain(
    5156             :                 state, this->AmbientTempZone, this->Name, DataHeatBalance::IntGainType::ThermalStorageChilledWaterStratified, &this->AmbientZoneGain);
    5157           2 :             break;
    5158             :         }
    5159           0 :         default:
    5160           0 :             break;
    5161             :         }
    5162             :     }
    5163         198 : }
    5164             : 
    5165         191 : void WaterThermalTankData::setupWaterHeaterOutputVars(EnergyPlusData &state)
    5166             : {
    5167             : 
    5168             :     // Setup report variables for WaterHeater:Mixed
    5169             :     // CurrentModuleObject='WaterHeater:Mixed'
    5170         382 :     SetupOutputVariable(state,
    5171             :                         "Water Heater Tank Temperature",
    5172             :                         Constant::Units::C,
    5173         191 :                         this->TankTempAvg,
    5174             :                         OutputProcessor::TimeStepType::System,
    5175             :                         OutputProcessor::StoreType::Average,
    5176         191 :                         this->Name);
    5177             : 
    5178         382 :     SetupOutputVariable(state,
    5179             :                         "Water Heater Final Tank Temperature",
    5180             :                         Constant::Units::C,
    5181         191 :                         this->TankTemp,
    5182             :                         OutputProcessor::TimeStepType::System,
    5183             :                         OutputProcessor::StoreType::Average,
    5184         191 :                         this->Name);
    5185             : 
    5186         382 :     SetupOutputVariable(state,
    5187             :                         "Water Heater Heat Loss Rate",
    5188             :                         Constant::Units::W,
    5189         191 :                         this->LossRate,
    5190             :                         OutputProcessor::TimeStepType::System,
    5191             :                         OutputProcessor::StoreType::Average,
    5192         191 :                         this->Name);
    5193         382 :     SetupOutputVariable(state,
    5194             :                         "Water Heater Heat Loss Energy",
    5195             :                         Constant::Units::J,
    5196         191 :                         this->LossEnergy,
    5197             :                         OutputProcessor::TimeStepType::System,
    5198             :                         OutputProcessor::StoreType::Sum,
    5199         191 :                         this->Name);
    5200             : 
    5201         382 :     SetupOutputVariable(state,
    5202             :                         "Water Heater Use Side Mass Flow Rate",
    5203             :                         Constant::Units::kg_s,
    5204         191 :                         this->UseMassFlowRate,
    5205             :                         OutputProcessor::TimeStepType::System,
    5206             :                         OutputProcessor::StoreType::Average,
    5207         191 :                         this->Name);
    5208             : 
    5209         382 :     SetupOutputVariable(state,
    5210             :                         "Water Heater Use Side Inlet Temperature",
    5211             :                         Constant::Units::C,
    5212         191 :                         this->UseInletTemp,
    5213             :                         OutputProcessor::TimeStepType::System,
    5214             :                         OutputProcessor::StoreType::Average,
    5215         191 :                         this->Name);
    5216             : 
    5217         382 :     SetupOutputVariable(state,
    5218             :                         "Water Heater Use Side Outlet Temperature",
    5219             :                         Constant::Units::C,
    5220         191 :                         this->UseOutletTemp,
    5221             :                         OutputProcessor::TimeStepType::System,
    5222             :                         OutputProcessor::StoreType::Average,
    5223         191 :                         this->Name);
    5224             : 
    5225         382 :     SetupOutputVariable(state,
    5226             :                         "Water Heater Use Side Heat Transfer Rate",
    5227             :                         Constant::Units::W,
    5228         191 :                         this->UseRate,
    5229             :                         OutputProcessor::TimeStepType::System,
    5230             :                         OutputProcessor::StoreType::Average,
    5231         191 :                         this->Name);
    5232         382 :     SetupOutputVariable(state,
    5233             :                         "Water Heater Use Side Heat Transfer Energy",
    5234             :                         Constant::Units::J,
    5235         191 :                         this->UseEnergy,
    5236             :                         OutputProcessor::TimeStepType::System,
    5237             :                         OutputProcessor::StoreType::Sum,
    5238         191 :                         this->Name);
    5239             : 
    5240         382 :     SetupOutputVariable(state,
    5241             :                         "Water Heater Source Side Mass Flow Rate",
    5242             :                         Constant::Units::kg_s,
    5243         191 :                         this->SourceMassFlowRate,
    5244             :                         OutputProcessor::TimeStepType::System,
    5245             :                         OutputProcessor::StoreType::Average,
    5246         191 :                         this->Name);
    5247             : 
    5248         382 :     SetupOutputVariable(state,
    5249             :                         "Water Heater Source Side Inlet Temperature",
    5250             :                         Constant::Units::C,
    5251         191 :                         this->SourceInletTemp,
    5252             :                         OutputProcessor::TimeStepType::System,
    5253             :                         OutputProcessor::StoreType::Average,
    5254         191 :                         this->Name);
    5255             : 
    5256         382 :     SetupOutputVariable(state,
    5257             :                         "Water Heater Source Side Outlet Temperature",
    5258             :                         Constant::Units::C,
    5259         191 :                         this->SourceOutletTemp,
    5260             :                         OutputProcessor::TimeStepType::System,
    5261             :                         OutputProcessor::StoreType::Average,
    5262         191 :                         this->Name);
    5263             : 
    5264         382 :     SetupOutputVariable(state,
    5265             :                         "Water Heater Source Side Heat Transfer Rate",
    5266             :                         Constant::Units::W,
    5267         191 :                         this->SourceRate,
    5268             :                         OutputProcessor::TimeStepType::System,
    5269             :                         OutputProcessor::StoreType::Average,
    5270         191 :                         this->Name);
    5271         382 :     SetupOutputVariable(state,
    5272             :                         "Water Heater Source Side Heat Transfer Energy",
    5273             :                         Constant::Units::J,
    5274         191 :                         this->SourceEnergy,
    5275             :                         OutputProcessor::TimeStepType::System,
    5276             :                         OutputProcessor::StoreType::Sum,
    5277         191 :                         this->Name,
    5278             :                         Constant::eResource::PlantLoopHeatingDemand,
    5279             :                         OutputProcessor::Group::Plant,
    5280             :                         OutputProcessor::EndUseCat::WaterSystem, // DHW
    5281             :                         this->EndUseSubcategoryName);
    5282             : 
    5283         382 :     SetupOutputVariable(state,
    5284             :                         "Water Heater Off Cycle Parasitic Tank Heat Transfer Rate",
    5285             :                         Constant::Units::W,
    5286         191 :                         this->OffCycParaRateToTank,
    5287             :                         OutputProcessor::TimeStepType::System,
    5288             :                         OutputProcessor::StoreType::Average,
    5289         191 :                         this->Name);
    5290         382 :     SetupOutputVariable(state,
    5291             :                         "Water Heater Off Cycle Parasitic Tank Heat Transfer Energy",
    5292             :                         Constant::Units::J,
    5293         191 :                         this->OffCycParaEnergyToTank,
    5294             :                         OutputProcessor::TimeStepType::System,
    5295             :                         OutputProcessor::StoreType::Sum,
    5296         191 :                         this->Name);
    5297             : 
    5298         382 :     SetupOutputVariable(state,
    5299             :                         "Water Heater On Cycle Parasitic Tank Heat Transfer Rate",
    5300             :                         Constant::Units::W,
    5301         191 :                         this->OnCycParaRateToTank,
    5302             :                         OutputProcessor::TimeStepType::System,
    5303             :                         OutputProcessor::StoreType::Average,
    5304         191 :                         this->Name);
    5305         382 :     SetupOutputVariable(state,
    5306             :                         "Water Heater On Cycle Parasitic Tank Heat Transfer Energy",
    5307             :                         Constant::Units::J,
    5308         191 :                         this->OnCycParaEnergyToTank,
    5309             :                         OutputProcessor::TimeStepType::System,
    5310             :                         OutputProcessor::StoreType::Sum,
    5311         191 :                         this->Name);
    5312             : 
    5313         382 :     SetupOutputVariable(state,
    5314             :                         "Water Heater Total Demand Heat Transfer Rate",
    5315             :                         Constant::Units::W,
    5316         191 :                         this->TotalDemandRate,
    5317             :                         OutputProcessor::TimeStepType::System,
    5318             :                         OutputProcessor::StoreType::Average,
    5319         191 :                         this->Name);
    5320         382 :     SetupOutputVariable(state,
    5321             :                         "Water Heater Total Demand Heat Transfer Energy",
    5322             :                         Constant::Units::J,
    5323         191 :                         this->TotalDemandEnergy,
    5324             :                         OutputProcessor::TimeStepType::System,
    5325             :                         OutputProcessor::StoreType::Sum,
    5326         191 :                         this->Name);
    5327             : 
    5328         382 :     SetupOutputVariable(state,
    5329             :                         "Water Heater Heating Rate",
    5330             :                         Constant::Units::W,
    5331         191 :                         this->HeaterRate,
    5332             :                         OutputProcessor::TimeStepType::System,
    5333             :                         OutputProcessor::StoreType::Average,
    5334         191 :                         this->Name);
    5335         382 :     SetupOutputVariable(state,
    5336             :                         "Water Heater Heating Energy",
    5337             :                         Constant::Units::J,
    5338         191 :                         this->HeaterEnergy,
    5339             :                         OutputProcessor::TimeStepType::System,
    5340             :                         OutputProcessor::StoreType::Sum,
    5341         191 :                         this->Name);
    5342             : 
    5343         382 :     SetupOutputVariable(state,
    5344             :                         "Water Heater Unmet Demand Heat Transfer Rate",
    5345             :                         Constant::Units::W,
    5346         191 :                         this->UnmetRate,
    5347             :                         OutputProcessor::TimeStepType::System,
    5348             :                         OutputProcessor::StoreType::Average,
    5349         191 :                         this->Name);
    5350         382 :     SetupOutputVariable(state,
    5351             :                         "Water Heater Unmet Demand Heat Transfer Energy",
    5352             :                         Constant::Units::J,
    5353         191 :                         this->UnmetEnergy,
    5354             :                         OutputProcessor::TimeStepType::System,
    5355             :                         OutputProcessor::StoreType::Sum,
    5356         191 :                         this->Name);
    5357             : 
    5358         382 :     SetupOutputVariable(state,
    5359             :                         "Water Heater Venting Heat Transfer Rate",
    5360             :                         Constant::Units::W,
    5361         191 :                         this->VentRate,
    5362             :                         OutputProcessor::TimeStepType::System,
    5363             :                         OutputProcessor::StoreType::Average,
    5364         191 :                         this->Name);
    5365         382 :     SetupOutputVariable(state,
    5366             :                         "Water Heater Venting Heat Transfer Energy",
    5367             :                         Constant::Units::J,
    5368         191 :                         this->VentEnergy,
    5369             :                         OutputProcessor::TimeStepType::System,
    5370             :                         OutputProcessor::StoreType::Sum,
    5371         191 :                         this->Name);
    5372             : 
    5373         382 :     SetupOutputVariable(state,
    5374             :                         "Water Heater Net Heat Transfer Rate",
    5375             :                         Constant::Units::W,
    5376         191 :                         this->NetHeatTransferRate,
    5377             :                         OutputProcessor::TimeStepType::System,
    5378             :                         OutputProcessor::StoreType::Average,
    5379         191 :                         this->Name);
    5380         382 :     SetupOutputVariable(state,
    5381             :                         "Water Heater Net Heat Transfer Energy",
    5382             :                         Constant::Units::J,
    5383         191 :                         this->NetHeatTransferEnergy,
    5384             :                         OutputProcessor::TimeStepType::System,
    5385             :                         OutputProcessor::StoreType::Sum,
    5386         191 :                         this->Name);
    5387             : 
    5388         191 :     SetupOutputVariable(state,
    5389             :                         "Water Heater Cycle On Count",
    5390             :                         Constant::Units::None,
    5391         191 :                         this->CycleOnCount,
    5392             :                         OutputProcessor::TimeStepType::System,
    5393             :                         OutputProcessor::StoreType::Sum,
    5394         191 :                         this->Name);
    5395         382 :     SetupOutputVariable(state,
    5396             :                         "Water Heater Runtime Fraction",
    5397             :                         Constant::Units::None,
    5398         191 :                         this->RuntimeFraction,
    5399             :                         OutputProcessor::TimeStepType::System,
    5400             :                         OutputProcessor::StoreType::Average,
    5401         191 :                         this->Name);
    5402         382 :     SetupOutputVariable(state,
    5403             :                         "Water Heater Part Load Ratio",
    5404             :                         Constant::Units::None,
    5405         191 :                         this->PartLoadRatio,
    5406             :                         OutputProcessor::TimeStepType::System,
    5407             :                         OutputProcessor::StoreType::Average,
    5408         191 :                         this->Name);
    5409             : 
    5410         573 :     SetupOutputVariable(state,
    5411         382 :                         format("Water Heater {} Rate", Constant::eFuelNames[static_cast<int>(this->FuelType)]),
    5412             :                         Constant::Units::W,
    5413         191 :                         this->FuelRate,
    5414             :                         OutputProcessor::TimeStepType::System,
    5415             :                         OutputProcessor::StoreType::Average,
    5416         191 :                         this->Name);
    5417         573 :     SetupOutputVariable(state,
    5418         382 :                         format("Water Heater {} Energy", Constant::eFuelNames[static_cast<int>(this->FuelType)]),
    5419             :                         Constant::Units::J,
    5420         191 :                         this->FuelEnergy,
    5421             :                         OutputProcessor::TimeStepType::System,
    5422             :                         OutputProcessor::StoreType::Sum,
    5423         191 :                         this->Name,
    5424         191 :                         Constant::eFuel2eResource[(int)this->FuelType],
    5425             :                         OutputProcessor::Group::Plant,
    5426             :                         OutputProcessor::EndUseCat::WaterSystem, // DHW
    5427             :                         this->EndUseSubcategoryName);
    5428             : 
    5429         573 :     SetupOutputVariable(state,
    5430         382 :                         format("Water Heater Off Cycle Parasitic {} Rate", Constant::eFuelNames[static_cast<int>(this->OffCycParaFuelType)]),
    5431             :                         Constant::Units::W,
    5432         191 :                         this->OffCycParaFuelRate,
    5433             :                         OutputProcessor::TimeStepType::System,
    5434             :                         OutputProcessor::StoreType::Average,
    5435         191 :                         this->Name);
    5436         573 :     SetupOutputVariable(state,
    5437         382 :                         format("Water Heater Off Cycle Parasitic {} Energy", Constant::eFuelNames[static_cast<int>(this->OffCycParaFuelType)]),
    5438             :                         Constant::Units::J,
    5439         191 :                         this->OffCycParaFuelEnergy,
    5440             :                         OutputProcessor::TimeStepType::System,
    5441             :                         OutputProcessor::StoreType::Sum,
    5442         191 :                         this->Name,
    5443         191 :                         Constant::eFuel2eResource[(int)this->OffCycParaFuelType],
    5444             :                         OutputProcessor::Group::Plant,
    5445             :                         OutputProcessor::EndUseCat::WaterSystem, // DHW
    5446             :                         this->EndUseSubcategoryName);
    5447             : 
    5448         573 :     SetupOutputVariable(state,
    5449         382 :                         format("Water Heater On Cycle Parasitic {} Rate", Constant::eFuelNames[static_cast<int>(this->OnCycParaFuelType)]),
    5450             :                         Constant::Units::W,
    5451         191 :                         this->OnCycParaFuelRate,
    5452             :                         OutputProcessor::TimeStepType::System,
    5453             :                         OutputProcessor::StoreType::Average,
    5454         191 :                         this->Name);
    5455         573 :     SetupOutputVariable(state,
    5456         382 :                         format("Water Heater On Cycle Parasitic {} Energy", Constant::eFuelNames[static_cast<int>(this->OnCycParaFuelType)]),
    5457             :                         Constant::Units::J,
    5458         191 :                         this->OnCycParaFuelEnergy,
    5459             :                         OutputProcessor::TimeStepType::System,
    5460             :                         OutputProcessor::StoreType::Sum,
    5461         191 :                         this->Name,
    5462         191 :                         Constant::eFuel2eResource[(int)this->OnCycParaFuelType],
    5463             :                         OutputProcessor::Group::Plant,
    5464             :                         OutputProcessor::EndUseCat::WaterSystem, // DHW
    5465             :                         this->EndUseSubcategoryName);
    5466             : 
    5467         382 :     SetupOutputVariable(state,
    5468             :                         "Water Heater Water Volume Flow Rate",
    5469             :                         Constant::Units::m3_s,
    5470         191 :                         this->VolFlowRate,
    5471             :                         OutputProcessor::TimeStepType::System,
    5472             :                         OutputProcessor::StoreType::Average,
    5473         191 :                         this->Name);
    5474         382 :     SetupOutputVariable(state,
    5475             :                         "Water Heater Water Volume",
    5476             :                         Constant::Units::m3,
    5477         191 :                         this->VolumeConsumed,
    5478             :                         OutputProcessor::TimeStepType::System,
    5479             :                         OutputProcessor::StoreType::Sum,
    5480         191 :                         this->Name,
    5481             :                         Constant::eResource::Water,
    5482             :                         OutputProcessor::Group::Plant,
    5483             :                         OutputProcessor::EndUseCat::WaterSystem, // DHW
    5484             :                         this->EndUseSubcategoryName);
    5485         382 :     SetupOutputVariable(state,
    5486             :                         "Water Heater Mains Water Volume",
    5487             :                         Constant::Units::m3,
    5488         191 :                         this->VolumeConsumed,
    5489             :                         OutputProcessor::TimeStepType::System,
    5490             :                         OutputProcessor::StoreType::Sum,
    5491         191 :                         this->Name,
    5492             :                         Constant::eResource::MainsWater,
    5493             :                         OutputProcessor::Group::Plant,
    5494             :                         OutputProcessor::EndUseCat::WaterSystem, // DHW
    5495             :                         this->EndUseSubcategoryName);
    5496             : 
    5497         191 :     if (this->HeatPumpNum > 0) {
    5498             :         // CurrentModuleObject='WaterHeater:HeatPump:PumpedCondenser'
    5499          23 :         HeatPumpWaterHeaterData &HPWH = state.dataWaterThermalTanks->HPWaterHeater(this->HeatPumpNum);
    5500          46 :         SetupOutputVariable(state,
    5501             :                             "Water Heater Compressor Part Load Ratio",
    5502             :                             Constant::Units::None,
    5503          23 :                             HPWH.HeatingPLR,
    5504             :                             OutputProcessor::TimeStepType::System,
    5505             :                             OutputProcessor::StoreType::Average,
    5506          23 :                             HPWH.Name);
    5507          46 :         SetupOutputVariable(state,
    5508             :                             "Water Heater Off Cycle Ancillary Electricity Rate",
    5509             :                             Constant::Units::W,
    5510          23 :                             HPWH.OffCycParaFuelRate,
    5511             :                             OutputProcessor::TimeStepType::System,
    5512             :                             OutputProcessor::StoreType::Average,
    5513          23 :                             HPWH.Name);
    5514          46 :         SetupOutputVariable(state,
    5515             :                             "Water Heater Off Cycle Ancillary Electricity Energy",
    5516             :                             Constant::Units::J,
    5517          23 :                             HPWH.OffCycParaFuelEnergy,
    5518             :                             OutputProcessor::TimeStepType::System,
    5519             :                             OutputProcessor::StoreType::Sum,
    5520          23 :                             HPWH.Name,
    5521             :                             Constant::eResource::Electricity,
    5522             :                             OutputProcessor::Group::Plant,
    5523             :                             OutputProcessor::EndUseCat::WaterSystem, // DHW
    5524             :                             "Water Heater Parasitic");
    5525          46 :         SetupOutputVariable(state,
    5526             :                             "Water Heater On Cycle Ancillary Electricity Rate",
    5527             :                             Constant::Units::W,
    5528          23 :                             HPWH.OnCycParaFuelRate,
    5529             :                             OutputProcessor::TimeStepType::System,
    5530             :                             OutputProcessor::StoreType::Average,
    5531          23 :                             HPWH.Name);
    5532          46 :         SetupOutputVariable(state,
    5533             :                             "Water Heater On Cycle Ancillary Electricity Energy",
    5534             :                             Constant::Units::J,
    5535          23 :                             HPWH.OnCycParaFuelEnergy,
    5536             :                             OutputProcessor::TimeStepType::System,
    5537             :                             OutputProcessor::StoreType::Sum,
    5538          23 :                             HPWH.Name,
    5539             :                             Constant::eResource::Electricity,
    5540             :                             OutputProcessor::Group::Plant,
    5541             :                             OutputProcessor::EndUseCat::WaterSystem, // DHW
    5542             :                             "Water Heater Parasitic");
    5543          46 :         SetupOutputVariable(state,
    5544             :                             "Water Heater Heat Pump Control Tank Temperature",
    5545             :                             Constant::Units::C,
    5546          23 :                             HPWH.ControlTempAvg,
    5547             :                             OutputProcessor::TimeStepType::System,
    5548             :                             OutputProcessor::StoreType::Average,
    5549          23 :                             HPWH.Name);
    5550          46 :         SetupOutputVariable(state,
    5551             :                             "Water Heater Heat Pump Control Tank Final Temperature",
    5552             :                             Constant::Units::C,
    5553          23 :                             HPWH.ControlTempFinal,
    5554             :                             OutputProcessor::TimeStepType::System,
    5555             :                             OutputProcessor::StoreType::Average,
    5556          23 :                             HPWH.Name);
    5557             :     }
    5558             : 
    5559         191 :     if (this->DesuperheaterNum > 0) {
    5560             :         // CurrentModuleObject='Coil:WaterHeating:Desuperheater'
    5561          12 :         SetupOutputVariable(state,
    5562             :                             "Water Heater Part Load Ratio",
    5563             :                             Constant::Units::None,
    5564           6 :                             state.dataWaterThermalTanks->WaterHeaterDesuperheater(this->DesuperheaterNum).DesuperheaterPLR,
    5565             :                             OutputProcessor::TimeStepType::System,
    5566             :                             OutputProcessor::StoreType::Average,
    5567           6 :                             state.dataWaterThermalTanks->WaterHeaterDesuperheater(this->DesuperheaterNum).Name);
    5568          12 :         SetupOutputVariable(state,
    5569             :                             "Water Heater On Cycle Parasitic Electricity Rate",
    5570             :                             Constant::Units::W,
    5571           6 :                             state.dataWaterThermalTanks->WaterHeaterDesuperheater(this->DesuperheaterNum).OnCycParaFuelRate,
    5572             :                             OutputProcessor::TimeStepType::System,
    5573             :                             OutputProcessor::StoreType::Average,
    5574           6 :                             state.dataWaterThermalTanks->WaterHeaterDesuperheater(this->DesuperheaterNum).Name);
    5575          12 :         SetupOutputVariable(state,
    5576             :                             "Water Heater On Cycle Parasitic Electricity Energy",
    5577             :                             Constant::Units::J,
    5578           6 :                             state.dataWaterThermalTanks->WaterHeaterDesuperheater(this->DesuperheaterNum).OnCycParaFuelEnergy,
    5579             :                             OutputProcessor::TimeStepType::System,
    5580             :                             OutputProcessor::StoreType::Sum,
    5581           6 :                             state.dataWaterThermalTanks->WaterHeaterDesuperheater(this->DesuperheaterNum).Name,
    5582             :                             Constant::eResource::Electricity,
    5583             :                             OutputProcessor::Group::Plant,
    5584             :                             OutputProcessor::EndUseCat::WaterSystem, // DHW
    5585             :                             "Water Heater Parasitic");
    5586          12 :         SetupOutputVariable(state,
    5587             :                             "Water Heater Off Cycle Parasitic Electricity Rate",
    5588             :                             Constant::Units::W,
    5589           6 :                             state.dataWaterThermalTanks->WaterHeaterDesuperheater(this->DesuperheaterNum).OffCycParaFuelRate,
    5590             :                             OutputProcessor::TimeStepType::System,
    5591             :                             OutputProcessor::StoreType::Average,
    5592           6 :                             state.dataWaterThermalTanks->WaterHeaterDesuperheater(this->DesuperheaterNum).Name);
    5593          12 :         SetupOutputVariable(state,
    5594             :                             "Water Heater Off Cycle Parasitic Electricity Energy",
    5595             :                             Constant::Units::J,
    5596           6 :                             state.dataWaterThermalTanks->WaterHeaterDesuperheater(this->DesuperheaterNum).OffCycParaFuelEnergy,
    5597             :                             OutputProcessor::TimeStepType::System,
    5598             :                             OutputProcessor::StoreType::Sum,
    5599           6 :                             state.dataWaterThermalTanks->WaterHeaterDesuperheater(this->DesuperheaterNum).Name,
    5600             :                             Constant::eResource::Electricity,
    5601             :                             OutputProcessor::Group::Plant,
    5602             :                             OutputProcessor::EndUseCat::WaterSystem, // DHW
    5603             :                             "Water Heater Parasitic");
    5604          12 :         SetupOutputVariable(state,
    5605             :                             "Water Heater Heat Reclaim Efficiency Modifier Multiplier",
    5606             :                             Constant::Units::None,
    5607           6 :                             state.dataWaterThermalTanks->WaterHeaterDesuperheater(this->DesuperheaterNum).HEffFTempOutput,
    5608             :                             OutputProcessor::TimeStepType::System,
    5609             :                             OutputProcessor::StoreType::Average,
    5610           6 :                             state.dataWaterThermalTanks->WaterHeaterDesuperheater(this->DesuperheaterNum).Name);
    5611          12 :         SetupOutputVariable(state,
    5612             :                             "Water Heater Pump Electricity Rate",
    5613             :                             Constant::Units::W,
    5614           6 :                             state.dataWaterThermalTanks->WaterHeaterDesuperheater(this->DesuperheaterNum).PumpPower,
    5615             :                             OutputProcessor::TimeStepType::System,
    5616             :                             OutputProcessor::StoreType::Average,
    5617           6 :                             state.dataWaterThermalTanks->WaterHeaterDesuperheater(this->DesuperheaterNum).Name);
    5618          12 :         SetupOutputVariable(state,
    5619             :                             "Water Heater Pump Electricity Energy",
    5620             :                             Constant::Units::J,
    5621           6 :                             state.dataWaterThermalTanks->WaterHeaterDesuperheater(this->DesuperheaterNum).PumpEnergy,
    5622             :                             OutputProcessor::TimeStepType::System,
    5623             :                             OutputProcessor::StoreType::Sum,
    5624           6 :                             state.dataWaterThermalTanks->WaterHeaterDesuperheater(this->DesuperheaterNum).Name,
    5625             :                             Constant::eResource::Electricity,
    5626             :                             OutputProcessor::Group::Plant,
    5627             :                             OutputProcessor::EndUseCat::WaterSystem, // DHW
    5628             :                             "Desuperheater Pump");
    5629          12 :         SetupOutputVariable(state,
    5630             :                             "Water Heater Heating Rate",
    5631             :                             Constant::Units::W,
    5632           6 :                             state.dataWaterThermalTanks->WaterHeaterDesuperheater(this->DesuperheaterNum).HeaterRate,
    5633             :                             OutputProcessor::TimeStepType::System,
    5634             :                             OutputProcessor::StoreType::Average,
    5635           6 :                             state.dataWaterThermalTanks->WaterHeaterDesuperheater(this->DesuperheaterNum).Name);
    5636          12 :         SetupOutputVariable(state,
    5637             :                             "Water Heater Heating Energy",
    5638             :                             Constant::Units::J,
    5639           6 :                             state.dataWaterThermalTanks->WaterHeaterDesuperheater(this->DesuperheaterNum).HeaterEnergy,
    5640             :                             OutputProcessor::TimeStepType::System,
    5641             :                             OutputProcessor::StoreType::Sum,
    5642           6 :                             state.dataWaterThermalTanks->WaterHeaterDesuperheater(this->DesuperheaterNum).Name,
    5643             :                             Constant::eResource::EnergyTransfer,
    5644             :                             OutputProcessor::Group::Plant,
    5645             :                             OutputProcessor::EndUseCat::WaterSystem, // DHW
    5646             :                             "Water Heater");
    5647             :     }
    5648             : 
    5649             :     // Setup report variables for WaterHeater:Stratified
    5650             :     // CurrentModuleObject='WaterHeater:Stratified'
    5651         191 :     if (this->WaterThermalTankType == DataPlant::PlantEquipmentType::WtrHeaterStratified) {
    5652             : 
    5653          32 :         SetupOutputVariable(state,
    5654             :                             "Water Heater Heater 1 Heating Rate",
    5655             :                             Constant::Units::W,
    5656          16 :                             this->HeaterRate1,
    5657             :                             OutputProcessor::TimeStepType::System,
    5658             :                             OutputProcessor::StoreType::Average,
    5659          16 :                             this->Name);
    5660          32 :         SetupOutputVariable(state,
    5661             :                             "Water Heater Heater 2 Heating Rate",
    5662             :                             Constant::Units::W,
    5663          16 :                             this->HeaterRate2,
    5664             :                             OutputProcessor::TimeStepType::System,
    5665             :                             OutputProcessor::StoreType::Average,
    5666          16 :                             this->Name);
    5667             : 
    5668          32 :         SetupOutputVariable(state,
    5669             :                             "Water Heater Heater 1 Heating Energy",
    5670             :                             Constant::Units::J,
    5671          16 :                             this->HeaterEnergy1,
    5672             :                             OutputProcessor::TimeStepType::System,
    5673             :                             OutputProcessor::StoreType::Sum,
    5674          16 :                             this->Name);
    5675          32 :         SetupOutputVariable(state,
    5676             :                             "Water Heater Heater 2 Heating Energy",
    5677             :                             Constant::Units::J,
    5678          16 :                             this->HeaterEnergy2,
    5679             :                             OutputProcessor::TimeStepType::System,
    5680             :                             OutputProcessor::StoreType::Sum,
    5681          16 :                             this->Name);
    5682             : 
    5683          16 :         SetupOutputVariable(state,
    5684             :                             "Water Heater Heater 1 Cycle On Count",
    5685             :                             Constant::Units::None,
    5686          16 :                             this->CycleOnCount1,
    5687             :                             OutputProcessor::TimeStepType::System,
    5688             :                             OutputProcessor::StoreType::Sum,
    5689          16 :                             this->Name);
    5690          16 :         SetupOutputVariable(state,
    5691             :                             "Water Heater Heater 2 Cycle On Count",
    5692             :                             Constant::Units::None,
    5693          16 :                             this->CycleOnCount2,
    5694             :                             OutputProcessor::TimeStepType::System,
    5695             :                             OutputProcessor::StoreType::Sum,
    5696          16 :                             this->Name);
    5697             : 
    5698          32 :         SetupOutputVariable(state,
    5699             :                             "Water Heater Heater 1 Runtime Fraction",
    5700             :                             Constant::Units::None,
    5701          16 :                             this->RuntimeFraction1,
    5702             :                             OutputProcessor::TimeStepType::System,
    5703             :                             OutputProcessor::StoreType::Average,
    5704          16 :                             this->Name);
    5705          32 :         SetupOutputVariable(state,
    5706             :                             "Water Heater Heater 2 Runtime Fraction",
    5707             :                             Constant::Units::None,
    5708          16 :                             this->RuntimeFraction2,
    5709             :                             OutputProcessor::TimeStepType::System,
    5710             :                             OutputProcessor::StoreType::Average,
    5711          16 :                             this->Name);
    5712             : 
    5713         144 :         for (int NodeNum = 1; NodeNum <= this->Nodes; ++NodeNum) {
    5714         384 :             SetupOutputVariable(state,
    5715         256 :                                 format("Water Heater Temperature Node {}", NodeNum),
    5716             :                                 Constant::Units::C,
    5717         128 :                                 this->Node(NodeNum).TempAvg,
    5718             :                                 OutputProcessor::TimeStepType::System,
    5719             :                                 OutputProcessor::StoreType::Average,
    5720         128 :                                 this->Name);
    5721             :         }
    5722             : 
    5723         144 :         for (int NodeNum = 1; NodeNum <= this->Nodes; ++NodeNum) {
    5724         384 :             SetupOutputVariable(state,
    5725         256 :                                 format("Water Heater Final Temperature Node {}", NodeNum),
    5726             :                                 Constant::Units::C,
    5727         128 :                                 this->Node(NodeNum).Temp,
    5728             :                                 OutputProcessor::TimeStepType::System,
    5729             :                                 OutputProcessor::StoreType::Average,
    5730         128 :                                 this->Name);
    5731             :         }
    5732             :     }
    5733             : 
    5734         191 :     if (this->WaterThermalTankType == DataPlant::PlantEquipmentType::WtrHeaterStratified) {
    5735             : 
    5736         144 :         for (int NodeNum = 1; NodeNum <= this->Nodes; ++NodeNum) {
    5737             :             static constexpr std::string_view Format_723("Water Heater Stratified Node Information,{},{:.4T},{:.4T},{:.3T},{:.4T},{:.4T},{},{}\n");
    5738         128 :             print(state.files.eio,
    5739             :                   Format_723,
    5740             :                   NodeNum,
    5741         128 :                   this->Node(NodeNum).Height,
    5742         128 :                   this->Node(NodeNum).Volume,
    5743         128 :                   this->Node(NodeNum).MaxCapacity,
    5744         128 :                   this->Node(NodeNum).OffCycLossCoeff,
    5745         128 :                   this->Node(NodeNum).OnCycLossCoeff,
    5746         128 :                   this->Node(NodeNum).Inlets,
    5747         128 :                   this->Node(NodeNum).Outlets);
    5748             :         }
    5749             :     }
    5750         191 : }
    5751             : 
    5752           0 : void WaterThermalTankData::ValidatePLFCurve(EnergyPlusData &state, int const CurveIndex, bool &IsValid)
    5753             : {
    5754             : 
    5755             :     // SUBROUTINE INFORMATION:
    5756             :     //       AUTHOR         Peter Graham Ellis
    5757             :     //       DATE WRITTEN   February 2005
    5758             :     //       MODIFIED       na
    5759             :     //       RE-ENGINEERED  na
    5760             : 
    5761             :     // PURPOSE OF THIS SUBROUTINE:
    5762             :     // Validates the Part Load Factor curve by making sure it can never be less than or equal to zero
    5763             :     // over the domain of Part Load Ratio inputs from 0 to 1.
    5764             : 
    5765             :     // METHODOLOGY EMPLOYED:
    5766             :     // Currently can only check 0 and 1.  Need changes in CurveManager to be able to check minimums and
    5767             :     // maximums.
    5768             : 
    5769           0 :     IsValid = true;
    5770             : 
    5771             :     // Check 0 and 1
    5772           0 :     if (Curve::CurveValue(state, CurveIndex, 0.0) <= 0) IsValid = false;
    5773           0 :     if (Curve::CurveValue(state, CurveIndex, 1.0) <= 0) IsValid = false;
    5774           0 : }
    5775             : 
    5776          18 : void WaterThermalTankData::SetupStratifiedNodes(EnergyPlusData &state)
    5777             : {
    5778             : 
    5779             :     // SUBROUTINE INFORMATION:
    5780             :     //       AUTHOR         Peter Graham Ellis
    5781             :     //       DATE WRITTEN   January 2007
    5782             :     //       MODIFIED       na
    5783             :     //       RE-ENGINEERED  na
    5784             : 
    5785             :     // PURPOSE OF THIS SUBROUTINE:
    5786             :     // Sets up node properties based on the tank shape, i.e., vertical cylinder, horizontal cylinder, or other.
    5787             :     // Node height, skin area, vertical conduction area, and loss coefficients are calculated and assigned.
    5788             :     // Heating elements, parasitics, and fluid inlet and outlet flows are assigned according to node height.
    5789             : 
    5790             :     // METHODOLOGY EMPLOYED:
    5791             :     // Tank is divided into nodes of equal mass.  For horizontal cylinders, node heights are calculated using
    5792             :     // the Newton-Raphson iterative method.  For vertical cylinders and other shapes, the node heights are calculated
    5793             :     // using basic geometry.
    5794             : 
    5795             :     static constexpr std::string_view RoutineName("GetWaterThermalTankInput");
    5796             : 
    5797          18 :     constexpr Real64 Tolerance(1.0e-8); // Tolerance for Newton-Raphson solution
    5798          18 :     constexpr Real64 FluidCond(0.6);    // Conductivity of water (W/m-K)
    5799             : 
    5800          18 :     int NumNodes = this->Nodes;
    5801          18 :     this->Node.allocate(NumNodes);
    5802             :     Real64 rho;
    5803          18 :     if ((this->UseSidePlantLoc.loopNum > 0) && allocated(state.dataPlnt->PlantLoop)) {
    5804           0 :         rho = FluidProperties::GetDensityGlycol(state,
    5805           0 :                                                 state.dataPlnt->PlantLoop(this->UseSidePlantLoc.loopNum).FluidName,
    5806             :                                                 Constant::InitConvTemp,
    5807           0 :                                                 state.dataPlnt->PlantLoop(this->UseSidePlantLoc.loopNum).FluidIndex,
    5808             :                                                 RoutineName);
    5809             :     } else {
    5810          18 :         rho = FluidProperties::GetDensityGlycol(state, fluidNameWater, Constant::InitConvTemp, this->FluidIndex, RoutineName);
    5811             :     }
    5812             : 
    5813          18 :     Real64 NodeMass = this->Volume * rho / NumNodes;
    5814             :     Real64 TankHeight;
    5815             : 
    5816             :     // Mixing rate set to 50% of the max value for dt = 1.0
    5817          18 :     this->InversionMixingRate = NodeMass * 0.5 * 1.0;
    5818             : 
    5819          18 :     if ((this->Shape == TankShape::VertCylinder) || (this->Shape == TankShape::Other)) {
    5820          18 :         TankHeight = this->Height;
    5821          18 :         Real64 EndArea = this->Volume / TankHeight;
    5822          18 :         Real64 NodeHeight = TankHeight / NumNodes;
    5823          18 :         Real64 CondCoeff = (FluidCond + this->AdditionalCond) * EndArea / NodeHeight;
    5824             : 
    5825             :         Real64 Perimeter_loc;
    5826          18 :         if (this->Shape == TankShape::VertCylinder) {
    5827          18 :             Real64 Radius = std::sqrt(EndArea / Constant::Pi);
    5828          18 :             Perimeter_loc = 2.0 * Constant::Pi * Radius;
    5829             :         } else { // TankShapeOther
    5830           0 :             Perimeter_loc = this->Perimeter;
    5831             :         }
    5832             : 
    5833         158 :         for (int NodeNum = 1; NodeNum <= NumNodes; ++NodeNum) {
    5834         140 :             this->Node(NodeNum).Mass = NodeMass;
    5835         140 :             this->Node(NodeNum).Volume = this->Volume / NumNodes;
    5836         140 :             this->Node(NodeNum).Height = NodeHeight;
    5837         140 :             this->Node(NodeNum).CondCoeffUp = CondCoeff;
    5838         140 :             this->Node(NodeNum).CondCoeffDn = CondCoeff;
    5839             : 
    5840             :             Real64 SkinArea;
    5841         140 :             if ((NodeNum == 1) || (NodeNum == NumNodes)) {
    5842          34 :                 SkinArea = Perimeter_loc * NodeHeight + EndArea;
    5843             :             } else {
    5844         106 :                 SkinArea = Perimeter_loc * NodeHeight;
    5845             :             }
    5846             : 
    5847         140 :             this->Node(NodeNum).OnCycLossCoeff = this->SkinLossCoeff * SkinArea + this->AdditionalLossCoeff(NodeNum);
    5848             : 
    5849         140 :             this->Node(NodeNum).OffCycLossCoeff = this->Node(NodeNum).OnCycLossCoeff + this->OffCycFlueLossCoeff;
    5850             : 
    5851             :         } // NodeNum
    5852             : 
    5853          18 :         this->Node(1).CondCoeffUp = 0.0;
    5854          18 :         this->Node(NumNodes).CondCoeffDn = 0.0;
    5855             : 
    5856          18 :     } else {                              // Tank%Shape == TankShapeHorizCylinder
    5857           0 :         Real64 TankLength = this->Height; // Height is the length in the axial direction
    5858           0 :         Real64 EndArea = this->Volume / TankLength;
    5859           0 :         Real64 Radius = std::sqrt(EndArea / Constant::Pi);
    5860           0 :         TankHeight = 2.0 * Radius; // Actual vertical height
    5861           0 :         Real64 NodeEndArea = EndArea / NumNodes;
    5862             : 
    5863           0 :         Real64 R = Radius;
    5864           0 :         Real64 H0 = 0.0;
    5865           0 :         Real64 ChordLength = 0.0;
    5866           0 :         for (int NodeNum = 1; NodeNum <= NumNodes; ++NodeNum) {
    5867           0 :             this->Node(NodeNum).Mass = NodeMass;
    5868           0 :             this->Node(NodeNum).Volume = this->Volume / NumNodes;
    5869             :             Real64 H;
    5870           0 :             if (NodeNum == NumNodes) {
    5871           0 :                 H = TankHeight;
    5872             :             } else {
    5873             :                 // Use the Newton-Raphson method to solve the nonlinear algebraic equation for node height
    5874           0 :                 H = H0 + TankHeight / NumNodes; // Initial guess
    5875             : 
    5876             :                 while (true) {
    5877           0 :                     Real64 a = std::sqrt(H);
    5878           0 :                     Real64 b = std::sqrt(2.0 * R - H);
    5879           0 :                     Real64 c = 2.0 * R * R * std::atan(a / b) - (2.0 * R * R - 3.0 * H * R + H * H) * (a / b);
    5880             :                     Real64 c0;
    5881           0 :                     if (H0 > 0.0) {
    5882           0 :                         Real64 a0 = std::sqrt(H0);
    5883           0 :                         Real64 b0 = std::sqrt(2.0 * R - H0);
    5884           0 :                         c0 = 2.0 * R * R * std::atan(a0 / b0) - (2.0 * R * R - 3.0 * H0 * R + H0 * H0) * (a0 / b0);
    5885             :                     } else {
    5886           0 :                         c0 = 0.0;
    5887             :                     }
    5888             : 
    5889           0 :                     Real64 ApproxEndArea = c - c0;          // Area approximated by iteration
    5890           0 :                     Real64 G = ApproxEndArea - NodeEndArea; // G is the function that should converge to zero
    5891             : 
    5892           0 :                     if (std::abs(G) < Tolerance) {
    5893           0 :                         break; // Converged !!!
    5894             :                     } else {
    5895           0 :                         H -= G / (2.0 * a * b); // Calculate next guess:  H = Hprev - G/G'
    5896             :                     }
    5897           0 :                 } // Newton-Raphson
    5898             :             }
    5899             : 
    5900           0 :             this->Node(NodeNum).Height = H - H0;
    5901             : 
    5902           0 :             if (NodeNum > 1) {
    5903           0 :                 Real64 CrossArea = 2.0 * ChordLength * TankLength; // Use old ChordLength from previous node
    5904           0 :                 Real64 CondCoeff = (FluidCond + this->AdditionalCond) * CrossArea / (0.5 * (H - H0) + 0.5 * this->Node(NodeNum - 1).Height);
    5905           0 :                 this->Node(NodeNum - 1).CondCoeffUp = CondCoeff; // Set for previous node
    5906           0 :                 this->Node(NodeNum).CondCoeffDn = CondCoeff;     // Set for this node
    5907             :             }
    5908             : 
    5909           0 :             ChordLength = std::sqrt(2.0 * R * H - H * H); // Calc new ChordLength to be used with next node
    5910             : 
    5911           0 :             Real64 Perimeter_loc = 2.0 * R * (std::acos((R - H) / R) - std::acos((R - H0) / R)); // Segments of circular perimeter
    5912           0 :             Real64 SkinArea = Perimeter_loc * TankLength + 2.0 * NodeEndArea;
    5913             : 
    5914           0 :             this->Node(NodeNum).OnCycLossCoeff = this->SkinLossCoeff * SkinArea + this->AdditionalLossCoeff(NodeNum);
    5915             : 
    5916           0 :             this->Node(NodeNum).OffCycLossCoeff = this->Node(NodeNum).OnCycLossCoeff + this->OffCycFlueLossCoeff;
    5917             :             // Although it doesn't make much sense to have a flue in a horizontal tank, keep it in anyway
    5918             : 
    5919           0 :             H0 = H;
    5920             :         } // NodeNum
    5921             : 
    5922           0 :         this->Node(1).CondCoeffUp = 0.0;
    5923           0 :         this->Node(NumNodes).CondCoeffDn = 0.0;
    5924             :     }
    5925             : 
    5926             :     // Loop through nodes again (from top to bottom this time) and assign heating elements, parasitics, flow inlets/outlets
    5927             :     // according to their vertical heights in the tank
    5928          18 :     Real64 H0 = TankHeight;
    5929         158 :     for (int NodeNum = 1; NodeNum <= NumNodes; ++NodeNum) {
    5930             :         Real64 H;
    5931         140 :         if (NodeNum == NumNodes) {
    5932          18 :             H = -1.0; // Avoids rounding errors and ensures that anything at height 0.0 goes into the bottom node
    5933             :         } else {
    5934         122 :             H = H0 - this->Node(NodeNum).Height;
    5935             :         }
    5936             : 
    5937             :         // Assign heater elements to the nodes at the specified heights
    5938         140 :         if ((this->HeaterHeight1 <= H0) && (this->HeaterHeight1 > H)) {
    5939             :             //       sensor node will not get set if user enters 0 for this heater capacity
    5940             :             //       (Tank%MaxCapacity > 0.0d0)) THEN
    5941          18 :             this->HeaterNode1 = NodeNum;
    5942          18 :             this->Node(NodeNum).MaxCapacity = this->MaxCapacity;
    5943             :         }
    5944             : 
    5945         140 :         if ((this->HeaterHeight2 <= H0) && (this->HeaterHeight2 > H)) {
    5946             :             //       sensor node will not get set if user enters 0 for this heater capacity
    5947             :             //      .AND. (Tank%MaxCapacity2 > 0.0d0)) THEN
    5948          18 :             this->HeaterNode2 = NodeNum;
    5949             : 
    5950          18 :             if ((NodeNum == this->HeaterNode1) && (this->StratifiedControlMode == PriorityControlMode::Simultaneous)) {
    5951           0 :                 this->Node(NodeNum).MaxCapacity += this->MaxCapacity2;
    5952             :             } else {
    5953          18 :                 this->Node(NodeNum).MaxCapacity = this->MaxCapacity2;
    5954             :             }
    5955             :         }
    5956             : 
    5957             :         // Assign parasitic heat gains to the nodes at the specified heights
    5958         140 :         if ((this->OffCycParaHeight <= H0) && (this->OffCycParaHeight > H)) {
    5959          18 :             this->Node(NodeNum).OffCycParaLoad = this->OffCycParaFracToTank * this->OffCycParaLoad;
    5960             :         }
    5961             : 
    5962         140 :         if ((this->OnCycParaHeight <= H0) && (this->OnCycParaHeight > H)) {
    5963          18 :             this->Node(NodeNum).OnCycParaLoad = this->OnCycParaFracToTank * this->OnCycParaLoad;
    5964             :         }
    5965             : 
    5966             :         // Assign inlets and outlets to the nodes at the specified heights
    5967         140 :         if ((this->UseInletHeight <= H0) && (this->UseInletHeight > H)) {
    5968          18 :             this->UseInletStratNode = NodeNum;
    5969             : 
    5970          18 :             if ((this->UseInletNode > 0) || (this->MassFlowRateMax > 0.0)) ++this->Node(NodeNum).Inlets;
    5971             :         }
    5972             : 
    5973         140 :         if ((this->UseOutletHeight <= H0) && (this->UseOutletHeight > H)) {
    5974          18 :             this->UseOutletStratNode = NodeNum;
    5975             : 
    5976          18 :             if ((this->UseOutletNode > 0) || (this->MassFlowRateMax > 0.0)) ++this->Node(NodeNum).Outlets;
    5977             :         }
    5978             : 
    5979         140 :         if ((this->SourceInletHeight <= H0) && (this->SourceInletHeight > H) && (this->SourceInletNode > 0)) {
    5980             : 
    5981          11 :             this->SourceInletStratNode = NodeNum;
    5982          11 :             ++this->Node(NodeNum).Inlets;
    5983             :         }
    5984             : 
    5985         140 :         if ((this->SourceOutletHeight <= H0) && (this->SourceOutletHeight > H) && (this->SourceOutletNode > 0)) {
    5986             : 
    5987          11 :             this->SourceOutletStratNode = NodeNum;
    5988          11 :             ++this->Node(NodeNum).Outlets;
    5989             :         }
    5990             : 
    5991         140 :         H0 = H;
    5992             :     } // NodeNum
    5993          18 : }
    5994             : 
    5995     6284636 : void WaterThermalTankData::initialize(EnergyPlusData &state, bool const FirstHVACIteration)
    5996             : {
    5997             : 
    5998             :     // SUBROUTINE INFORMATION:
    5999             :     //       AUTHOR         Peter Graham Ellis
    6000             :     //       DATE WRITTEN   February 2004
    6001             :     //       MODIFIED       FSEC, July 2005
    6002             :     //                      Brent Griffith, October 2007 indirect fired water heater
    6003             :     //                        B. Shen 12/2014, add air-source variable-speed heat pump water heating
    6004             :     //       RE-ENGINEERED  na
    6005             : 
    6006             :     // PURPOSE OF THIS SUBROUTINE:
    6007             :     // Initialize the water heater, heat pump water heater, or desuperheater heating coil objects during the simulation.
    6008             :     // determine flow rates thru use side and source side plant connections (if any)
    6009             : 
    6010             :     // METHODOLOGY EMPLOYED:
    6011             :     // Inlet and outlet nodes are initialized.  Scheduled values are retrieved for the current timestep.
    6012             : 
    6013     6284636 :     auto &ZoneEqSizing = state.dataSize->ZoneEqSizing;
    6014             : 
    6015             :     static constexpr std::string_view RoutineName("InitWaterThermalTank");
    6016             :     static constexpr std::string_view GetWaterThermalTankInput("GetWaterThermalTankInput");
    6017             :     static constexpr std::string_view SizeTankForDemand("SizeTankForDemandSide");
    6018             : 
    6019     6284636 :     if (this->scanPlantLoopsFlag && allocated(state.dataPlnt->PlantLoop)) {
    6020         197 :         if ((this->UseInletNode > 0) && (this->HeatPumpNum == 0)) {
    6021         119 :             bool errFlag = false;
    6022         357 :             PlantUtilities::ScanPlantLoopsForObject(
    6023         238 :                 state, this->Name, this->WaterThermalTankType, this->UseSidePlantLoc, errFlag, _, _, _, this->UseInletNode, _);
    6024         119 :             if (errFlag) {
    6025           0 :                 ShowFatalError(state, "InitWaterThermalTank: Program terminated due to previous condition(s).");
    6026             :             }
    6027             :         }
    6028         197 :         if ((this->UseInletNode > 0) && (this->HeatPumpNum > 0)) {
    6029             :             // this is a heat pump water heater, need a separate block because TypeOf_HeatPumpWtrHeater shows up on Branch
    6030             :             //  (input should probably have been the associated tank )
    6031          10 :             bool errFlag = false;
    6032          30 :             PlantUtilities::ScanPlantLoopsForObject(state,
    6033          10 :                                                     state.dataWaterThermalTanks->HPWaterHeater(this->HeatPumpNum).Name,
    6034          10 :                                                     state.dataWaterThermalTanks->HPWaterHeater(this->HeatPumpNum).HPWHType,
    6035          10 :                                                     this->UseSidePlantLoc,
    6036             :                                                     errFlag,
    6037             :                                                     _,
    6038             :                                                     _,
    6039             :                                                     _,
    6040          10 :                                                     this->UseInletNode,
    6041             :                                                     _);
    6042          10 :             if (errFlag) {
    6043           0 :                 ShowFatalError(state, "InitWaterThermalTank: Program terminated due to previous condition(s).");
    6044             :             }
    6045             :         }
    6046         197 :         if ((this->SourceInletNode > 0) && (this->DesuperheaterNum == 0) && (this->HeatPumpNum == 0)) {
    6047          21 :             bool errFlag = false;
    6048          63 :             PlantUtilities::ScanPlantLoopsForObject(
    6049          42 :                 state, this->Name, this->WaterThermalTankType, this->SrcSidePlantLoc, errFlag, _, _, _, this->SourceInletNode, _);
    6050          21 :             if (this->UseInletNode > 0) {
    6051          21 :                 PlantUtilities::InterConnectTwoPlantLoopSides(state, this->UseSidePlantLoc, this->SrcSidePlantLoc, this->WaterThermalTankType, true);
    6052             :             }
    6053          21 :             if (errFlag) {
    6054           0 :                 ShowFatalError(state, "InitWaterThermalTank: Program terminated due to previous condition(s).");
    6055             :             }
    6056             :         }
    6057         197 :         this->scanPlantLoopsFlag = false;
    6058             :     }
    6059             : 
    6060     6284636 :     if (this->SetLoopIndexFlag && allocated(state.dataPlnt->PlantLoop)) {
    6061        1434 :         if ((this->UseInletNode > 0) && (this->HeatPumpNum == 0)) {
    6062        1356 :             Real64 rho = FluidProperties::GetDensityGlycol(state,
    6063        1356 :                                                            state.dataPlnt->PlantLoop(this->UseSidePlantLoc.loopNum).FluidName,
    6064             :                                                            Constant::InitConvTemp,
    6065        1356 :                                                            state.dataPlnt->PlantLoop(this->UseSidePlantLoc.loopNum).FluidIndex,
    6066             :                                                            GetWaterThermalTankInput);
    6067        1356 :             this->PlantUseMassFlowRateMax = this->UseDesignVolFlowRate * rho;
    6068        1356 :             this->Mass = this->Volume * rho;
    6069        1356 :             this->UseSidePlantSizNum = state.dataPlnt->PlantLoop(this->UseSidePlantLoc.loopNum).PlantSizNum;
    6070        1356 :             if ((this->UseDesignVolFlowRateWasAutoSized) && (this->UseSidePlantSizNum == 0)) {
    6071           0 :                 ShowSevereError(state,
    6072           0 :                                 format("InitWaterThermalTank: Did not find Sizing:Plant object for use side of plant thermal tank = {}", this->Name));
    6073           0 :                 ShowFatalError(state, "InitWaterThermalTank: Program terminated due to previous condition(s).");
    6074             :             }
    6075             :         }
    6076        1434 :         if ((this->UseInletNode > 0) && (this->HeatPumpNum > 0)) {
    6077          10 :             Real64 rho = FluidProperties::GetDensityGlycol(state,
    6078          10 :                                                            state.dataPlnt->PlantLoop(this->UseSidePlantLoc.loopNum).FluidName,
    6079             :                                                            Constant::InitConvTemp,
    6080          10 :                                                            state.dataPlnt->PlantLoop(this->UseSidePlantLoc.loopNum).FluidIndex,
    6081             :                                                            GetWaterThermalTankInput);
    6082          10 :             this->PlantUseMassFlowRateMax = this->UseDesignVolFlowRate * rho;
    6083          10 :             this->Mass = this->Volume * rho;
    6084          10 :             this->UseSidePlantSizNum = state.dataPlnt->PlantLoop(this->UseSidePlantLoc.loopNum).PlantSizNum;
    6085          10 :             if ((this->UseDesignVolFlowRateWasAutoSized) && (this->UseSidePlantSizNum == 0)) {
    6086           0 :                 ShowSevereError(state,
    6087           0 :                                 format("InitWaterThermalTank: Did not find Sizing:Plant object for use side of plant thermal tank = {}", this->Name));
    6088           0 :                 ShowFatalError(state, "InitWaterThermalTank: Program terminated due to previous condition(s).");
    6089             :             }
    6090             :         }
    6091        1434 :         if ((this->SourceInletNode > 0) && (this->DesuperheaterNum == 0) && (this->HeatPumpNum == 0)) {
    6092         379 :             Real64 rho = FluidProperties::GetDensityGlycol(state,
    6093         379 :                                                            state.dataPlnt->PlantLoop(this->SrcSidePlantLoc.loopNum).FluidName,
    6094             :                                                            Constant::InitConvTemp,
    6095         379 :                                                            state.dataPlnt->PlantLoop(this->SrcSidePlantLoc.loopNum).FluidIndex,
    6096             :                                                            GetWaterThermalTankInput);
    6097         379 :             this->PlantSourceMassFlowRateMax = this->SourceDesignVolFlowRate * rho;
    6098         379 :             this->SourceSidePlantSizNum = state.dataPlnt->PlantLoop(this->SrcSidePlantLoc.loopNum).PlantSizNum;
    6099         379 :             if ((this->SourceDesignVolFlowRateWasAutoSized) && (this->SourceSidePlantSizNum == 0)) {
    6100           0 :                 ShowSevereError(
    6101           0 :                     state, format("InitWaterThermalTank: Did not find Sizing:Plant object for source side of plant thermal tank = {}", this->Name));
    6102           0 :                 ShowFatalError(state, "InitWaterThermalTank: Program terminated due to previous condition(s).");
    6103             :             }
    6104             :         }
    6105        1434 :         if (((this->SourceInletNode > 0) && (this->DesuperheaterNum > 0)) || (this->HeatPumpNum > 0)) {
    6106          29 :             this->SetLoopIndexFlag = false;
    6107             :         }
    6108        1434 :         if (state.dataPlnt->PlantFirstSizesOkayToFinalize) this->SetLoopIndexFlag = false;
    6109        1434 :         if (this->StandAlone) {
    6110          49 :             this->SizeStandAloneWaterHeater(state);
    6111          49 :             this->SetLoopIndexFlag = false;
    6112             :         }
    6113     6283202 :     } else if (this->SetLoopIndexFlag && !state.dataGlobal->AnyPlantInModel) {
    6114           0 :         if (this->StandAlone) {
    6115           0 :             this->SizeStandAloneWaterHeater(state);
    6116             :         }
    6117           0 :         this->SetLoopIndexFlag = false;
    6118             :     }
    6119             : 
    6120     6284636 :     if (state.dataGlobal->BeginEnvrnFlag && this->MyEnvrnFlag && !this->SetLoopIndexFlag) {
    6121             : 
    6122       49289 :         if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
    6123             : 
    6124       48385 :             if (this->ControlType == HeaterControlMode::Cycle) {
    6125       47867 :                 this->MinCapacity = this->MaxCapacity;
    6126             :             }
    6127             : 
    6128             :             // check for sizing issues that model can not support
    6129             : 
    6130             :             // if stratified tank model, ensure that nominal change over rate is greater than one minute, avoid numerical problems.
    6131             : 
    6132       48385 :             if ((this->WaterThermalTankType == DataPlant::PlantEquipmentType::WtrHeaterStratified) ||
    6133       46059 :                 (this->WaterThermalTankType == DataPlant::PlantEquipmentType::ChilledWaterTankStratified)) {
    6134        3004 :                 Real64 MaxSideVolFlow = max(this->UseDesignVolFlowRate, this->SourceDesignVolFlowRate);
    6135             : 
    6136        3004 :                 if (MaxSideVolFlow > 0.0) { // protect div by zero
    6137        2827 :                     Real64 TankChangeRateScale = this->Volume / MaxSideVolFlow;
    6138        2827 :                     if (TankChangeRateScale < 60.0) { // nominal change over in less than one minute
    6139           0 :                         ShowSevereError(state, "InitWaterThermalTank: Detected problem for stratified tank model.  Model cannot be applied.");
    6140           0 :                         ShowContinueError(state, format("Occurs for stratified tank name = {}", this->Name));
    6141           0 :                         ShowContinueError(state, format("Tank volume = {:.4R} [m3]", this->Volume));
    6142           0 :                         ShowContinueError(state, format("Tank use side volume flow rate = {:.4R} [m3/s]", this->UseDesignVolFlowRate));
    6143           0 :                         ShowContinueError(state, format("Tank source side volume flow rate = {:.4R} [m3/s]", this->SourceDesignVolFlowRate));
    6144           0 :                         ShowContinueError(state, format("Nominal tank change over rate = {:.2R} [s]", TankChangeRateScale));
    6145           0 :                         ShowContinueError(
    6146             :                             state, "Change over rate is too fast, increase tank volume, decrease connection flow rates or use mixed tank model");
    6147             : 
    6148           0 :                         ShowFatalError(state, "InitWaterThermalTank: Simulation halted because of sizing problem in stratified tank model.");
    6149             :                     }
    6150             :                 }
    6151             :             }
    6152             :         }
    6153             : 
    6154             :         // Clear node initial conditions
    6155       49289 :         if (this->UseInletNode > 0 && this->UseOutletNode > 0) {
    6156       47796 :             state.dataLoopNodes->Node(this->UseInletNode).Temp = 0.0;
    6157       47796 :             Real64 rho = FluidProperties::GetDensityGlycol(state,
    6158       47796 :                                                            state.dataPlnt->PlantLoop(this->UseSidePlantLoc.loopNum).FluidName,
    6159             :                                                            Constant::InitConvTemp,
    6160       47796 :                                                            state.dataPlnt->PlantLoop(this->UseSidePlantLoc.loopNum).FluidIndex,
    6161             :                                                            GetWaterThermalTankInput);
    6162       47796 :             this->MassFlowRateMin = this->VolFlowRateMin * rho;
    6163       47796 :             this->PlantUseMassFlowRateMax = this->UseDesignVolFlowRate * rho;
    6164       47796 :             PlantUtilities::InitComponentNodes(state, this->MassFlowRateMin, this->PlantUseMassFlowRateMax, this->UseInletNode, this->UseOutletNode);
    6165       47796 :             this->UseOutletTemp = 0.0;
    6166       47796 :             this->UseMassFlowRate = 0.0;
    6167       47796 :             this->SavedUseOutletTemp = 0.0;
    6168             : 
    6169       47796 :             this->Mass = this->Volume * rho;
    6170       47796 :             this->UseBranchControlType = DataPlant::CompData::getPlantComponent(state, this->UseSidePlantLoc).FlowCtrl;
    6171             :         }
    6172             : 
    6173       49289 :         if ((this->SourceInletNode > 0) && (this->DesuperheaterNum == 0) && (this->HeatPumpNum == 0)) {
    6174       14760 :             Real64 rho = FluidProperties::GetDensityGlycol(state,
    6175       14760 :                                                            state.dataPlnt->PlantLoop(this->SrcSidePlantLoc.loopNum).FluidName,
    6176             :                                                            Constant::InitConvTemp,
    6177       14760 :                                                            state.dataPlnt->PlantLoop(this->SrcSidePlantLoc.loopNum).FluidIndex,
    6178             :                                                            GetWaterThermalTankInput);
    6179       14760 :             this->PlantSourceMassFlowRateMax = this->SourceDesignVolFlowRate * rho;
    6180       14760 :             PlantUtilities::InitComponentNodes(state, 0.0, this->PlantSourceMassFlowRateMax, this->SourceInletNode, this->SourceOutletNode);
    6181             : 
    6182       14760 :             this->SourceOutletTemp = 0.0;
    6183       14760 :             this->SourceMassFlowRate = 0.0;
    6184       14760 :             this->SavedSourceOutletTemp = 0.0;
    6185             : 
    6186       14760 :             this->SourceBranchControlType = DataPlant::CompData::getPlantComponent(state, this->SrcSidePlantLoc).FlowCtrl;
    6187             :         }
    6188             : 
    6189       49289 :         if ((this->SourceInletNode > 0) && ((this->DesuperheaterNum > 0) || (this->HeatPumpNum > 0))) {
    6190        2410 :             state.dataLoopNodes->Node(this->SourceInletNode).Temp = 0.0;
    6191        2410 :             this->SourceOutletTemp = 0.0;
    6192        2410 :             this->SourceMassFlowRate = 0.0;
    6193        2410 :             this->SavedSourceOutletTemp = 0.0;
    6194        2410 :             Real64 rho = FluidProperties::GetDensityGlycol(state, fluidNameWater, Constant::InitConvTemp, this->FluidIndex, SizeTankForDemand);
    6195        2410 :             this->PlantSourceMassFlowRateMax = this->SourceDesignVolFlowRate * rho;
    6196             :         }
    6197             : 
    6198             :         // Initialize tank temperature to setpoint of first hour of warm up period
    6199             :         // (use HPWH or Desuperheater heating coil set point if applicable)
    6200             :         int SchIndex;
    6201       49289 :         if (this->HeatPumpNum > 0) {
    6202        2278 :             state.dataWaterThermalTanks->HPWaterHeater(this->HeatPumpNum).Mode = TankOperatingMode::Floating;
    6203        2278 :             state.dataWaterThermalTanks->HPWaterHeater(this->HeatPumpNum).SaveMode = TankOperatingMode::Floating;
    6204        2278 :             state.dataWaterThermalTanks->HPWaterHeater(this->HeatPumpNum).SaveWHMode = TankOperatingMode::Floating;
    6205        2278 :             SchIndex = state.dataWaterThermalTanks->HPWaterHeater(this->HeatPumpNum).SetPointTempSchedule;
    6206       47011 :         } else if (this->DesuperheaterNum > 0) {
    6207         132 :             state.dataWaterThermalTanks->WaterHeaterDesuperheater(this->DesuperheaterNum).Mode = TankOperatingMode::Floating;
    6208         132 :             SchIndex = state.dataWaterThermalTanks->WaterHeaterDesuperheater(this->DesuperheaterNum).SetPointTempSchedule;
    6209             :         } else {
    6210       46879 :             SchIndex = this->SetPointTempSchedule;
    6211             :         }
    6212             : 
    6213       49289 :         if (SchIndex > 0) {
    6214       49289 :             this->TankTemp = ScheduleManager::GetCurrentScheduleValue(state, SchIndex);
    6215       49289 :             this->SavedTankTemp = this->TankTemp;
    6216             : 
    6217       49289 :             if (this->Nodes > 0) {
    6218       27013 :                 for (auto &e : this->Node) {
    6219       23926 :                     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       49289 :         this->SourceOutletTemp = this->SavedTankTemp;
    6233       49289 :         this->SavedSourceOutletTemp = this->SavedTankTemp;
    6234       49289 :         this->UseOutletTemp = this->SavedTankTemp;
    6235       49289 :         this->SavedUseOutletTemp = this->SavedTankTemp;
    6236       49289 :         this->TankTempAvg = this->SavedTankTemp;
    6237             : 
    6238       49289 :         this->SavedHeaterOn1 = false;
    6239       49289 :         this->SavedHeaterOn2 = false;
    6240       49289 :         this->Mode = TankOperatingMode::Floating;
    6241       49289 :         this->SavedMode = TankOperatingMode::Floating;
    6242       49289 :         this->FirstRecoveryDone = false;
    6243       49289 :         this->FirstRecoveryFuel = 0.0;
    6244       49289 :         this->UnmetEnergy = 0.0;
    6245       49289 :         this->LossEnergy = 0.0;
    6246       49289 :         this->FlueLossEnergy = 0.0;
    6247       49289 :         this->UseEnergy = 0.0;
    6248       49289 :         this->TotalDemandEnergy = 0.0;
    6249       49289 :         this->SourceEnergy = 0.0;
    6250       49289 :         this->HeaterEnergy = 0.0;
    6251       49289 :         this->HeaterEnergy1 = 0.0;
    6252       49289 :         this->HeaterEnergy2 = 0.0;
    6253       49289 :         this->FuelEnergy = 0.0;
    6254       49289 :         this->FuelEnergy1 = 0.0;
    6255       49289 :         this->FuelEnergy2 = 0.0;
    6256       49289 :         this->VentEnergy = 0.0;
    6257       49289 :         this->OffCycParaFuelEnergy = 0.0;
    6258       49289 :         this->OffCycParaEnergyToTank = 0.0;
    6259       49289 :         this->OnCycParaFuelEnergy = 0.0;
    6260       49289 :         this->OnCycParaEnergyToTank = 0.0;
    6261       49289 :         this->NetHeatTransferEnergy = 0.0;
    6262             :     }
    6263             : 
    6264     6284636 :     if (!state.dataGlobal->BeginEnvrnFlag) this->MyEnvrnFlag = true;
    6265             : 
    6266     6284636 :     if (this->WarmupFlag && (!state.dataGlobal->WarmupFlag)) {
    6267             :         // reInitialize tank temperature to setpoint of first hour (use HPWH or Desuperheater heating coil set point if applicable)
    6268             :         // BG's interpretation here is that its better to reset initial condition to setpoint once warm up is over.
    6269             :         // (otherwise with a dynamic storage model it is difficult for the user to see the initial performance if it isn't periodic.)
    6270             :         int SchIndex;
    6271         437 :         if (this->HeatPumpNum > 0) {
    6272          46 :             state.dataWaterThermalTanks->HPWaterHeater(this->HeatPumpNum).Mode = TankOperatingMode::Floating;
    6273          46 :             SchIndex = state.dataWaterThermalTanks->HPWaterHeater(this->HeatPumpNum).SetPointTempSchedule;
    6274         391 :         } else if (this->DesuperheaterNum > 0) {
    6275          12 :             state.dataWaterThermalTanks->WaterHeaterDesuperheater(this->DesuperheaterNum).Mode = TankOperatingMode::Floating;
    6276          12 :             SchIndex = state.dataWaterThermalTanks->WaterHeaterDesuperheater(this->DesuperheaterNum).SetPointTempSchedule;
    6277             :         } else {
    6278         379 :             SchIndex = this->SetPointTempSchedule;
    6279             :         }
    6280             : 
    6281         437 :         if (SchIndex > 0) {
    6282         437 :             this->TankTemp = ScheduleManager::GetCurrentScheduleValue(state, SchIndex);
    6283         437 :             this->SavedTankTemp = this->TankTemp;
    6284             : 
    6285         437 :             if (this->Nodes > 0) {
    6286         316 :                 for (auto &e : this->Node) {
    6287         280 :                     e.Temp = e.SavedTemp = this->TankTemp;
    6288             :                 }
    6289             :             }
    6290             :         } else {
    6291           0 :             this->TankTemp = 20.0;
    6292           0 :             this->SavedTankTemp = this->TankTemp;
    6293             : 
    6294           0 :             if (this->Nodes > 0) {
    6295           0 :                 for (auto &e : this->Node) {
    6296           0 :                     e.Temp = e.SavedTemp = this->TankTemp;
    6297             :                 }
    6298             :             }
    6299             :         }
    6300         437 :         this->SourceOutletTemp = this->SavedTankTemp;
    6301         437 :         this->SavedSourceOutletTemp = this->SavedTankTemp;
    6302         437 :         this->UseOutletTemp = this->SavedTankTemp;
    6303         437 :         this->SavedUseOutletTemp = this->SavedTankTemp;
    6304         437 :         this->SavedHeaterOn1 = false;
    6305         437 :         this->SavedHeaterOn2 = false;
    6306         437 :         this->Mode = TankOperatingMode::Floating;
    6307         437 :         this->SavedMode = TankOperatingMode::Floating;
    6308         437 :         this->WarmupFlag = false;
    6309             :     }
    6310     6284636 :     if (state.dataGlobal->WarmupFlag) this->WarmupFlag = true;
    6311             : 
    6312     6284636 :     if (FirstHVACIteration) {
    6313             :         // Get all scheduled values
    6314     3008026 :         int SchIndex = this->SetPointTempSchedule;
    6315     3008026 :         this->SetPointTemp = ScheduleManager::GetCurrentScheduleValue(state, SchIndex);
    6316             : 
    6317     3008026 :         if (!this->IsChilledWaterTank) {
    6318     2723759 :             if (this->SetPointTemp > this->TankTempLimit) {
    6319             :                 // Setpoint temperature scheduled higher than maximum tank temperature limit
    6320           0 :                 this->SetPointTemp = this->TankTempLimit - 1.0;
    6321             : 
    6322           0 :                 if (this->ShowSetPointWarning) {
    6323           0 :                     ShowSevereError(
    6324             :                         state,
    6325           0 :                         format("Water heater = {}:  Water heater tank set point temperature is greater than the maximum tank temperature limit.",
    6326           0 :                                this->Name));
    6327           0 :                     ShowContinueErrorTimeStamp(state,
    6328           0 :                                                format("Water heater tank set point temperature is reset to Tank Temperature Limit minus 1 C "
    6329             :                                                       "({:.2T}) and simulation continues.",
    6330           0 :                                                       this->SetPointTemp));
    6331           0 :                     this->ShowSetPointWarning = false;
    6332             :                 }
    6333             :             }
    6334             :         } else {
    6335      284267 :             if (this->SetPointTemp < this->TankTempLimit) {
    6336             :                 // Setpoint temperature scheduled lower than minimum tank temperature limit
    6337           0 :                 this->SetPointTemp = this->TankTempLimit + 1.0;
    6338             : 
    6339           0 :                 if (this->ShowSetPointWarning) {
    6340           0 :                     ShowSevereError(
    6341             :                         state,
    6342           0 :                         format("Chilled Water Tank = {}:  Water heater tank set point temperature is lower than the minimum tank temperature limit.",
    6343           0 :                                this->Name));
    6344           0 :                     ShowContinueErrorTimeStamp(state,
    6345           0 :                                                format("Chilled water tank set point temperature is reset to Tank Temperature Limit plus 1 C "
    6346             :                                                       "({:.2T}) and simulation continues.",
    6347           0 :                                                       this->SetPointTemp));
    6348           0 :                     this->ShowSetPointWarning = false;
    6349             :                 }
    6350             :             }
    6351             :         }
    6352             : 
    6353     3008026 :         SchIndex = this->SetPointTempSchedule2;
    6354     3008026 :         if (SchIndex > 0) {
    6355      158244 :             this->SetPointTemp2 = ScheduleManager::GetCurrentScheduleValue(state, SchIndex);
    6356             :         }
    6357             : 
    6358     3008026 :         switch (this->AmbientTempIndicator) {
    6359     2244433 :         case WTTAmbientTemp::Schedule: {
    6360     2244433 :             SchIndex = this->AmbientTempSchedule;
    6361     2244433 :             this->AmbientTemp = ScheduleManager::GetCurrentScheduleValue(state, SchIndex);
    6362             : 
    6363     2244433 :             break;
    6364             :         }
    6365      611344 :         case WTTAmbientTemp::TempZone: {
    6366      611344 :             this->AmbientTemp = state.dataZoneTempPredictorCorrector->zoneHeatBalance(this->AmbientTempZone).MAT;
    6367             : 
    6368      611344 :             break;
    6369             :         }
    6370      152249 :         case WTTAmbientTemp::OutsideAir: {
    6371      152249 :             this->AmbientTemp = state.dataLoopNodes->Node(this->AmbientTempOutsideAirNode).Temp;
    6372      152249 :             break;
    6373             :         }
    6374           0 :         default:
    6375           0 :             break;
    6376             :         }
    6377             : 
    6378     3008026 :         if (this->UseInletNode == 0) { // Stand-alone operation
    6379             : 
    6380      212099 :             SchIndex = this->UseInletTempSchedule;
    6381      212099 :             if (SchIndex > 0) {
    6382       80871 :                 this->UseInletTemp = ScheduleManager::GetCurrentScheduleValue(state, SchIndex);
    6383             :             } else {
    6384      131228 :                 this->UseInletTemp = state.dataEnvrn->WaterMainsTemp;
    6385             :             }
    6386             : 
    6387      212099 :             SchIndex = this->FlowRateSchedule;
    6388      212099 :             if (SchIndex > 0) {
    6389      212099 :                 this->UseMassFlowRate = ScheduleManager::GetCurrentScheduleValue(state, SchIndex) * this->MassFlowRateMax;
    6390             : 
    6391      212099 :                 this->VolFlowRate = this->UseMassFlowRate / Psychrometrics::RhoH2O(Constant::InitConvTemp);
    6392             :             } else {
    6393           0 :                 this->UseMassFlowRate = this->MassFlowRateMax;
    6394           0 :                 this->VolFlowRate = this->UseMassFlowRate / Psychrometrics::RhoH2O(Constant::InitConvTemp);
    6395             :             }
    6396             :         }
    6397             : 
    6398     3008026 :         if (this->HeatPumpNum > 0) {
    6399      226094 :             state.dataWaterThermalTanks->HPWaterHeater(this->HeatPumpNum).SetPointTemp =
    6400      226094 :                 ScheduleManager::GetCurrentScheduleValue(state, state.dataWaterThermalTanks->HPWaterHeater(this->HeatPumpNum).SetPointTempSchedule);
    6401      226094 :             if (state.dataWaterThermalTanks->HPWaterHeater(this->HeatPumpNum).SetPointTemp >= this->TankTempLimit) {
    6402             :                 // HP setpoint temperature scheduled equal to or higher than tank temperature limit
    6403           0 :                 state.dataWaterThermalTanks->HPWaterHeater(this->HeatPumpNum).SetPointTemp = this->TankTempLimit - 1.0;
    6404             : 
    6405           0 :                 if (state.dataWaterThermalTanks->HPWaterHeater(this->HeatPumpNum).ShowSetPointWarning) {
    6406           0 :                     ShowSevereError(state,
    6407           0 :                                     format("Heat Pump Water Heater = {}:  Heat Pump water heater set point temperature is equal to or greater than "
    6408             :                                            "the maximum tank temperature limit.",
    6409           0 :                                            state.dataWaterThermalTanks->HPWaterHeater(this->HeatPumpNum).Name));
    6410           0 :                     ShowContinueErrorTimeStamp(state,
    6411           0 :                                                format("Heat Pump water heater tank set point temperature is reset to Tank Temperature Limit "
    6412             :                                                       "minus 1 C ({:.2T}) and simulation continues.",
    6413           0 :                                                       state.dataWaterThermalTanks->HPWaterHeater(this->HeatPumpNum).SetPointTemp));
    6414           0 :                     state.dataWaterThermalTanks->HPWaterHeater(this->HeatPumpNum).ShowSetPointWarning = false;
    6415             :                 }
    6416             :             }
    6417             :         }
    6418             : 
    6419     3008026 :         if (this->DesuperheaterNum > 0) {
    6420       14742 :             state.dataWaterThermalTanks->WaterHeaterDesuperheater(this->DesuperheaterNum).SetPointTemp = ScheduleManager::GetCurrentScheduleValue(
    6421       14742 :                 state, state.dataWaterThermalTanks->WaterHeaterDesuperheater(this->DesuperheaterNum).SetPointTempSchedule);
    6422             :         }
    6423             : 
    6424             :     } // first HVAC Iteration
    6425             : 
    6426     6284636 :     if (this->UseInletNode > 0 && !this->SetLoopIndexFlag) { // setup mass flows for plant connections
    6427             :         Real64 DeadBandTemp;
    6428     5862748 :         if (this->IsChilledWaterTank) {
    6429      573190 :             DeadBandTemp = this->SetPointTemp + this->DeadBandDeltaTemp;
    6430             :         } else {
    6431     5289558 :             DeadBandTemp = this->SetPointTemp - this->DeadBandDeltaTemp;
    6432             :         }
    6433             : 
    6434    11725496 :         Real64 mdotUse = this->PlantMassFlowRatesFunc(state,
    6435             :                                                       this->UseInletNode,
    6436             :                                                       FirstHVACIteration,
    6437             :                                                       WaterHeaterSide::Use,
    6438             :                                                       this->UseSidePlantLoc.loopSideNum,
    6439     5862748 :                                                       this->UseSideSeries,
    6440             :                                                       this->UseBranchControlType,
    6441             :                                                       this->SavedUseOutletTemp,
    6442             :                                                       DeadBandTemp,
    6443     5862748 :                                                       this->SetPointTemp);
    6444     5862748 :         PlantUtilities::SetComponentFlowRate(state, mdotUse, this->UseInletNode, this->UseOutletNode, this->UseSidePlantLoc);
    6445             : 
    6446     5862748 :         this->UseInletTemp = state.dataLoopNodes->Node(this->UseInletNode).Temp;
    6447     5862748 :         this->UseMassFlowRate = mdotUse;
    6448             :     }
    6449             : 
    6450     6284636 :     if (this->SourceInletNode > 0 && !this->SetLoopIndexFlag) { // setup mass flows for plant connections
    6451             :         Real64 DeadBandTemp;
    6452     1858772 :         if (this->IsChilledWaterTank) {
    6453      418496 :             DeadBandTemp = this->SetPointTemp + this->DeadBandDeltaTemp;
    6454             :         } else {
    6455     1440276 :             DeadBandTemp = this->SetPointTemp - this->DeadBandDeltaTemp;
    6456             :         }
    6457             : 
    6458             :         Real64 sensedTemp;
    6459     1858772 :         if (this->WaterThermalTankType == DataPlant::PlantEquipmentType::ChilledWaterTankStratified) {
    6460      104404 :             int tmpNodeNum = this->HeaterNode1;
    6461      104404 :             sensedTemp = this->Node(tmpNodeNum).SavedTemp;
    6462             :         } else {
    6463     1754368 :             sensedTemp = this->SavedSourceOutletTemp;
    6464             :         }
    6465             : 
    6466     3717544 :         Real64 mdotSource = this->PlantMassFlowRatesFunc(state,
    6467             :                                                          this->SourceInletNode,
    6468             :                                                          FirstHVACIteration,
    6469             :                                                          WaterHeaterSide::Source,
    6470             :                                                          this->SrcSidePlantLoc.loopSideNum,
    6471     1858772 :                                                          this->SourceSideSeries,
    6472             :                                                          this->SourceBranchControlType,
    6473             :                                                          sensedTemp,
    6474             :                                                          DeadBandTemp,
    6475     1858772 :                                                          this->SetPointTemp);
    6476     1858772 :         if (this->SrcSidePlantLoc.loopNum > 0) {
    6477     1380552 :             PlantUtilities::SetComponentFlowRate(state, mdotSource, this->SourceInletNode, this->SourceOutletNode, this->SrcSidePlantLoc);
    6478             :         } else { // not really plant connected (desuperheater or heat pump)
    6479      478220 :             state.dataLoopNodes->Node(this->SourceInletNode).MassFlowRate = mdotSource;
    6480      478220 :             state.dataLoopNodes->Node(this->SourceOutletNode).MassFlowRate = mdotSource;
    6481             :         }
    6482             : 
    6483     1858772 :         this->SourceInletTemp = state.dataLoopNodes->Node(this->SourceInletNode).Temp;
    6484     1858772 :         this->SourceMassFlowRate = mdotSource;
    6485             :     }
    6486             : 
    6487             :     // initialize HPWHs each iteration
    6488     6284636 :     if (this->HeatPumpNum > 0) {
    6489             : 
    6490      448736 :         int HPNum = this->HeatPumpNum;
    6491             : 
    6492      448736 :         if (this->MyHPSizeFlag) {
    6493             :             //     autosize info must be calculated in GetWaterThermalTankInputFlag for use in StandardRating procedure
    6494             :             //       (called at end of GetWaterThermalTankInputFlag)
    6495             :             //     report autosizing information here (must be done after GetWaterThermalTankInputFlag is complete)
    6496          61 :             if (state.dataWaterThermalTanks->HPWaterHeater(HPNum).WaterFlowRateAutoSized &&
    6497          16 :                 (state.dataPlnt->PlantFirstSizesOkayToReport || !state.dataGlobal->AnyPlantInModel || this->AlreadyRated)) {
    6498          16 :                 BaseSizer::reportSizerOutput(state,
    6499           8 :                                              state.dataWaterThermalTanks->HPWaterHeater(HPNum).Type,
    6500           8 :                                              state.dataWaterThermalTanks->HPWaterHeater(HPNum).Name,
    6501             :                                              "Condenser water flow rate [m3/s]",
    6502           8 :                                              state.dataWaterThermalTanks->HPWaterHeater(HPNum).OperatingWaterFlowRate);
    6503             :             }
    6504          65 :             if (state.dataWaterThermalTanks->HPWaterHeater(HPNum).AirFlowRateAutoSized &&
    6505          20 :                 (state.dataPlnt->PlantFirstSizesOkayToReport || !state.dataGlobal->AnyPlantInModel || this->AlreadyRated)) {
    6506          20 :                 BaseSizer::reportSizerOutput(state,
    6507          10 :                                              state.dataWaterThermalTanks->HPWaterHeater(HPNum).Type,
    6508          10 :                                              state.dataWaterThermalTanks->HPWaterHeater(HPNum).Name,
    6509             :                                              "Evaporator air flow rate [m3/s]",
    6510          10 :                                              state.dataWaterThermalTanks->HPWaterHeater(HPNum).OperatingAirFlowRate);
    6511             :             }
    6512          45 :             state.dataSize->DataNonZoneNonAirloopValue = state.dataWaterThermalTanks->HPWaterHeater(HPNum).OperatingAirFlowRate;
    6513          45 :             state.dataWaterThermalTanks->HPWaterHeater(HPNum).OperatingAirMassFlowRate =
    6514          45 :                 state.dataWaterThermalTanks->HPWaterHeater(HPNum).OperatingAirFlowRate * state.dataEnvrn->StdRhoAir;
    6515          45 :             if (state.dataSize->CurZoneEqNum > 0) {
    6516          12 :                 ZoneEqSizing(state.dataSize->CurZoneEqNum).CoolingAirFlow = true;
    6517          12 :                 ZoneEqSizing(state.dataSize->CurZoneEqNum).CoolingAirVolFlow = state.dataSize->DataNonZoneNonAirloopValue;
    6518             :             }
    6519          45 :             if (state.dataPlnt->PlantFirstSizesOkayToReport || !state.dataGlobal->AnyPlantInModel || this->AlreadyRated) this->MyHPSizeFlag = false;
    6520             :         }
    6521             : 
    6522      448736 :         int HPAirInletNode = state.dataWaterThermalTanks->HPWaterHeater(HPNum).HeatPumpAirInletNode;
    6523      448736 :         int HPAirOutletNode = state.dataWaterThermalTanks->HPWaterHeater(HPNum).HeatPumpAirOutletNode;
    6524      448736 :         int OutdoorAirNode = state.dataWaterThermalTanks->HPWaterHeater(HPNum).OutsideAirNode;
    6525      448736 :         int ExhaustAirNode = state.dataWaterThermalTanks->HPWaterHeater(HPNum).ExhaustAirNode;
    6526      448736 :         int HPWaterInletNode = state.dataWaterThermalTanks->HPWaterHeater(HPNum).CondWaterInletNode;
    6527      448736 :         int HPWaterOutletNode = state.dataWaterThermalTanks->HPWaterHeater(HPNum).CondWaterOutletNode;
    6528      448736 :         int InletAirMixerNode = state.dataWaterThermalTanks->HPWaterHeater(HPNum).InletAirMixerNode;
    6529      448736 :         int OutletAirSplitterNode = state.dataWaterThermalTanks->HPWaterHeater(HPNum).OutletAirSplitterNode;
    6530             : 
    6531      448736 :         switch (state.dataWaterThermalTanks->HPWaterHeater(HPNum).CrankcaseTempIndicator) {
    6532      189862 :         case CrankcaseHeaterControlTemp::Zone: {
    6533      379724 :             state.dataHVACGlobal->HPWHCrankcaseDBTemp =
    6534      189862 :                 state.dataZoneTempPredictorCorrector->zoneHeatBalance(state.dataWaterThermalTanks->HPWaterHeater(HPNum).AmbientTempZone).MAT;
    6535      189862 :             break;
    6536             :         }
    6537      239560 :         case CrankcaseHeaterControlTemp::Outdoors: {
    6538      239560 :             state.dataHVACGlobal->HPWHCrankcaseDBTemp = state.dataEnvrn->OutDryBulbTemp;
    6539      239560 :             break;
    6540             :         }
    6541       19314 :         case CrankcaseHeaterControlTemp::Schedule: {
    6542       38628 :             state.dataHVACGlobal->HPWHCrankcaseDBTemp =
    6543       19314 :                 ScheduleManager::GetCurrentScheduleValue(state, state.dataWaterThermalTanks->HPWaterHeater(HPNum).CrankcaseTempSchedule);
    6544       19314 :             break;
    6545             :         }
    6546           0 :         default:
    6547           0 :             break;
    6548             :         }
    6549             : 
    6550             :         //   initialize HPWH report variables to 0 and set tank inlet node equal to outlet node
    6551      448736 :         state.dataWaterThermalTanks->HPWaterHeater(HPNum).HPWaterHeaterSensibleCapacity = 0.0;
    6552      448736 :         state.dataWaterThermalTanks->HPWaterHeater(HPNum).HPWaterHeaterLatentCapacity = 0.0;
    6553      448736 :         this->SourceMassFlowRate = 0.0;
    6554      448736 :         state.dataWaterThermalTanks->HPWaterHeater(HPNum).HeatingPLR = 0.0;
    6555      448736 :         this->SourceInletTemp = this->SourceOutletTemp;
    6556             : 
    6557             :         //   determine HPWH inlet air conditions based on inlet air configuration (Zone, ZoneAndOA, OutdoorAir, or Schedule)
    6558      448736 :         Real64 HPInletDryBulbTemp = 0.0;
    6559      448736 :         Real64 HPInletHumRat = 0.0;
    6560             :         Real64 HPInletRelHum;
    6561      448736 :         switch (state.dataWaterThermalTanks->HPWaterHeater(HPNum).InletAirConfiguration) {
    6562      169833 :         case WTTAmbientTemp::TempZone: {
    6563      169833 :             state.dataWaterThermalTanks->mixerInletAirSchedule = 0.0;
    6564      169833 :             HPInletDryBulbTemp = state.dataLoopNodes->Node(HPAirInletNode).Temp;
    6565      169833 :             HPInletHumRat = state.dataLoopNodes->Node(HPAirInletNode).HumRat;
    6566      169833 :             break;
    6567             :         }
    6568       20029 :         case WTTAmbientTemp::ZoneAndOA: {
    6569       20029 :             if (state.dataWaterThermalTanks->HPWaterHeater(HPNum).InletAirMixerSchPtr > 0) {
    6570             :                 //         schedule values are checked for boundary of 0 and 1 in GetWaterThermalTankInputFlag
    6571       20029 :                 state.dataWaterThermalTanks->mixerInletAirSchedule =
    6572       20029 :                     ScheduleManager::GetCurrentScheduleValue(state, state.dataWaterThermalTanks->HPWaterHeater(HPNum).InletAirMixerSchPtr);
    6573             :             } else {
    6574           0 :                 state.dataWaterThermalTanks->mixerInletAirSchedule = 0.0;
    6575             :             }
    6576       20029 :             HPInletDryBulbTemp = state.dataWaterThermalTanks->mixerInletAirSchedule * state.dataLoopNodes->Node(OutdoorAirNode).Temp +
    6577       20029 :                                  (1.0 - state.dataWaterThermalTanks->mixerInletAirSchedule) * state.dataLoopNodes->Node(HPAirInletNode).Temp;
    6578       20029 :             HPInletHumRat = state.dataWaterThermalTanks->mixerInletAirSchedule * state.dataLoopNodes->Node(OutdoorAirNode).HumRat +
    6579       20029 :                             (1.0 - state.dataWaterThermalTanks->mixerInletAirSchedule) * state.dataLoopNodes->Node(HPAirInletNode).HumRat;
    6580       20029 :             break;
    6581             :         }
    6582      239560 :         case WTTAmbientTemp::OutsideAir: {
    6583      239560 :             state.dataWaterThermalTanks->mixerInletAirSchedule = 1.0;
    6584      239560 :             HPInletDryBulbTemp = state.dataLoopNodes->Node(OutdoorAirNode).Temp;
    6585      239560 :             HPInletHumRat = state.dataLoopNodes->Node(OutdoorAirNode).HumRat;
    6586             : 
    6587      239560 :             break;
    6588             :         }
    6589       19314 :         case WTTAmbientTemp::Schedule: {
    6590             :             HPInletDryBulbTemp =
    6591       19314 :                 ScheduleManager::GetCurrentScheduleValue(state, state.dataWaterThermalTanks->HPWaterHeater(HPNum).AmbientTempSchedule);
    6592       19314 :             HPInletRelHum = ScheduleManager::GetCurrentScheduleValue(state, state.dataWaterThermalTanks->HPWaterHeater(HPNum).AmbientRHSchedule);
    6593       19314 :             HPInletHumRat = Psychrometrics::PsyWFnTdbRhPb(state, HPInletDryBulbTemp, HPInletRelHum, state.dataEnvrn->OutBaroPress, RoutineName);
    6594       19314 :             state.dataLoopNodes->Node(HPAirInletNode).Temp = HPInletDryBulbTemp;
    6595       19314 :             state.dataLoopNodes->Node(HPAirInletNode).HumRat = HPInletHumRat;
    6596       19314 :             state.dataLoopNodes->Node(HPAirInletNode).Enthalpy = Psychrometrics::PsyHFnTdbW(HPInletDryBulbTemp, HPInletHumRat);
    6597       19314 :             state.dataLoopNodes->Node(HPAirInletNode).Press = state.dataEnvrn->OutBaroPress;
    6598             : 
    6599       19314 :             break;
    6600             :         }
    6601           0 :         default:
    6602           0 :             assert(false);
    6603             :             break;
    6604             :         }
    6605             : 
    6606      448736 :         state.dataWaterThermalTanks->mdotAir = state.dataWaterThermalTanks->HPWaterHeater(HPNum).OperatingAirMassFlowRate;
    6607             : 
    6608             :         //   set up initial conditions on nodes
    6609      448736 :         if (InletAirMixerNode > 0) {
    6610       20029 :             state.dataLoopNodes->Node(InletAirMixerNode).MassFlowRate = 0.0;
    6611       20029 :             state.dataLoopNodes->Node(InletAirMixerNode).MassFlowRateMax = state.dataWaterThermalTanks->mdotAir;
    6612       20029 :             state.dataLoopNodes->Node(InletAirMixerNode).MassFlowRateMaxAvail = state.dataWaterThermalTanks->mdotAir;
    6613       20029 :             state.dataLoopNodes->Node(InletAirMixerNode).Temp = HPInletDryBulbTemp;
    6614       20029 :             state.dataLoopNodes->Node(InletAirMixerNode).HumRat = HPInletHumRat;
    6615       20029 :             state.dataLoopNodes->Node(InletAirMixerNode).Enthalpy = Psychrometrics::PsyHFnTdbW(HPInletDryBulbTemp, HPInletHumRat);
    6616       20029 :             state.dataLoopNodes->Node(HPAirInletNode).MassFlowRate = 0.0;
    6617       20029 :             state.dataLoopNodes->Node(HPAirOutletNode).MassFlowRate = 0.0;
    6618       20029 :             state.dataLoopNodes->Node(OutdoorAirNode).MassFlowRate = 0.0;
    6619       20029 :             state.dataLoopNodes->Node(ExhaustAirNode).MassFlowRate = 0.0;
    6620             :         } else {
    6621      428707 :             if (OutdoorAirNode == 0) {
    6622      189147 :                 state.dataLoopNodes->Node(HPAirInletNode).MassFlowRate = 0.0;
    6623      189147 :                 state.dataLoopNodes->Node(HPAirInletNode).MassFlowRateMax = state.dataWaterThermalTanks->mdotAir;
    6624      189147 :                 state.dataLoopNodes->Node(HPAirInletNode).MassFlowRateMaxAvail = state.dataWaterThermalTanks->mdotAir;
    6625      189147 :                 state.dataLoopNodes->Node(HPAirOutletNode).MassFlowRate = 0.0;
    6626             :             } else {
    6627      239560 :                 state.dataLoopNodes->Node(OutdoorAirNode).MassFlowRate = 0.0;
    6628      239560 :                 state.dataLoopNodes->Node(OutdoorAirNode).MassFlowRateMax = state.dataWaterThermalTanks->mdotAir;
    6629      239560 :                 state.dataLoopNodes->Node(OutdoorAirNode).MassFlowRateMaxAvail = state.dataWaterThermalTanks->mdotAir;
    6630      239560 :                 state.dataLoopNodes->Node(ExhaustAirNode).MassFlowRate = 0.0;
    6631             :             }
    6632             :         }
    6633             : 
    6634      448736 :         if (OutletAirSplitterNode > 0) state.dataLoopNodes->Node(OutletAirSplitterNode).MassFlowRate = 0.0;
    6635             :         // these are water nodes are not managed by plant. the HP connects
    6636             :         // directly to the WH without using plant.
    6637      448736 :         if (state.dataWaterThermalTanks->HPWaterHeater(HPNum).HPWHType == DataPlant::PlantEquipmentType::HeatPumpWtrHeaterPumped) {
    6638      344781 :             state.dataLoopNodes->Node(HPWaterInletNode).MassFlowRate = 0.0;
    6639      344781 :             state.dataLoopNodes->Node(HPWaterOutletNode).MassFlowRate = 0.0;
    6640             :         }
    6641             : 
    6642             :         //   set the max mass flow rate for outdoor fans
    6643      448736 :         state.dataLoopNodes->Node(state.dataWaterThermalTanks->HPWaterHeater(HPNum).FanOutletNode).MassFlowRateMax =
    6644      448736 :             state.dataWaterThermalTanks->mdotAir;
    6645             : 
    6646             :         //   Curve objects in DXCoils::CalcHPWHDXCoil will use inlet conditions to HPWH not inlet air conditions to DX Coil
    6647             :         //   HPWHInletDBTemp and HPWHInletWBTemp are DataHVACGlobals to pass info to HPWHDXCoil
    6648      448736 :         state.dataHVACGlobal->HPWHInletDBTemp = HPInletDryBulbTemp;
    6649      897472 :         state.dataHVACGlobal->HPWHInletWBTemp =
    6650      448736 :             Psychrometrics::PsyTwbFnTdbWPb(state, state.dataHVACGlobal->HPWHInletDBTemp, HPInletHumRat, state.dataEnvrn->OutBaroPress);
    6651             : 
    6652             :         // initialize flow rates at speed levels for variable-speed HPWH
    6653      458782 :         if ((state.dataWaterThermalTanks->HPWaterHeater(HPNum).bIsIHP) &&
    6654       10046 :             (0 == state.dataWaterThermalTanks->HPWaterHeater(HPNum).NumofSpeed)) // use SCWH coil represents
    6655             :         {
    6656           1 :             IntegratedHeatPump::SizeIHP(state, state.dataWaterThermalTanks->HPWaterHeater(HPNum).DXCoilNum); //
    6657             :             // IntegratedHeatPump::SimIHP(modBlankString, HPWaterHeater(HPNum).DXCoilNum,
    6658             :             //    0, EMP1, EMP2, EMP3, 0, 0.0, 1, 0.0, 0.0, 0.0, false, 0.0); //conduct the sizing operation in the IHP
    6659           1 :             int VSCoilID = state.dataIntegratedHP->IntegratedHeatPumps(state.dataWaterThermalTanks->HPWaterHeater(HPNum).DXCoilNum).SCWHCoilIndex;
    6660           1 :             state.dataWaterThermalTanks->HPWaterHeater(HPNum).NumofSpeed = state.dataVariableSpeedCoils->VarSpeedCoil(VSCoilID).NumOfSpeeds;
    6661             : 
    6662      448735 :         } else if (Util::SameString(state.dataWaterThermalTanks->HPWaterHeater(HPNum).DXCoilType,
    6663      547453 :                                     "Coil:WaterHeating:AirToWaterHeatPump:VariableSpeed") &&
    6664       98718 :                    (state.dataWaterThermalTanks->HPWaterHeater(HPNum).NumofSpeed == 0)) {
    6665           6 :             VariableSpeedCoils::SimVariableSpeedCoils(state,
    6666           6 :                                                       std::string(),
    6667           6 :                                                       state.dataWaterThermalTanks->HPWaterHeater(HPNum).DXCoilNum,
    6668             :                                                       HVAC::FanOp::Invalid, // Invalid instead of off?
    6669             :                                                       HVAC::CompressorOp::Off,
    6670             :                                                       0.0,
    6671             :                                                       1,
    6672             :                                                       0.0,
    6673             :                                                       0.0,
    6674             :                                                       0.0,
    6675             :                                                       0.0); // conduct the sizing operation in the VS WSHP
    6676           6 :             int VSCoilID = state.dataWaterThermalTanks->HPWaterHeater(HPNum).DXCoilNum;
    6677           6 :             state.dataWaterThermalTanks->HPWaterHeater(HPNum).NumofSpeed = state.dataVariableSpeedCoils->VarSpeedCoil(VSCoilID).NumOfSpeeds;
    6678             :             // below pass the flow rates from the VS coil to the water heater object
    6679             :         }
    6680             : 
    6681      448736 :         if (state.dataWaterThermalTanks->HPWaterHeater(HPNum).NumofSpeed > 0) {
    6682             :             int VSCoilID;
    6683      108764 :             if (state.dataWaterThermalTanks->HPWaterHeater(HPNum).bIsIHP)
    6684       10046 :                 VSCoilID = state.dataIntegratedHP->IntegratedHeatPumps(state.dataWaterThermalTanks->HPWaterHeater(HPNum).DXCoilNum).SCWHCoilIndex;
    6685             :             else
    6686       98718 :                 VSCoilID = state.dataWaterThermalTanks->HPWaterHeater(HPNum).DXCoilNum;
    6687             : 
    6688             :             // scale air flow rates
    6689      108764 :             Real64 MulSpeedFlowScale = state.dataVariableSpeedCoils->VarSpeedCoil(VSCoilID).RatedAirVolFlowRate /
    6690      108764 :                                        state.dataVariableSpeedCoils->VarSpeedCoil(VSCoilID).MSRatedAirVolFlowRate(
    6691      108764 :                                            state.dataVariableSpeedCoils->VarSpeedCoil(VSCoilID).NormSpedLevel);
    6692     1196404 :             for (int Iter = 1; Iter <= state.dataWaterThermalTanks->HPWaterHeater(HPNum).NumofSpeed; ++Iter) {
    6693     1087640 :                 state.dataWaterThermalTanks->HPWaterHeater(HPNum).HPWHAirVolFlowRate(Iter) =
    6694     1087640 :                     state.dataVariableSpeedCoils->VarSpeedCoil(VSCoilID).MSRatedAirVolFlowRate(Iter) * MulSpeedFlowScale;
    6695             :             }
    6696             : 
    6697             :             // check fan flow rate, should be larger than the max flow rate of the VS coil
    6698      108764 :             Real64 FanVolFlow = state.dataFans->fans(state.dataWaterThermalTanks->HPWaterHeater(HPNum).FanNum)->maxAirFlowRate;
    6699             : 
    6700      217528 :             if (FanVolFlow < state.dataWaterThermalTanks->HPWaterHeater(HPNum).HPWHAirVolFlowRate(
    6701      108764 :                                  state.dataWaterThermalTanks->HPWaterHeater(HPNum).NumofSpeed)) { // but this is the not the scaled mas flow
    6702             :                 // if ( FanVolFlow  < HPWaterHeater( HPNum ).HPWHAirVolFlowRate( HPWaterHeater( HPNum ).NumofSpeed ) ) {
    6703             : 
    6704           0 :                 ShowWarningError(state,
    6705           0 :                                  format("InitWaterThermalTank: -air flow rate = {:.7T} in fan object  is less than the MSHP system air flow rate "
    6706             :                                         "when waterheating is required({:.7T}).",
    6707             :                                         FanVolFlow,
    6708           0 :                                         state.dataWaterThermalTanks->HPWaterHeater(HPNum).HPWHAirVolFlowRate(
    6709           0 :                                             state.dataWaterThermalTanks->HPWaterHeater(HPNum).NumofSpeed)));
    6710           0 :                 ShowContinueError(state,
    6711             :                                   " The MSHP system flow rate when waterheating is required is reset to the"
    6712             :                                   " fan flow rate and the simulation continues.");
    6713           0 :                 ShowContinueError(state, format(" Occurs in {}", state.dataWaterThermalTanks->HPWaterHeater(HPNum).Name));
    6714           0 :                 state.dataWaterThermalTanks->HPWaterHeater(HPNum).HPWHAirVolFlowRate(state.dataWaterThermalTanks->HPWaterHeater(HPNum).NumofSpeed) =
    6715             :                     FanVolFlow;
    6716             :                 // Check flow rates in other speeds and ensure flow rates are not above the max flow rate
    6717           0 :                 for (int Iter = state.dataWaterThermalTanks->HPWaterHeater(HPNum).NumofSpeed - 1; Iter >= 1; --Iter) {
    6718           0 :                     if (state.dataWaterThermalTanks->HPWaterHeater(HPNum).HPWHAirVolFlowRate(Iter) >
    6719           0 :                         state.dataWaterThermalTanks->HPWaterHeater(HPNum).HPWHAirVolFlowRate(Iter + 1)) {
    6720           0 :                         ShowContinueError(state,
    6721           0 :                                           format(" The MSHP system flow rate when waterheating is required is reset to the flow rate at higher "
    6722             :                                                  "speed and the simulation continues at Speed{}.",
    6723             :                                                  Iter));
    6724           0 :                         ShowContinueError(state, format(" Occurs in {}", state.dataWaterThermalTanks->HPWaterHeater(HPNum).Name));
    6725           0 :                         state.dataWaterThermalTanks->HPWaterHeater(HPNum).HPWHAirVolFlowRate(Iter) =
    6726           0 :                             state.dataWaterThermalTanks->HPWaterHeater(HPNum).HPWHAirVolFlowRate(Iter + 1);
    6727             :                     }
    6728             :                 }
    6729             :             }
    6730             : 
    6731     1196404 :             for (int Iter = 1; Iter <= state.dataWaterThermalTanks->HPWaterHeater(HPNum).NumofSpeed; ++Iter) {
    6732     1087640 :                 state.dataWaterThermalTanks->HPWaterHeater(HPNum).MSAirSpeedRatio(Iter) =
    6733     1087640 :                     state.dataWaterThermalTanks->HPWaterHeater(HPNum).HPWHAirVolFlowRate(Iter) /
    6734     2175280 :                     state.dataWaterThermalTanks->HPWaterHeater(HPNum).HPWHAirVolFlowRate(
    6735     1087640 :                         state.dataWaterThermalTanks->HPWaterHeater(HPNum).NumofSpeed);
    6736             :             }
    6737             : 
    6738             :             // scale water flow rates
    6739      108764 :             MulSpeedFlowScale = state.dataVariableSpeedCoils->VarSpeedCoil(VSCoilID).RatedWaterVolFlowRate /
    6740      108764 :                                 state.dataVariableSpeedCoils->VarSpeedCoil(VSCoilID).MSRatedWaterVolFlowRate(
    6741      108764 :                                     state.dataVariableSpeedCoils->VarSpeedCoil(VSCoilID).NormSpedLevel);
    6742     1196404 :             for (int Iter = 1; Iter <= state.dataWaterThermalTanks->HPWaterHeater(HPNum).NumofSpeed; ++Iter) {
    6743     1087640 :                 state.dataWaterThermalTanks->HPWaterHeater(HPNum).HPWHWaterVolFlowRate(Iter) =
    6744     1087640 :                     state.dataVariableSpeedCoils->VarSpeedCoil(VSCoilID).MSRatedWaterVolFlowRate(Iter) * MulSpeedFlowScale;
    6745     1087640 :                 state.dataWaterThermalTanks->HPWaterHeater(HPNum).HPWHWaterMassFlowRate(Iter) =
    6746     1087640 :                     state.dataVariableSpeedCoils->VarSpeedCoil(VSCoilID).MSRatedWaterMassFlowRate(Iter) * MulSpeedFlowScale;
    6747     1087640 :                 state.dataWaterThermalTanks->HPWaterHeater(HPNum).MSWaterSpeedRatio(Iter) =
    6748     1087640 :                     state.dataVariableSpeedCoils->VarSpeedCoil(VSCoilID).MSRatedWaterVolFlowRate(Iter) /
    6749     2175280 :                     state.dataVariableSpeedCoils->VarSpeedCoil(VSCoilID).MSRatedWaterVolFlowRate(
    6750     1087640 :                         state.dataWaterThermalTanks->HPWaterHeater(HPNum).NumofSpeed);
    6751             :             }
    6752             : 
    6753      108764 :             Real64 rhoAir = Psychrometrics::PsyRhoAirFnPbTdbW(state, state.dataEnvrn->OutBaroPress, HPInletDryBulbTemp, HPInletHumRat);
    6754             : 
    6755     1196404 :             for (int Iter = 1; Iter <= state.dataWaterThermalTanks->HPWaterHeater(HPNum).NumofSpeed; ++Iter) {
    6756     1087640 :                 state.dataWaterThermalTanks->HPWaterHeater(HPNum).HPWHAirMassFlowRate(Iter) =
    6757     1087640 :                     state.dataWaterThermalTanks->HPWaterHeater(HPNum).HPWHAirVolFlowRate(Iter) * rhoAir;
    6758             :             }
    6759             : 
    6760             :             //   set the max mass flow rate for outdoor fans
    6761      108764 :             state.dataLoopNodes->Node(state.dataWaterThermalTanks->HPWaterHeater(HPNum).FanOutletNode).MassFlowRateMax =
    6762      108764 :                 state.dataWaterThermalTanks->HPWaterHeater(HPNum).HPWHAirMassFlowRate(state.dataWaterThermalTanks->HPWaterHeater(HPNum).NumofSpeed);
    6763             :         }
    6764             : 
    6765             :     } //  IF(WaterThermalTank(WaterThermalTankNum)%HeatPumpNum .GT. 0)THEN
    6766             : 
    6767             :     // calling CalcStandardRatings early bypasses fan sizing since DataSizing::DataNonZoneNonAirloopValue has not been set yet
    6768     6284636 :     if (!this->AlreadyRated) {
    6769         293 :         if (this->IsChilledWaterTank) {
    6770           6 :             this->AlreadyRated = true;
    6771             :         } else {
    6772         391 :             if (!state.dataGlobal->AnyPlantInModel || state.dataPlnt->PlantFirstSizesOkayToReport || this->MaxCapacity > 0.0 ||
    6773         104 :                 this->HeatPumpNum > 0) {
    6774         185 :                 this->CalcStandardRatings(state);
    6775             :             }
    6776             :         }
    6777             :     }
    6778     6284636 : }
    6779             : 
    6780     6523006 : void WaterThermalTankData::CalcWaterThermalTankMixed(EnergyPlusData &state) // Water Heater being simulated
    6781             : {
    6782             : 
    6783             :     // SUBROUTINE INFORMATION:
    6784             :     //       AUTHOR         Peter Graham Ellis
    6785             :     //       DATE WRITTEN   January 2005
    6786             :     //       MODIFIED       na
    6787             :     //       RE-ENGINEERED  na
    6788             : 
    6789             :     // PURPOSE OF THIS SUBROUTINE:
    6790             :     // Simulates a well-mixed, single node water heater tank.
    6791             : 
    6792             :     // METHODOLOGY EMPLOYED:
    6793             :     // This model uses analytical calculations based on the differential equation describing the tank energy
    6794             :     // balance.  The model operates in three different modes:  heating, floating, and venting.  Temperatures and
    6795             :     // energies change dynamically over the timestep.  The final reported tank temperature is the average over
    6796             :     // the timestep.  The final reported heat rates are averages based on the total energy transfer over the
    6797             :     // timestep.
    6798             : 
    6799             :     static constexpr std::string_view RoutineName("CalcWaterThermalTankMixed");
    6800             : 
    6801             :     Real64 TimeElapsed_loc =
    6802     6523006 :         state.dataGlobal->HourOfDay + state.dataGlobal->TimeStep * state.dataGlobal->TimeStepZone + state.dataHVACGlobal->SysTimeElapsed;
    6803             : 
    6804     6523006 :     if (this->TimeElapsed != TimeElapsed_loc) {
    6805             :         // The simulation has advanced to the next system DataGlobals::TimeStep.  Save conditions from the end of the previous system
    6806             :         // DataGlobals::TimeStep for use as the initial conditions of each iteration that does not advance the system DataGlobals::TimeStep.
    6807      589816 :         this->SavedTankTemp = this->TankTemp;
    6808      589816 :         this->SavedMode = this->Mode;
    6809             : 
    6810             :         // Save outlet temperatures for demand-side flow control
    6811      589816 :         this->SavedUseOutletTemp = this->UseOutletTemp;
    6812      589816 :         this->SavedSourceOutletTemp = this->SourceOutletTemp;
    6813             : 
    6814      589816 :         this->TimeElapsed = TimeElapsed_loc;
    6815             :     }
    6816             : 
    6817     6523006 :     Real64 TankTemp_loc = this->SavedTankTemp;
    6818     6523006 :     TankOperatingMode Mode_loc = this->SavedMode;
    6819             : 
    6820     6523006 :     Real64 Qmaxcap = this->MaxCapacity;
    6821     6523006 :     Real64 Qmincap = this->MinCapacity;
    6822     6523006 :     Real64 Qoffcycfuel = this->OffCycParaLoad;
    6823     6523006 :     Real64 Qoffcycheat = Qoffcycfuel * this->OffCycParaFracToTank;
    6824     6523006 :     Real64 Qoncycfuel = this->OnCycParaLoad;
    6825     6523006 :     Real64 Qoncycheat = Qoncycfuel * this->OnCycParaFracToTank;
    6826             : 
    6827     6523006 :     Real64 SetPointTemp_loc = this->SetPointTemp;
    6828     6523006 :     Real64 DeadBandTemp = this->getDeadBandTemp();
    6829     6523006 :     Real64 MaxTemp = this->TankTempLimit;
    6830     6523006 :     Real64 AmbientTemp_loc = this->AmbientTemp;
    6831             : 
    6832     6523006 :     Real64 UseInletTemp_loc = this->UseInletTemp;
    6833     6523006 :     Real64 UseMassFlowRate_loc = this->UseMassFlowRate * this->UseEffectiveness;
    6834     6523006 :     Real64 SourceInletTemp_loc = this->SourceInletTemp;
    6835     6523006 :     Real64 SourceMassFlowRate_loc = this->SourceMassFlowRate * this->SourceEffectiveness;
    6836             : 
    6837             :     Real64 rho;
    6838     6523006 :     if (this->UseSidePlantLoc.loopNum > 0) {
    6839     5944106 :         rho = FluidProperties::GetDensityGlycol(state,
    6840     5944106 :                                                 state.dataPlnt->PlantLoop(this->UseSidePlantLoc.loopNum).FluidName,
    6841             :                                                 TankTemp_loc,
    6842     5944106 :                                                 state.dataPlnt->PlantLoop(this->UseSidePlantLoc.loopNum).FluidIndex,
    6843             :                                                 RoutineName);
    6844             :     } else {
    6845      578900 :         rho = FluidProperties::GetDensityGlycol(state, fluidNameWater, TankTemp_loc, this->waterIndex, RoutineName);
    6846             :     }
    6847             : 
    6848     6523006 :     Real64 TankMass = rho * this->Volume;
    6849             : 
    6850             :     Real64 Cp;
    6851     6523006 :     if (this->UseSidePlantLoc.loopNum > 0) {
    6852     5944106 :         Cp = FluidProperties::GetSpecificHeatGlycol(state,
    6853     5944106 :                                                     state.dataPlnt->PlantLoop(this->UseSidePlantLoc.loopNum).FluidName,
    6854             :                                                     TankTemp_loc,
    6855     5944106 :                                                     state.dataPlnt->PlantLoop(this->UseSidePlantLoc.loopNum).FluidIndex,
    6856             :                                                     RoutineName);
    6857             :     } else {
    6858      578900 :         Cp = FluidProperties::GetSpecificHeatGlycol(state, fluidNameWater, TankTemp_loc, this->waterIndex, RoutineName);
    6859             :     }
    6860             : 
    6861     6523006 :     Real64 SecInTimeStep = state.dataHVACGlobal->TimeStepSysSec;
    6862     6523006 :     Real64 TimeRemaining = SecInTimeStep;
    6863     6523006 :     int CycleOnCount_loc = 0;
    6864     6523006 :     int MaxCycles = SecInTimeStep;
    6865     6523006 :     Real64 Runtime = 0.0;
    6866     6523006 :     bool SetPointRecovered = false;
    6867             : 
    6868     6523006 :     Real64 Tsum = 0.0;
    6869     6523006 :     Real64 Eloss = 0.0;
    6870     6523006 :     Real64 Elosszone = 0.0;
    6871     6523006 :     Real64 Euse = 0.0;
    6872     6523006 :     Real64 Esource = 0.0;
    6873     6523006 :     Real64 Eheater = 0.0;
    6874     6523006 :     Real64 Event = 0.0;
    6875     6523006 :     Real64 Eneeded = 0.0;
    6876     6523006 :     Real64 Eunmet = 0.0;
    6877     6523006 :     Real64 Efuel = 0.0;
    6878     6523006 :     Real64 Eoncycfuel = 0.0;
    6879     6523006 :     Real64 Eoffcycfuel = 0.0;
    6880     6523006 :     Real64 PLR = 0.0;
    6881     6523006 :     Real64 PLRsum = 0.0;
    6882             : 
    6883     6523006 :     Real64 Qheat = 0.0;
    6884     6523006 :     Real64 Qheater = 0.0;
    6885     6523006 :     Real64 Qvent = 0.0;
    6886     6523006 :     Real64 Qneeded = 0.0;
    6887     6523006 :     Real64 Qunmet = 0.0;
    6888     6523006 :     Real64 Qfuel = 0.0;
    6889             : 
    6890             :     // Calculate the heating rate from the heat pump.
    6891     6523006 :     Real64 HPWHCondenserDeltaT = 0.0;
    6892             : 
    6893     6523006 :     if (this->HeatPumpNum > 0) {
    6894      895707 :         HeatPumpWaterHeaterData const &HeatPump = state.dataWaterThermalTanks->HPWaterHeater(this->HeatPumpNum);
    6895      895707 :         DataLoopNode::NodeData const &HPWHCondWaterInletNode = state.dataLoopNodes->Node(HeatPump.CondWaterInletNode);
    6896      895707 :         DataLoopNode::NodeData const &HPWHCondWaterOutletNode = state.dataLoopNodes->Node(HeatPump.CondWaterOutletNode);
    6897      895707 :         HPWHCondenserDeltaT = HPWHCondWaterOutletNode.Temp - HPWHCondWaterInletNode.Temp;
    6898             :     }
    6899     6523006 :     assert(HPWHCondenserDeltaT >= 0);
    6900             : 
    6901             :     Real64 Qheatpump;
    6902             :     Real64 Qsource;
    6903     6523006 :     EnergyPlus::WaterThermalTanks::WaterThermalTankData::CalcMixedTankSourceSideHeatTransferRate(
    6904             :         HPWHCondenserDeltaT, SourceInletTemp_loc, Cp, SetPointTemp_loc, SourceMassFlowRate_loc, Qheatpump, Qsource);
    6905             : 
    6906             :     // Calculate steady-state use heat rate.
    6907     6523006 :     Real64 Quse = UseMassFlowRate_loc * Cp * (UseInletTemp_loc - SetPointTemp_loc);
    6908     6523006 :     Real64 Qloss = 0.0, PLF = 0.0;
    6909             : 
    6910    24276701 :     while (TimeRemaining > 0.0) {
    6911             : 
    6912    17753695 :         Real64 TimeNeeded = 0.0;
    6913             : 
    6914    17753695 :         Real64 NewTankTemp = TankTemp_loc;
    6915    17753695 :         Real64 LossCoeff_loc = 0.0;
    6916    17753695 :         Real64 LossFracToZone = 0.0;
    6917             : 
    6918    17753695 :         switch (Mode_loc) {
    6919             : 
    6920     7892872 :         case TankOperatingMode::Heating: // Heater is on
    6921             : 
    6922             :             // Calculate heat rate needed to maintain the setpoint at steady-state conditions
    6923     7892872 :             LossCoeff_loc = this->OnCycLossCoeff;
    6924     7892872 :             LossFracToZone = this->OnCycLossFracToZone;
    6925     7892872 :             Qloss = LossCoeff_loc * (AmbientTemp_loc - SetPointTemp_loc);
    6926     7892872 :             Qneeded = -Quse - Qsource - Qloss - Qoncycheat;
    6927             : 
    6928     7892872 :             if (TankTemp_loc > SetPointTemp_loc) {
    6929             :                 // Heater is not needed after all, possibly due to step change in scheduled SetPointTemp
    6930             : 
    6931           8 :                 Qheater = 0.0;
    6932           8 :                 Qunmet = 0.0;
    6933           8 :                 Mode_loc = TankOperatingMode::Floating;
    6934           8 :                 continue;
    6935             : 
    6936     7892864 :             } else if (TankTemp_loc < SetPointTemp_loc) {
    6937             :                 // Attempt to recover to the setpoint as quickly as possible by using maximum heater capacity
    6938             : 
    6939             :                 // Qneeded is calculated above
    6940             :                 // Qneeded does not account for the extra energy needed to recover to the setpoint
    6941     4181777 :                 Qheater = Qmaxcap;
    6942     4181777 :                 Qunmet = max(Qneeded - Qheater, 0.0);
    6943     4181777 :                 Qheat = Qoncycheat + Qheater + Qheatpump;
    6944             : 
    6945             :                 // Calculate time needed to recover to the setpoint at maximum heater capacity
    6946     4181777 :                 TimeNeeded = EnergyPlus::WaterThermalTanks::WaterThermalTankData::CalcTimeNeeded(TankTemp_loc,
    6947             :                                                                                                  SetPointTemp_loc,
    6948             :                                                                                                  AmbientTemp_loc,
    6949             :                                                                                                  UseInletTemp_loc,
    6950             :                                                                                                  SourceInletTemp_loc,
    6951             :                                                                                                  TankMass,
    6952             :                                                                                                  Cp,
    6953             :                                                                                                  UseMassFlowRate_loc,
    6954             :                                                                                                  SourceMassFlowRate_loc,
    6955             :                                                                                                  LossCoeff_loc,
    6956             :                                                                                                  Qheat);
    6957             : 
    6958     4181777 :                 if (TimeNeeded > TimeRemaining) {
    6959             :                     // Heater is at maximum capacity and heats for all of the remaining time
    6960             :                     // Setpoint temperature WILL NOT be recovered
    6961             : 
    6962      522572 :                     TimeNeeded = TimeRemaining;
    6963             : 
    6964      522572 :                     NewTankTemp = EnergyPlus::WaterThermalTanks::WaterThermalTankData::CalcTankTemp(TankTemp_loc,
    6965             :                                                                                                     AmbientTemp_loc,
    6966             :                                                                                                     UseInletTemp_loc,
    6967             :                                                                                                     SourceInletTemp_loc,
    6968             :                                                                                                     TankMass,
    6969             :                                                                                                     Cp,
    6970             :                                                                                                     UseMassFlowRate_loc,
    6971             :                                                                                                     SourceMassFlowRate_loc,
    6972             :                                                                                                     LossCoeff_loc,
    6973             :                                                                                                     Qheat,
    6974             :                                                                                                     TimeNeeded);
    6975             : 
    6976             :                 } else { // TimeNeeded <= TimeRemaining
    6977             :                     // Heater is at maximum capacity but will not heat for all of the remaining time (at maximum anyway)
    6978             :                     // Setpoint temperature WILL be recovered
    6979             : 
    6980     3659205 :                     NewTankTemp = SetPointTemp_loc;
    6981             : 
    6982     3659205 :                     SetPointRecovered = true;
    6983             : 
    6984             :                 } // TimeNeeded > TimeRemaining
    6985             : 
    6986             :             } else { // TankTemp == SetPointTemp
    6987             :                 // Attempt to maintain the setpoint by using the needed heater capacity (modulating, if allowed)
    6988             : 
    6989     3711087 :                 if (Qneeded <= 0.0) {
    6990             :                     // Heater is not needed
    6991             : 
    6992        9256 :                     Qneeded = 0.0;
    6993        9256 :                     Qheater = 0.0;
    6994        9256 :                     Qunmet = 0.0;
    6995        9256 :                     Mode_loc = TankOperatingMode::Floating;
    6996        9256 :                     continue;
    6997             : 
    6998     3701831 :                 } else if (Qneeded < Qmincap) {
    6999             :                     // Heater is required at less than the minimum capacity
    7000             :                     // If cycling, Qmincap = Qmaxcap.  Once the setpoint is reached, heater will almost always be shut off here
    7001             : 
    7002     3649286 :                     if (this->ControlType == HeaterControlMode::Cycle) {
    7003             :                         // Control will cycle on and off based on DeadBandTemp
    7004     3649286 :                         Qheater = 0.0;
    7005     3649286 :                         Qunmet = 0.0;
    7006     3649286 :                         Mode_loc = TankOperatingMode::Floating;
    7007     3649286 :                         continue;
    7008             : 
    7009           0 :                     } else if (this->ControlType == HeaterControlMode::Modulate) {
    7010             :                         // Control will cycle on and off based on DeadBandTemp until Qneeded > Qmincap again
    7011           0 :                         Qheater = 0.0;
    7012           0 :                         Qunmet = Qneeded;
    7013           0 :                         Mode_loc = TankOperatingMode::Floating;
    7014           0 :                         continue;
    7015             : 
    7016             :                         // CASE (ControlTypeModulateWithOverheat)  ! Not yet implemented
    7017             :                         // Calculate time to reach steady-state temp; check for venting at MaxTemp limit
    7018             :                         // Qheater = Qmincap
    7019             : 
    7020             :                         // CASE (ControlTypeModulateWithUnderheat)  ! Not yet implemented
    7021             :                         // Heater must not come back on until Qneeded >= Qmincap
    7022             :                         // Mode = modfloatMode
    7023             :                     }
    7024             : 
    7025       52545 :                 } else if (Qneeded <= Qmaxcap) {
    7026             :                     // Heater can exactly meet the needed heat rate (usually by modulating) and heats for all of the remaining time
    7027             :                     // Setpoint temperature WILL be maintained
    7028             : 
    7029       52503 :                     TimeNeeded = TimeRemaining;
    7030             : 
    7031       52503 :                     Qheater = Qneeded;
    7032       52503 :                     Qunmet = 0.0;
    7033             : 
    7034       52503 :                     NewTankTemp = SetPointTemp_loc;
    7035             : 
    7036             :                 } else { // Qneeded > Qmaxcap
    7037             :                     // Heater is at maximum capacity and heats for all of the remaining time
    7038             :                     // Setpoint temperature WILL NOT be maintained
    7039             : 
    7040          42 :                     TimeNeeded = TimeRemaining;
    7041             : 
    7042          42 :                     Qheater = Qmaxcap;
    7043          42 :                     Qunmet = Qneeded - Qheater;
    7044          42 :                     Qheat = Qoncycheat + Qheater + Qheatpump;
    7045             : 
    7046          42 :                     NewTankTemp = EnergyPlus::WaterThermalTanks::WaterThermalTankData::CalcTankTemp(TankTemp_loc,
    7047             :                                                                                                     AmbientTemp_loc,
    7048             :                                                                                                     UseInletTemp_loc,
    7049             :                                                                                                     SourceInletTemp_loc,
    7050             :                                                                                                     TankMass,
    7051             :                                                                                                     Cp,
    7052             :                                                                                                     UseMassFlowRate_loc,
    7053             :                                                                                                     SourceMassFlowRate_loc,
    7054             :                                                                                                     LossCoeff_loc,
    7055             :                                                                                                     Qheat,
    7056             :                                                                                                     TimeNeeded);
    7057             : 
    7058             :                 } // Qneeded > Qmaxcap
    7059             : 
    7060             :             } // TankTemp > SetPointTemp
    7061             : 
    7062             :             // Update summed values
    7063     4234322 :             Eneeded += Qneeded * TimeNeeded;
    7064     4234322 :             Eheater += Qheater * TimeNeeded;
    7065     4234322 :             Eunmet += Qunmet * TimeNeeded;
    7066     4234322 :             Eoncycfuel += Qoncycfuel * TimeNeeded;
    7067             : 
    7068     4234322 :             if (Qmaxcap > 0.0) PLR = Qheater / Qmaxcap;
    7069     4234322 :             PLF = this->PartLoadFactor(state, PLR);
    7070     4234322 :             Efuel += Qheater * TimeNeeded / (PLF * this->Efficiency);
    7071             : 
    7072     4234322 :             Runtime += TimeNeeded;
    7073     4234322 :             PLRsum += PLR * TimeNeeded;
    7074             : 
    7075     4234322 :             if (!this->FirstRecoveryDone) {
    7076      107362 :                 this->FirstRecoveryFuel += Efuel + Eoffcycfuel + Eoncycfuel;
    7077      107362 :                 if (SetPointRecovered) this->FirstRecoveryDone = true;
    7078             :             }
    7079     4234322 :             break;
    7080             : 
    7081     9734343 :         case TankOperatingMode::Floating:
    7082             :         case TankOperatingMode::Cooling: // Heater is off
    7083             : 
    7084             :             // Calculate heat rate needed to maintain the setpoint at steady-state conditions
    7085     9734343 :             LossCoeff_loc = this->OffCycLossCoeff;
    7086     9734343 :             LossFracToZone = this->OffCycLossFracToZone;
    7087     9734343 :             Qloss = LossCoeff_loc * (AmbientTemp_loc - SetPointTemp_loc);
    7088     9734343 :             Qneeded = -Quse - Qsource - Qloss - Qoffcycheat;
    7089             : 
    7090             :             // This section really needs to work differently depending on ControlType
    7091             :             // CYCLE will look at TankTemp, MODULATE will look at Qneeded
    7092             : 
    7093     9734343 :             if ((TankTemp_loc < DeadBandTemp) && (!this->IsChilledWaterTank)) {
    7094             :                 // Tank temperature is already below the minimum, possibly due to step change in scheduled SetPointTemp
    7095             : 
    7096         445 :                 Mode_loc = TankOperatingMode::Heating;
    7097         445 :                 ++CycleOnCount_loc;
    7098         445 :                 continue;
    7099             : 
    7100     9733898 :             } else if ((TankTemp_loc >= DeadBandTemp) && (!this->IsChilledWaterTank)) {
    7101             : 
    7102     9336118 :                 Qheat = Qoffcycheat + Qheatpump;
    7103             : 
    7104             :                 // Calculate time needed for tank temperature to fall to minimum (setpoint - deadband)
    7105     9336118 :                 TimeNeeded = EnergyPlus::WaterThermalTanks::WaterThermalTankData::CalcTimeNeeded(TankTemp_loc,
    7106             :                                                                                                  DeadBandTemp,
    7107             :                                                                                                  AmbientTemp_loc,
    7108             :                                                                                                  UseInletTemp_loc,
    7109             :                                                                                                  SourceInletTemp_loc,
    7110             :                                                                                                  TankMass,
    7111             :                                                                                                  Cp,
    7112             :                                                                                                  UseMassFlowRate_loc,
    7113             :                                                                                                  SourceMassFlowRate_loc,
    7114             :                                                                                                  LossCoeff_loc,
    7115             :                                                                                                  Qheat);
    7116             : 
    7117     9336118 :                 if (TimeNeeded <= TimeRemaining) {
    7118             :                     // Heating will be needed in this DataGlobals::TimeStep
    7119             : 
    7120     3852515 :                     NewTankTemp = DeadBandTemp;
    7121     3852515 :                     Mode_loc = TankOperatingMode::Heating;
    7122     3852515 :                     ++CycleOnCount_loc;
    7123             : 
    7124             :                 } else { // TimeNeeded > TimeRemaining
    7125             :                     // Heating will not be needed for all of the remaining time
    7126             : 
    7127     5483603 :                     NewTankTemp = EnergyPlus::WaterThermalTanks::WaterThermalTankData::CalcTankTemp(TankTemp_loc,
    7128             :                                                                                                     AmbientTemp_loc,
    7129             :                                                                                                     UseInletTemp_loc,
    7130             :                                                                                                     SourceInletTemp_loc,
    7131             :                                                                                                     TankMass,
    7132             :                                                                                                     Cp,
    7133             :                                                                                                     UseMassFlowRate_loc,
    7134             :                                                                                                     SourceMassFlowRate_loc,
    7135             :                                                                                                     LossCoeff_loc,
    7136             :                                                                                                     Qheat,
    7137             :                                                                                                     TimeRemaining);
    7138             : 
    7139     5483603 :                     if ((NewTankTemp < MaxTemp) || (this->IsChilledWaterTank)) {
    7140             :                         // Neither heating nor venting is needed for all of the remaining time
    7141             : 
    7142     5464756 :                         TimeNeeded = TimeRemaining;
    7143             : 
    7144             :                     } else { // NewTankTemp >= MaxTemp
    7145             :                         // Venting will be needed in this DataGlobals::TimeStep
    7146             : 
    7147             :                         // Calculate time needed for tank temperature to rise to the maximum
    7148       18847 :                         TimeNeeded = CalcTimeNeeded(TankTemp_loc,
    7149             :                                                     MaxTemp,
    7150             :                                                     AmbientTemp_loc,
    7151             :                                                     UseInletTemp_loc,
    7152             :                                                     SourceInletTemp_loc,
    7153             :                                                     TankMass,
    7154             :                                                     Cp,
    7155             :                                                     UseMassFlowRate_loc,
    7156             :                                                     SourceMassFlowRate_loc,
    7157             :                                                     LossCoeff_loc,
    7158             :                                                     Qheat);
    7159             : 
    7160             :                         // if limit NewTankTemp >= MaxTemp
    7161       18847 :                         if (TankTemp_loc >= MaxTemp) {
    7162           0 :                             TimeNeeded = TimeRemaining;
    7163             :                         }
    7164       18847 :                         NewTankTemp = MaxTemp;
    7165       18847 :                         Mode_loc = TankOperatingMode::Venting;
    7166             : 
    7167             :                     } // NewTankTemp >= MaxTemp
    7168             : 
    7169             :                 } // TimeNeeded <= TimeRemaining
    7170             : 
    7171      397780 :             } else if ((TankTemp_loc > DeadBandTemp) && (this->IsChilledWaterTank)) {
    7172       78670 :                 Mode_loc = TankOperatingMode::Cooling;
    7173       78670 :                 Qheat = Qheatpump;
    7174             : 
    7175       78670 :                 NewTankTemp = EnergyPlus::WaterThermalTanks::WaterThermalTankData::CalcTankTemp(TankTemp_loc,
    7176             :                                                                                                 AmbientTemp_loc,
    7177             :                                                                                                 UseInletTemp_loc,
    7178             :                                                                                                 SourceInletTemp_loc,
    7179             :                                                                                                 TankMass,
    7180             :                                                                                                 Cp,
    7181             :                                                                                                 UseMassFlowRate_loc,
    7182             :                                                                                                 SourceMassFlowRate_loc,
    7183             :                                                                                                 LossCoeff_loc,
    7184             :                                                                                                 Qheat,
    7185             :                                                                                                 TimeRemaining);
    7186       78670 :                 TimeNeeded = TimeRemaining;
    7187      319110 :             } else if ((TankTemp_loc <= DeadBandTemp) && (this->IsChilledWaterTank)) {
    7188             : 
    7189      319110 :                 if (TankTemp_loc < SetPointTemp_loc) Mode_loc = TankOperatingMode::Floating;
    7190             : 
    7191      319110 :                 Qheat = Qheatpump;
    7192             : 
    7193      319110 :                 NewTankTemp = EnergyPlus::WaterThermalTanks::WaterThermalTankData::CalcTankTemp(TankTemp_loc,
    7194             :                                                                                                 AmbientTemp_loc,
    7195             :                                                                                                 UseInletTemp_loc,
    7196             :                                                                                                 SourceInletTemp_loc,
    7197             :                                                                                                 TankMass,
    7198             :                                                                                                 Cp,
    7199             :                                                                                                 UseMassFlowRate_loc,
    7200             :                                                                                                 SourceMassFlowRate_loc,
    7201             :                                                                                                 LossCoeff_loc,
    7202             :                                                                                                 Qheat,
    7203             :                                                                                                 TimeRemaining);
    7204      319110 :                 TimeNeeded = TimeRemaining;
    7205             :             } // TankTemp vs DeadBandTemp for heaters and chilled water tanks
    7206             : 
    7207             :             // Update summed values
    7208     9733898 :             Eneeded += Qneeded * TimeNeeded;
    7209     9733898 :             Eunmet += Qunmet * TimeNeeded; // Qunmet may be propagated thru from the previous iteration
    7210     9733898 :             Eoffcycfuel += Qoffcycfuel * TimeNeeded;
    7211     9733898 :             break;
    7212             : 
    7213      126480 :         case TankOperatingMode::Venting: // Excess heat is vented
    7214             : 
    7215      126480 :             LossCoeff_loc = this->OffCycLossCoeff;
    7216      126480 :             LossFracToZone = this->OffCycLossFracToZone;
    7217      126480 :             Qheat = Qoffcycheat + Qheatpump;
    7218             : 
    7219      126480 :             NewTankTemp = EnergyPlus::WaterThermalTanks::WaterThermalTankData::CalcTankTemp(TankTemp_loc,
    7220             :                                                                                             AmbientTemp_loc,
    7221             :                                                                                             UseInletTemp_loc,
    7222             :                                                                                             SourceInletTemp_loc,
    7223             :                                                                                             TankMass,
    7224             :                                                                                             Cp,
    7225             :                                                                                             UseMassFlowRate_loc,
    7226             :                                                                                             SourceMassFlowRate_loc,
    7227             :                                                                                             LossCoeff_loc,
    7228             :                                                                                             Qheat,
    7229             :                                                                                             TimeRemaining);
    7230             : 
    7231      126480 :             if (NewTankTemp < MaxTemp) {
    7232             :                 // Venting is no longer needed because conditions have changed
    7233             : 
    7234       41127 :                 Mode_loc = TankOperatingMode::Floating;
    7235       41127 :                 continue;
    7236             : 
    7237             :             } else { // NewTankTemp >= MaxTemp
    7238             : 
    7239       85353 :                 TimeNeeded = TimeRemaining;
    7240             : 
    7241             :                 // Calculate the steady-state venting rate needed to maintain the tank at maximum temperature
    7242       85353 :                 Real64 Qloss = LossCoeff_loc * (AmbientTemp_loc - MaxTemp);
    7243       85353 :                 Quse = UseMassFlowRate_loc * Cp * (UseInletTemp_loc - MaxTemp);
    7244       85353 :                 Qsource = SourceMassFlowRate_loc * Cp * (SourceInletTemp_loc - MaxTemp);
    7245       85353 :                 Qvent = -Quse - Qsource - Qloss - Qoffcycheat;
    7246             : 
    7247       85353 :                 NewTankTemp = MaxTemp;
    7248             : 
    7249             :             } // NewTankTemp < MaxTemp
    7250             : 
    7251             :             // Update summed values
    7252       85353 :             Event += Qvent * TimeNeeded;
    7253       85353 :             Eoffcycfuel += Qoffcycfuel * TimeNeeded;
    7254       85353 :             break;
    7255           0 :         default:
    7256           0 :             assert(false); // should never get here
    7257             :         }
    7258             : 
    7259    14053573 :         Real64 deltaTsum = EnergyPlus::WaterThermalTanks::WaterThermalTankData::CalcTempIntegral(TankTemp_loc,
    7260             :                                                                                                  NewTankTemp,
    7261             :                                                                                                  AmbientTemp_loc,
    7262             :                                                                                                  UseInletTemp_loc,
    7263             :                                                                                                  SourceInletTemp_loc,
    7264             :                                                                                                  TankMass,
    7265             :                                                                                                  Cp,
    7266             :                                                                                                  UseMassFlowRate_loc,
    7267             :                                                                                                  SourceMassFlowRate_loc,
    7268             :                                                                                                  LossCoeff_loc,
    7269             :                                                                                                  Qheat,
    7270             :                                                                                                  TimeNeeded);
    7271             : 
    7272             :         // Update summed values
    7273    14053573 :         Tsum += deltaTsum;
    7274    14053573 :         Eloss += LossCoeff_loc * (AmbientTemp_loc * TimeNeeded - deltaTsum);
    7275    14053573 :         Elosszone += LossFracToZone * LossCoeff_loc * (AmbientTemp_loc * TimeNeeded - deltaTsum);
    7276    14053573 :         Euse += UseMassFlowRate_loc * Cp * (UseInletTemp_loc * TimeNeeded - deltaTsum);
    7277    14053573 :         if (this->HeatPumpNum > 0) {
    7278     1004358 :             Esource += Qheatpump * TimeNeeded;
    7279             :         } else {
    7280    13049215 :             Esource += SourceMassFlowRate_loc * Cp * (SourceInletTemp_loc * TimeNeeded - deltaTsum);
    7281             :         }
    7282             : 
    7283    14053573 :         TankTemp_loc = NewTankTemp; // Update tank temperature
    7284             : 
    7285    14053573 :         TimeRemaining -= TimeNeeded;
    7286             : 
    7287    14053573 :         if (CycleOnCount_loc > MaxCycles) {
    7288             : 
    7289           0 :             if (!state.dataGlobal->WarmupFlag) {
    7290           0 :                 if (this->MaxCycleErrorIndex == 0) {
    7291           0 :                     ShowWarningError(state, format("WaterHeater:Mixed = {}:  Heater is cycling on and off more than once per second.", this->Name));
    7292           0 :                     ShowContinueError(state, "Try increasing Deadband Temperature Difference or Tank Volume");
    7293           0 :                     ShowContinueErrorTimeStamp(state, "");
    7294             :                 }
    7295           0 :                 ShowRecurringWarningErrorAtEnd(state,
    7296           0 :                                                "WaterHeater:Mixed = " + this->Name + " Heater is cycling on and off more than once per second:",
    7297           0 :                                                this->MaxCycleErrorIndex);
    7298             :             }
    7299             : 
    7300           0 :             break;
    7301             : 
    7302             :         } // CycleOnCount > MaxCycles
    7303             : 
    7304             :     } // TimeRemaining > 0.0
    7305             : 
    7306             :     // 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
    7307     6523006 :     Real64 TankTempAvg_loc = Tsum / SecInTimeStep;
    7308     6523006 :     Qloss = Eloss / SecInTimeStep;
    7309     6523006 :     Real64 Qlosszone = Elosszone / SecInTimeStep;
    7310     6523006 :     Quse = Euse / SecInTimeStep;
    7311     6523006 :     Qsource = Esource / SecInTimeStep;
    7312     6523006 :     Qheater = Eheater / SecInTimeStep;
    7313     6523006 :     Qoffcycfuel = Eoffcycfuel / SecInTimeStep;
    7314     6523006 :     Qoffcycheat = Qoffcycfuel * this->OffCycParaFracToTank;
    7315     6523006 :     Qoncycfuel = Eoncycfuel / SecInTimeStep;
    7316     6523006 :     Qoncycheat = Qoncycfuel * this->OnCycParaFracToTank;
    7317     6523006 :     Qvent = Event / SecInTimeStep;
    7318     6523006 :     Qneeded = Eneeded / SecInTimeStep;
    7319     6523006 :     Qunmet = Eunmet / SecInTimeStep;
    7320     6523006 :     Real64 RTF = Runtime / SecInTimeStep;
    7321     6523006 :     PLR = PLRsum / SecInTimeStep;
    7322             : 
    7323     6523006 :     if (this->ControlType == HeaterControlMode::Cycle) {
    7324             :         // Recalculate Part Load Factor and fuel energy based on Runtime Fraction, instead of Part Load Ratio
    7325     6469218 :         PLF = this->PartLoadFactor(state, RTF);
    7326     6469218 :         Efuel = Eheater / (PLF * this->Efficiency);
    7327             :     }
    7328             : 
    7329     6523006 :     Qfuel = Efuel / SecInTimeStep;
    7330             : 
    7331     6523006 :     this->Mode = Mode_loc;               // Operating mode for carry-over to next DataGlobals::TimeStep
    7332     6523006 :     this->TankTemp = TankTemp_loc;       // Final tank temperature for carry-over to next DataGlobals::TimeStep
    7333     6523006 :     this->TankTempAvg = TankTempAvg_loc; // Average tank temperature over the DataGlobals::TimeStep for reporting
    7334             : 
    7335     6523006 :     if (!state.dataGlobal->WarmupFlag) {
    7336             :         // Warn for potential freezing when avg of final temp over all nodes is below 2°C (nearing 0°C)
    7337      872188 :         if (this->TankTemp < 2) {
    7338           0 :             if (this->FreezingErrorIndex == 0) {
    7339           0 :                 ShowWarningError(state,
    7340           0 :                                  format("{}: {} = '{}':  Temperature of tank < 2C indicates of possibility of freeze. Tank Temperature = {:.2R} C.",
    7341             :                                         RoutineName,
    7342           0 :                                         this->Type,
    7343           0 :                                         this->Name,
    7344           0 :                                         this->TankTemp));
    7345           0 :                 ShowContinueErrorTimeStamp(state, "");
    7346             :             }
    7347           0 :             ShowRecurringWarningErrorAtEnd(state,
    7348           0 :                                            this->Type + " = '" + this->Name + "':  Temperature of tank < 2C indicates of possibility of freeze",
    7349           0 :                                            this->FreezingErrorIndex,
    7350           0 :                                            this->TankTemp, // Report Max
    7351           0 :                                            this->TankTemp, // Report Min
    7352             :                                            _,              // Don't report Sum
    7353             :                                            "{C}",          // Max Unit
    7354             :                                            "{C}");         // Min Unit
    7355             :         }
    7356             :     }
    7357     6523006 :     this->UseOutletTemp = TankTempAvg_loc;    // Because entire tank is at same temperature
    7358     6523006 :     this->SourceOutletTemp = TankTempAvg_loc; // Because entire tank is at same temperature
    7359     6523006 :     if (this->HeatPumpNum > 0) {
    7360      895707 :         this->SourceInletTemp =
    7361      895707 :             TankTempAvg_loc + HPWHCondenserDeltaT; // Update the source inlet temperature to the average over the DataGlobals::TimeStep
    7362             :     }
    7363             : 
    7364     6523006 :     this->LossRate = Qloss;
    7365     6523006 :     this->UseRate = Quse;
    7366     6523006 :     this->SourceRate = Qsource;
    7367     6523006 :     this->OffCycParaRateToTank = Qoffcycheat;
    7368     6523006 :     this->OnCycParaRateToTank = Qoncycheat;
    7369     6523006 :     this->TotalDemandRate = -Quse - Qsource - Qloss - Qoffcycheat - Qoncycheat;
    7370     6523006 :     this->HeaterRate = Qheater;
    7371     6523006 :     this->UnmetRate = Qunmet;
    7372     6523006 :     this->VentRate = Qvent;
    7373     6523006 :     this->NetHeatTransferRate = Quse + Qsource + Qloss + Qoffcycheat + Qoncycheat + Qheater + Qvent;
    7374             : 
    7375     6523006 :     this->CycleOnCount = CycleOnCount_loc;
    7376     6523006 :     this->RuntimeFraction = RTF;
    7377     6523006 :     this->PartLoadRatio = PLR;
    7378             : 
    7379     6523006 :     this->FuelRate = Qfuel;
    7380     6523006 :     this->OffCycParaFuelRate = Qoffcycfuel;
    7381     6523006 :     this->OnCycParaFuelRate = Qoncycfuel;
    7382             : 
    7383             :     // Add water heater skin losses and venting losses to ambient zone, if specified
    7384     6523006 :     if (this->AmbientTempZone > 0) this->AmbientZoneGain = -Qlosszone - Qvent;
    7385     6523006 : }
    7386             : 
    7387     6523006 : void WaterThermalTankData::CalcMixedTankSourceSideHeatTransferRate(
    7388             :     Real64 HPWHCondenserDeltaT, // input, The temperature difference (C) across the heat pump, zero if
    7389             :                                 // there is no heat pump or if the heat pump is off
    7390             :     Real64 SourceInletTemp,     // input, Source inlet temperature (C)
    7391             :     Real64 Cp,                  // Specific heat of fluid (J/kg deltaC)
    7392             :     Real64 SetPointTemp,        // input, Mixed tank set point temperature
    7393             :     Real64 &SourceMassFlowRate, // source mass flow rate (kg/s)
    7394             :     Real64 &Qheatpump,          // heat transfer rate from heat pump
    7395             :     Real64 &Qsource             // steady state heat transfer rate from a constant temperature source side flow
    7396             : )
    7397             : {
    7398             :     // Function Information:
    7399             :     //        Author: Noel Merket
    7400             :     //        Date Written: January 2015
    7401             :     //        Modified: na
    7402             :     //        Re-engineered: na
    7403             : 
    7404             :     // Purpose of this function:
    7405             :     // Determines if the source side heat transfer is coming from a heat pump.
    7406             :     // If so it treats the source side heat transfer as a constant heat source
    7407             :     // If it is not coming from a heat pump it treats the source side heat transfer
    7408             :     // as a constant temperature.
    7409             : 
    7410             :     // Determine if the source side heating is coming from a heat pump.
    7411     6523006 :     Qheatpump = SourceMassFlowRate * Cp * HPWHCondenserDeltaT;
    7412     6523006 :     if (Qheatpump > 0.0) {
    7413      580371 :         SourceMassFlowRate = 0.0; // Handle this heating as a constant heat source
    7414      580371 :         Qsource = Qheatpump;
    7415             :     } else {
    7416     5942635 :         Qsource = SourceMassFlowRate * Cp * (SourceInletTemp - SetPointTemp);
    7417             :     }
    7418     6523006 : }
    7419             : 
    7420    13536742 : Real64 WaterThermalTankData::CalcTimeNeeded(Real64 const Ti, // Initial tank temperature (C)
    7421             :                                             Real64 const Tf, // Final tank temperature (C)
    7422             :                                             Real64 const Ta, // Ambient environment temperature (C)
    7423             :                                             Real64 const T1, // Temperature of flow 1 (C)
    7424             :                                             Real64 const T2, // Temperature of flow 2 (C)
    7425             :                                             Real64 const m,  // Mass of tank fluid (kg)
    7426             :                                             Real64 const Cp, // Specific heat of fluid (J/kg deltaC)
    7427             :                                             Real64 const m1, // Mass flow rate 1 (kg/s)
    7428             :                                             Real64 const m2, // Mass flow rate 2 (kg/s)
    7429             :                                             Real64 const UA, // Heat loss coefficient to ambient environment (W/deltaC)
    7430             :                                             Real64 const Q   // Net heating rate for non-temp dependent sources, i.e. heater and parasitics (W)
    7431             : )
    7432             : {
    7433             : 
    7434             :     // SUBROUTINE INFORMATION:
    7435             :     //       AUTHOR         Peter Graham Ellis
    7436             :     //       DATE WRITTEN   February 2005
    7437             :     //       MODIFIED       na
    7438             :     //       RE-ENGINEERED  na
    7439             : 
    7440             :     // PURPOSE OF THIS SUBROUTINE:
    7441             :     // Calculates the time needed for the tank temperature to change from Ti to Tf given heat loss,
    7442             :     // mass flow rates and temperatures, and net heat transfer due to heater and parasitics.
    7443             : 
    7444             :     // METHODOLOGY EMPLOYED:
    7445             :     // Equations are derived by solving the differential equation governing the tank energy balance.
    7446             :     // Special cases which cause the natural logarithm to blow up are trapped and interpreted as
    7447             :     // requiring an infinite amount of time because Tf can never be reached under the given conditions.
    7448             : 
    7449             :     // Return value
    7450             :     Real64 CalcTimeNeeded;
    7451             : 
    7452             :     // SUBROUTINE PARAMETER DEFINITIONS:
    7453    13536742 :     Real64 constexpr Infinity(99999999.9); // A time interval much larger than any single DataGlobals::TimeStep (s)
    7454             : 
    7455             :     Real64 t; // Time elapsed from Ti to Tf (s)
    7456             : 
    7457    13536742 :     if (Tf == Ti) {
    7458             :         // Already at Tf; no time is needed
    7459           0 :         t = 0.0;
    7460             : 
    7461             :     } else {
    7462             :         Real64 a;        // Intermediate variable
    7463             :         Real64 b;        // Intermediate variable
    7464             :         Real64 Tm;       // Mixed temperature after an infinite amount of time has passed (C)
    7465             :         Real64 quotient; // Intermediate variable
    7466             : 
    7467    13536742 :         if (UA / Cp + m1 + m2 == 0.0) {
    7468             : 
    7469       23269 :             if (Q == 0.0) {
    7470             :                 // With no mass flow and no heat flow and Tf<>Ti, then Tf can never be reached
    7471       22396 :                 t = Infinity;
    7472             : 
    7473             :             } else {
    7474         873 :                 a = Q / (m * Cp);
    7475             : 
    7476         873 :                 t = (Tf - Ti) / a;
    7477             :             }
    7478             : 
    7479             :         } else {
    7480    13513473 :             a = (Q / Cp + UA * Ta / Cp + m1 * T1 + m2 * T2) / m;
    7481    13513473 :             b = -(UA / Cp + m1 + m2) / m;
    7482             : 
    7483             :             // Calculate the mixed temperature Tm of the tank after an infinite amount of time has passed
    7484    13513473 :             Tm = -a / b;
    7485             : 
    7486    13513473 :             if (Tm == Ti) {
    7487             :                 // Mixed temperature is the same as Ti; if Tf<>Ti, then Tf can never be reached
    7488        1538 :                 t = Infinity;
    7489             : 
    7490    13511935 :             } else if (Tm == Tf) {
    7491             :                 // Tf only approaches Tm; it can never actually get there in finite time (also avoids divide by zero error)
    7492           0 :                 t = Infinity;
    7493             : 
    7494             :             } else {
    7495    13511935 :                 quotient = (Tf - Tm) / (Ti - Tm);
    7496             : 
    7497    13511935 :                 if (quotient <= 0.0) { // Autodesk:Num Changed < to <= to elim poss floating point error in LOG call
    7498             :                     // Tm is in between Ti and Tf; Tf can never be reached
    7499      558190 :                     t = Infinity;
    7500             : 
    7501             :                 } else {
    7502    12953745 :                     t = std::log(quotient) / b;
    7503             :                 }
    7504             :             }
    7505             :         }
    7506             : 
    7507    13536742 :         if (t < 0.0) t = Infinity; // If negative time, Tf can never be reached in the future
    7508             :     }
    7509             : 
    7510    13536742 :     CalcTimeNeeded = t;
    7511             : 
    7512    13536742 :     return CalcTimeNeeded;
    7513             : }
    7514             : 
    7515     6547252 : Real64 WaterThermalTankData::CalcTankTemp(Real64 const Ti, // Initial tank temperature (C)
    7516             :                                           Real64 const Ta, // Ambient environment temperature (C)
    7517             :                                           Real64 const T1, // Temperature of flow 1 (C)
    7518             :                                           Real64 const T2, // Temperature of flow 2 (C)
    7519             :                                           Real64 const m,  // Mass of tank fluid (kg)
    7520             :                                           Real64 const Cp, // Specific heat of fluid (J/kg deltaC)
    7521             :                                           Real64 const m1, // Mass flow rate 1 (kg/s)
    7522             :                                           Real64 const m2, // Mass flow rate 2 (kg/s)
    7523             :                                           Real64 const UA, // Heat loss coefficient to ambient environment (W/deltaC)
    7524             :                                           Real64 const Q,  // Net heating rate for non-temp dependent sources, i.e. heater and parasitics (W)
    7525             :                                           Real64 const t   // Time elapsed from Ti to Tf (s)
    7526             : )
    7527             : {
    7528             : 
    7529             :     // SUBROUTINE INFORMATION:
    7530             :     //       AUTHOR         Peter Graham Ellis
    7531             :     //       DATE WRITTEN   February 2005
    7532             :     //       MODIFIED       na
    7533             :     //       RE-ENGINEERED  na
    7534             : 
    7535             :     // PURPOSE OF THIS SUBROUTINE:
    7536             :     // Calculates the final tank temperature Tf after time t has elapsed given heat loss,
    7537             :     // mass flow rates and temperatures, and net heat transfer due to heater and parasitics.
    7538             : 
    7539             :     // METHODOLOGY EMPLOYED:
    7540             :     // Equations are derived by solving the differential equation governing the tank energy balance.
    7541             : 
    7542             :     // Return value
    7543             :     Real64 CalcTankTemp;
    7544             : 
    7545             :     // Locals
    7546             :     // SUBROUTINE ARGUMENT DEFINITIONS:
    7547             : 
    7548             :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    7549             :     Real64 a;  // Intermediate variable
    7550             :     Real64 b;  // Intermediate variable
    7551             :     Real64 Tf; // Final tank temperature (C)
    7552             : 
    7553     6547252 :     if (UA / Cp + m1 + m2 == 0.0) {
    7554       23197 :         a = Q / (m * Cp);
    7555             : 
    7556       23197 :         Tf = a * t + Ti;
    7557             : 
    7558             :     } else {
    7559     6524055 :         a = (Q / Cp + UA * Ta / Cp + m1 * T1 + m2 * T2) / m;
    7560     6524055 :         b = -(UA / Cp + m1 + m2) / m;
    7561             : 
    7562     6524055 :         Tf = (a / b + Ti) * std::exp(b * t) - a / b;
    7563             :     }
    7564             : 
    7565     6547252 :     CalcTankTemp = Tf;
    7566             : 
    7567     6547252 :     return CalcTankTemp;
    7568             : }
    7569             : 
    7570    14070348 : Real64 WaterThermalTankData::CalcTempIntegral(Real64 const Ti, // Initial tank temperature (C)
    7571             :                                               Real64 const Tf, // Final tank temperature (C)
    7572             :                                               Real64 const Ta, // Ambient environment temperature (C)
    7573             :                                               Real64 const T1, // Temperature of flow 1 (C)
    7574             :                                               Real64 const T2, // Temperature of flow 2 (C)
    7575             :                                               Real64 const m,  // Mass of tank fluid (kg)
    7576             :                                               Real64 const Cp, // Specific heat of fluid (J/kg deltaC)
    7577             :                                               Real64 const m1, // Mass flow rate 1 (kg/s)
    7578             :                                               Real64 const m2, // Mass flow rate 2 (kg/s)
    7579             :                                               Real64 const UA, // Heat loss coefficient to ambient environment (W/deltaC)
    7580             :                                               Real64 const Q,  // Net heating rate for non-temp dependent sources, i.e. heater and parasitics (W)
    7581             :                                               Real64 const t   // Time elapsed from Ti to Tf (s)
    7582             : )
    7583             : {
    7584             : 
    7585             :     // SUBROUTINE INFORMATION:
    7586             :     //       AUTHOR         Peter Graham Ellis
    7587             :     //       DATE WRITTEN   February 2005
    7588             :     //       MODIFIED       na
    7589             :     //       RE-ENGINEERED  na
    7590             : 
    7591             :     // PURPOSE OF THIS SUBROUTINE:
    7592             :     // Calculates the integral of the tank temperature from Ti to Tf.  The integral is added to a sum which is
    7593             :     // later divided by the elapsed time to yield the average tank temperature over the DataGlobals::TimeStep.
    7594             : 
    7595             :     // METHODOLOGY EMPLOYED:
    7596             :     // Equations are the mathematical integrals of the governing differential equations.
    7597             : 
    7598             :     // Return value
    7599             :     Real64 CalcTempIntegral;
    7600             : 
    7601             :     // Locals
    7602             :     // SUBROUTINE ARGUMENT DEFINITIONS:
    7603             : 
    7604             :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    7605             :     Real64 a;     // Intermediate variable
    7606             :     Real64 b;     // Intermediate variable
    7607             :     Real64 dTsum; // Integral of tank temperature (C s)
    7608             : 
    7609    14070348 :     if (t == 0.0) {
    7610           0 :         dTsum = 0.0;
    7611             : 
    7612    14070348 :     } else if (Tf == Ti) { // Steady-state conditions
    7613      179424 :         dTsum = Tf * t;
    7614             : 
    7615    13890924 :     } else if (UA / Cp + m1 + m2 == 0.0) {
    7616         873 :         a = Q / (m * Cp);
    7617             : 
    7618             :         // Integral of T(t) = a * t + Ti, evaluated from 0 to t
    7619         873 :         dTsum = 0.5 * a * t * t + Ti * t;
    7620             : 
    7621             :     } else {
    7622    13890051 :         a = (Q / Cp + UA * Ta / Cp + m1 * T1 + m2 * T2) / m;
    7623    13890051 :         b = -(UA / Cp + m1 + m2) / m;
    7624             : 
    7625             :         // Integral of T(t) = (a / b + Ti) * EXP(b * t) - a / b, evaluated from 0 to t
    7626    13890051 :         dTsum = (a / b + Ti) * (std::exp(b * t) - 1.0) / b - a * t / b;
    7627             :     }
    7628             : 
    7629    14070348 :     CalcTempIntegral = dTsum;
    7630             : 
    7631    14070348 :     return CalcTempIntegral;
    7632             : }
    7633             : 
    7634    10703540 : Real64 WaterThermalTankData::PartLoadFactor(EnergyPlusData &state, Real64 const PartLoadRatio_loc)
    7635             : {
    7636             : 
    7637             :     // SUBROUTINE INFORMATION:
    7638             :     //       AUTHOR         Peter Graham Ellis
    7639             :     //       DATE WRITTEN   January 2005
    7640             :     //       MODIFIED       na
    7641             :     //       RE-ENGINEERED  na
    7642             : 
    7643             :     // PURPOSE OF THIS SUBROUTINE:
    7644             :     // Calculates the Part Load Factor (PLF) based on a curve correlated to Part Load Ratio, if Heater Control Type
    7645             :     // is MODULATE, or correlated to Runtime Fraction, if Heater Control Type is CYCLE.
    7646             : 
    7647    10703540 :     if (this->PLFCurve > 0) {
    7648        1260 :         return max(Curve::CurveValue(state, this->PLFCurve, PartLoadRatio_loc), 0.1);
    7649             :     } else {
    7650    10702280 :         return 1.0;
    7651             :     }
    7652             : }
    7653             : 
    7654     1164484 : void WaterThermalTankData::CalcWaterThermalTankStratified(EnergyPlusData &state)
    7655             : {
    7656             :     // SUBROUTINE INFORMATION:
    7657             :     //       AUTHOR         Noel Merket, originally by Peter Graham Ellis
    7658             :     //       DATE WRITTEN   January 2007
    7659             :     //       MODIFIED       Nov 2011, BAN; modified the use and source outlet temperature calculation
    7660             :     //       RE-ENGINEERED  Noel Merket, November 2018
    7661             : 
    7662             :     // PURPOSE OF THIS SUBROUTINE:
    7663             :     // Simulates a stratified, multi-node water heater tank with up to two heating elements.
    7664             : 
    7665             :     // METHODOLOGY EMPLOYED:
    7666             :     // This model uses a numerical calculation based on an analytical solution of the ODE dT/dt = a*T + b.
    7667             :     // A heat balance is calculated for each node.
    7668             :     // Temperatures and energies change dynamically over the system time step.
    7669             :     // Final node temperatures are reported as final instantaneous values as well as averages over the
    7670             :     // time step.  Heat transfer rates are averages over the time step.
    7671             : 
    7672             :     static constexpr std::string_view RoutineName("CalcWaterThermalTankStratified");
    7673     1164484 :     constexpr Real64 TemperatureConvergenceCriteria = 0.0001;
    7674     1164484 :     constexpr Real64 SubTimestepMax = 60.0 * 10.0; // seconds
    7675     1164484 :     constexpr Real64 SubTimestepMin = 10.0;        // seconds
    7676             :     Real64 dt;
    7677             : 
    7678             :     // Tank object reference
    7679     1164484 :     const Real64 &nTankNodes = this->Nodes;
    7680             : 
    7681             :     // Fraction of the current hour that has elapsed (h)
    7682             :     const Real64 TimeElapsed_loc =
    7683     1164484 :         state.dataGlobal->HourOfDay + state.dataGlobal->TimeStep * state.dataGlobal->TimeStepZone + state.dataHVACGlobal->SysTimeElapsed;
    7684             : 
    7685             :     // Seconds in one DataGlobals::TimeStep (s)
    7686     1164484 :     const Real64 SecInTimeStep = state.dataHVACGlobal->TimeStepSysSec;
    7687             : 
    7688             :     // Advance tank simulation to the next system DataGlobals::TimeStep, if applicable
    7689     1164484 :     if (this->TimeElapsed != TimeElapsed_loc) {
    7690             :         // The simulation has advanced to the next system DataGlobals::TimeStep.  Save conditions from the end of the previous system
    7691             :         // DataGlobals::TimeStep for use as the initial conditions of each iteration that does not advance the system DataGlobals::TimeStep.
    7692      413556 :         for (auto &e : this->Node)
    7693      367540 :             e.SavedTemp = e.Temp;
    7694             : 
    7695       46016 :         this->SavedHeaterOn1 = this->HeaterOn1;
    7696       46016 :         this->SavedHeaterOn2 = this->HeaterOn2;
    7697             : 
    7698             :         // Save outlet temperatures for demand-side flow control
    7699       46016 :         this->SavedUseOutletTemp = this->UseOutletTemp;
    7700       46016 :         this->SavedSourceOutletTemp = this->SourceOutletTemp;
    7701             : 
    7702       46016 :         this->TimeElapsed = TimeElapsed_loc;
    7703             :     }
    7704             : 
    7705             :     // Reset node temperatures to what they were at the beginning of the system DataGlobals::TimeStep.
    7706     9387118 :     for (auto &e : this->Node)
    7707     8222634 :         e.Temp = e.SavedTemp;
    7708             : 
    7709     1164484 :     this->HeaterOn1 = this->SavedHeaterOn1;
    7710     1164484 :     this->HeaterOn2 = this->SavedHeaterOn2;
    7711             : 
    7712             :     // Condenser configuration of heat pump water heater
    7713             :     const DataPlant::PlantEquipmentType HPWHCondenserConfig =
    7714     1164484 :         this->HeatPumpNum > 0 ? state.dataWaterThermalTanks->HPWaterHeater(this->HeatPumpNum).HPWHType : DataPlant::PlantEquipmentType::Invalid;
    7715             : 
    7716             :     // Heat rate from the heat pump (W)
    7717     2964868 :     const Real64 Qheatpump = [&, this] { // BLB
    7718     1164484 :         if (this->HeatPumpNum == 0) return 0.0;
    7719      900192 :         HeatPumpWaterHeaterData const &HPWH = state.dataWaterThermalTanks->HPWaterHeater(this->HeatPumpNum);
    7720             :         Real64 CoilTotalHeatingEnergyRate;
    7721      900192 :         if (HPWH.NumofSpeed > 0) {
    7722             :             // VSHPWH
    7723       70625 :             VariableSpeedCoils::VariableSpeedCoilData const &Coil = state.dataVariableSpeedCoils->VarSpeedCoil(HPWH.DXCoilNum);
    7724       70625 :             CoilTotalHeatingEnergyRate = Coil.TotalHeatingEnergyRate;
    7725             :         } else {
    7726             :             // Single speed HPWH
    7727      829567 :             DXCoils::DXCoilData const &Coil = state.dataDXCoils->DXCoil(HPWH.DXCoilNum);
    7728      829567 :             CoilTotalHeatingEnergyRate = Coil.TotalHeatingEnergyRate;
    7729             :         }
    7730      900192 :         return CoilTotalHeatingEnergyRate * this->SourceEffectiveness;
    7731     1164484 :     }();
    7732             : 
    7733             :     // Minimum tank temperatures
    7734     1164484 :     const Real64 MinTemp1 = this->SetPointTemp - this->DeadBandDeltaTemp;
    7735     1164484 :     const Real64 MinTemp2 = this->SetPointTemp2 - this->DeadBandDeltaTemp2;
    7736             : 
    7737             :     // Specific Heat of water (J/kg K)
    7738     1164484 :     const Real64 Cp = [&] {
    7739     1164484 :         if (this->UseSidePlantLoc.loopNum > 0) {
    7740     1093285 :             return FluidProperties::GetSpecificHeatGlycol(state,
    7741     1093285 :                                                           state.dataPlnt->PlantLoop(this->UseSidePlantLoc.loopNum).FluidName,
    7742             :                                                           this->TankTemp,
    7743     1093285 :                                                           state.dataPlnt->PlantLoop(this->UseSidePlantLoc.loopNum).FluidIndex,
    7744     1093285 :                                                           RoutineName);
    7745             :         } else {
    7746       71199 :             return FluidProperties::GetSpecificHeatGlycol(state, fluidNameWater, this->TankTemp, this->waterIndex, RoutineName);
    7747             :         }
    7748     1164484 :     }();
    7749             : 
    7750     1164484 :     Real64 Eloss = 0.0;             // Energy change due to ambient losses over the DataGlobals::TimeStep (J)
    7751     1164484 :     Real64 Euse = 0.0;              // Energy change due to use side mass flow over the DataGlobals::TimeStep (J)
    7752     1164484 :     Real64 Esource = 0.0;           // Energy change due to source side mass flow over the DataGlobals::TimeStep (J)
    7753     1164484 :     Real64 Eheater1 = 0.0;          // Energy change due to heater 1 over the DataGlobals::TimeStep (J)
    7754     1164484 :     Real64 Eheater2 = 0.0;          // Energy change due to heater 2 over the DataGlobals::TimeStep (J)
    7755     1164484 :     Real64 Eunmet = 0.0;            // Energy change unmet over the DataGlobals::TimeStep (J)
    7756     1164484 :     Real64 Event = 0.0;             // Energy change due to venting over the DataGlobals::TimeStep (J)
    7757     1164484 :     int CycleOnCount1_loc = 0;      // Number of times heater 1 cycles on in the current time step
    7758     1164484 :     int CycleOnCount2_loc = 0;      // Number of times heater 2 cycles on in the current time step
    7759     1164484 :     Real64 Runtime = 0.0;           // Time that either heater is running (s)
    7760     1164484 :     Real64 Runtime1 = 0.0;          // Time that heater 1 is running (s)
    7761     1164484 :     Real64 Runtime2 = 0.0;          // Time that heater 2 is running (s)
    7762     1164484 :     bool SetPointRecovered = false; // Flag to indicate when set point is recovered for the first time
    7763             :     // Added three variables for desuperheater sourceinlet temperature update
    7764             :     Real64 MdotDesuperheaterWater;        // mass flow rate of desuperheater source side water, kg/s
    7765     1164484 :     Real64 DesuperheaterPLR = 0.0;        // Desuperheater part load ratio
    7766     1164484 :     Real64 DesuperheaterHeaterRate = 0.0; // Desuperheater heater rate (W)
    7767     1164484 :     Real64 SourceInletTempSum = 0.0;      // Sum the source inlet temperature in sub time step to calculate average tempearature
    7768             :     Real64 Qheater1;                      // Heating rate of burner or electric heating element 1 (W)
    7769             :     Real64 Qheater2;                      // Heating rate of burner or electric heating element 2 (W)
    7770             : 
    7771     1164484 :     if (this->InletMode == InletPositionMode::Fixed) CalcNodeMassFlows(InletPositionMode::Fixed);
    7772             : 
    7773             :     // Time remaining in the current DataGlobals::TimeStep (s)
    7774     1164484 :     Real64 TimeRemaining = SecInTimeStep;
    7775             : 
    7776             :     // Diff Eq. Coefficients for each node
    7777     1164484 :     std::vector<Real64> A;
    7778     1164484 :     A.resize(nTankNodes);
    7779     1164484 :     std::vector<Real64> B;
    7780     1164484 :     B.resize(nTankNodes);
    7781             : 
    7782             :     // Temperature at the end of the internal DataGlobals::TimeStep
    7783     1164484 :     std::vector<Real64> Tfinal;
    7784     1164484 :     Tfinal.resize(nTankNodes);
    7785             : 
    7786             :     // Average temperature of each node over the internal DataGlobals::TimeStep
    7787     1164484 :     std::vector<Real64> Tavg;
    7788     1164484 :     Tavg.resize(nTankNodes);
    7789             : 
    7790     1164484 :     int SubTimestepCount = 0;
    7791             : 
    7792     6325347 :     while (TimeRemaining > 0.0) {
    7793             : 
    7794     5160863 :         ++SubTimestepCount;
    7795             : 
    7796     5160863 :         bool PrevHeaterOn1 = this->HeaterOn1;
    7797     5160863 :         bool PrevHeaterOn2 = this->HeaterOn2;
    7798             : 
    7799     5160863 :         if (this->InletMode == InletPositionMode::Seeking) CalcNodeMassFlows(InletPositionMode::Seeking);
    7800             : 
    7801             :         // Heater control logic
    7802     5160863 :         if (this->IsChilledWaterTank) {
    7803             :             // Chilled Water Tank, no heating
    7804      350994 :             Qheater1 = 0.0;
    7805      350994 :             Qheater2 = 0.0;
    7806             :         } else {
    7807             :             // Control the first heater element (master)
    7808     4809869 :             if (this->MaxCapacity > 0.0) {
    7809     2875584 :                 const Real64 &NodeTemp = this->Node(this->HeaterNode1).Temp;
    7810             : 
    7811     2875584 :                 if (this->HeaterOn1) {
    7812      278506 :                     if (NodeTemp >= this->SetPointTemp) {
    7813       42983 :                         this->HeaterOn1 = false;
    7814       42983 :                         SetPointRecovered = true;
    7815             :                     }
    7816             :                 } else { // Heater is off
    7817     2597078 :                     if (NodeTemp < MinTemp1) {
    7818       84329 :                         this->HeaterOn1 = true;
    7819       84329 :                         ++CycleOnCount1_loc;
    7820             :                     }
    7821             :                 }
    7822             :             }
    7823             : 
    7824     4809869 :             if (this->HeaterOn1) {
    7825      319872 :                 Qheater1 = this->MaxCapacity;
    7826             :             } else {
    7827     4489997 :                 Qheater1 = 0.0;
    7828             :             }
    7829             : 
    7830             :             // Control the second heater element (slave)
    7831     4809869 :             if (this->MaxCapacity2 > 0.0) {
    7832      756904 :                 if ((this->StratifiedControlMode == PriorityControlMode::MasterSlave) && this->HeaterOn1) {
    7833       30937 :                     this->HeaterOn2 = false;
    7834             : 
    7835             :                 } else {
    7836      725967 :                     const Real64 &NodeTemp = this->Node(this->HeaterNode2).Temp;
    7837             : 
    7838      725967 :                     if (this->HeaterOn2) {
    7839      422778 :                         if (NodeTemp >= this->SetPointTemp2) {
    7840        7028 :                             this->HeaterOn2 = false;
    7841        7028 :                             SetPointRecovered = true;
    7842             :                         }
    7843             :                     } else { // Heater is off
    7844      303189 :                         if (NodeTemp < MinTemp2) {
    7845       58361 :                             this->HeaterOn2 = true;
    7846       58361 :                             ++CycleOnCount2_loc;
    7847             :                         }
    7848             :                     }
    7849             :                 }
    7850             :             }
    7851             : 
    7852     4809869 :             if (this->HeaterOn2) {
    7853      474111 :                 Qheater2 = this->MaxCapacity2;
    7854             :             } else {
    7855     4335758 :                 Qheater2 = 0.0;
    7856             :             }
    7857             :         }
    7858             : 
    7859     5160863 :         if (SubTimestepCount == 1) {
    7860     1164484 :             dt = SubTimestepMin;
    7861             :         } else {
    7862             : 
    7863             :             // Set the maximum tank temperature change allowed
    7864     3996379 :             Real64 dT_max = std::numeric_limits<Real64>::max();
    7865     3996379 :             if (this->HeaterOn1) {
    7866      310637 :                 if (this->Node(this->HeaterNode1).Temp < this->SetPointTemp) {
    7867             :                     // Node temperature is less than setpoint and heater is on
    7868      310637 :                     dT_max = min(dT_max, this->SetPointTemp - this->Node(this->HeaterNode1).Temp);
    7869             :                 } else {
    7870             :                     // Node temperature is greater than or equal to setpoint and heater is on
    7871             :                     // Heater will turn off next time around, calculate assuming that
    7872           0 :                     dT_max = min(dT_max, this->Node(this->HeaterNode1).Temp - MinTemp1);
    7873             :                 }
    7874             :             } else { // Heater off
    7875     3685742 :                 if (this->Node(this->HeaterNode1).Temp >= MinTemp1) {
    7876             :                     // Node temperature is greater than or equal to cut in temperature and heater is off
    7877     2904330 :                     dT_max = min(dT_max, this->Node(this->HeaterNode1).Temp - MinTemp1);
    7878             :                 } else {
    7879             :                     // Heater will turn on next time around, calculate to setpoint
    7880      781412 :                     dT_max = min(dT_max, this->SetPointTemp - this->Node(this->HeaterNode1).Temp);
    7881             :                 }
    7882             :             }
    7883     3996379 :             if (this->HeaterOn2) {
    7884      454824 :                 if (this->Node(this->HeaterNode2).Temp < this->SetPointTemp2) {
    7885             :                     // Node temperature is less than setpoint and heater is on
    7886      454824 :                     dT_max = min(dT_max, this->SetPointTemp2 - this->Node(this->HeaterNode2).Temp);
    7887             :                 } else {
    7888             :                     // Node temperature is greater than or equal to setpoint and heater is on
    7889             :                     // Heater will turn off next time around, calculate assuming that
    7890           0 :                     dT_max = min(dT_max, this->Node(this->HeaterNode2).Temp - MinTemp2);
    7891             :                 }
    7892             :             } else { // Heater off
    7893     3541555 :                 if (this->Node(this->HeaterNode2).Temp >= MinTemp2) {
    7894             :                     // Node temperature is greater than or equal to cut in temperature and heater is off
    7895     1901952 :                     dT_max = min(dT_max, this->Node(this->HeaterNode2).Temp - MinTemp2);
    7896             :                 } else {
    7897             :                     // Heater will turn on next time around, calculate to setpoint
    7898     1639603 :                     dT_max = min(dT_max, this->SetPointTemp2 - this->Node(this->HeaterNode2).Temp);
    7899             :                 }
    7900             :             }
    7901             : 
    7902             :             // Make adjustments to A and B to account for heaters being on or off now
    7903     3996379 :             if (this->HeaterOn1 && !PrevHeaterOn1) {
    7904             :                 // If heater 1 is on now and wasn't before add the heat rate to the B term
    7905       83473 :                 B[this->HeaterNode1 - 1] += Qheater1 / (this->Node(this->HeaterNode1).Mass * Cp);
    7906     3912906 :             } else if (!this->HeaterOn1 && PrevHeaterOn1) {
    7907             :                 // If heater 1 is off now and was on before, remove the heat rate from the B term
    7908       41709 :                 B[this->HeaterNode1 - 1] -= this->MaxCapacity / (this->Node(this->HeaterNode1).Mass * Cp);
    7909             :             }
    7910     3996379 :             if (this->HeaterOn2 && !PrevHeaterOn2) {
    7911             :                 // If heater 2 is on now and wasn't before add the heat rate to the B term
    7912       57921 :                 B[this->HeaterNode2 - 1] += Qheater2 / (this->Node(this->HeaterNode2).Mass * Cp);
    7913     3938458 :             } else if (!this->HeaterOn2 && PrevHeaterOn2) {
    7914             :                 // If heater 1 is off now and was on before, remove the heat rate from the B term
    7915       12215 :                 B[this->HeaterNode2 - 1] -= this->MaxCapacity / (this->Node(this->HeaterNode2).Mass * Cp);
    7916             :             }
    7917             : 
    7918     3996379 :             if ((this->HeaterOn1 || this->HeaterOn2) && !(PrevHeaterOn1 || PrevHeaterOn2)) {
    7919             :                 // Remove off cycle loads
    7920             :                 // Apply on cycle loads
    7921     1266063 :                 for (int i = 0; i < nTankNodes; i++) {
    7922     1130608 :                     auto &node = this->Node[i];
    7923     1130608 :                     Real64 NodeCapacitance = node.Mass * Cp;
    7924     1130608 :                     A[i] += (node.OffCycLossCoeff - node.OnCycLossCoeff) / NodeCapacitance;
    7925     1130608 :                     B[i] += (-node.OffCycParaLoad + node.OnCycParaLoad + (node.OnCycLossCoeff - node.OffCycLossCoeff) * this->AmbientTemp) /
    7926             :                             NodeCapacitance;
    7927             :                 }
    7928     3996379 :             } else if (!(this->HeaterOn1 || this->HeaterOn2) && (PrevHeaterOn1 || PrevHeaterOn2)) {
    7929             :                 // Remove on cycle loads
    7930             :                 // Apply off cycle loads
    7931      501951 :                 for (int i = 0; i < nTankNodes; i++) {
    7932      453966 :                     auto &node = this->Node[i];
    7933      453966 :                     Real64 NodeCapacitance = node.Mass * Cp;
    7934      453966 :                     A[i] -= (node.OffCycLossCoeff - node.OnCycLossCoeff) / NodeCapacitance;
    7935      453966 :                     B[i] -= (-node.OffCycParaLoad + node.OnCycParaLoad + (node.OnCycLossCoeff - node.OffCycLossCoeff) * this->AmbientTemp) /
    7936             :                             NodeCapacitance;
    7937             :                 }
    7938             :             }
    7939             : 
    7940             :             // Set the sub DataGlobals::TimeStep (dt)
    7941     3996379 :             dt = TimeRemaining;
    7942    30133559 :             for (int i = 0; i < nTankNodes; ++i) {
    7943    26137180 :                 const Real64 Denominator = fabs(A[i] * Tavg[i] + B[i]);
    7944    26137180 :                 if (Denominator != 0.0) dt = min(dt, dT_max / Denominator);
    7945             :             }
    7946     3996379 :             dt = max(min(SubTimestepMin, TimeRemaining), dt);
    7947     3996379 :             dt = min(SubTimestepMax, dt);
    7948             :         }
    7949             : 
    7950             :         // Make initial guess that average and final temperatures over the DataGlobals::TimeStep are equal to the starting temperatures
    7951    39520677 :         for (int i = 0; i < nTankNodes; i++) {
    7952    34359814 :             const auto &NodeTemp = this->Node[i].Temp;
    7953    34359814 :             Tfinal[i] = NodeTemp;
    7954    34359814 :             Tavg[i] = NodeTemp;
    7955             :         }
    7956             : 
    7957    22791631 :         for (int ConvergenceCounter = 1; ConvergenceCounter <= 10; ConvergenceCounter++) {
    7958             : 
    7959    22437820 :             std::fill(A.begin(), A.end(), 0.0);
    7960    22437820 :             std::fill(B.begin(), B.end(), 0.0);
    7961             : 
    7962             :             // Heater Coefficients
    7963    22437820 :             B[this->HeaterNode1 - 1] += Qheater1;
    7964    22437820 :             B[this->HeaterNode2 - 1] += Qheater2;
    7965             : 
    7966   206578402 :             for (int i = 0; i < nTankNodes; i++) {
    7967   184140582 :                 const int NodeNum = i + 1;
    7968   184140582 :                 const auto &tank_node = this->Node(NodeNum);
    7969             : 
    7970             :                 // Parasitic Loads and Losses to Ambient
    7971   184140582 :                 if (this->HeaterOn1 || this->HeaterOn2) {
    7972             :                     // Parasitic Loads
    7973    31359840 :                     B[i] += tank_node.OnCycParaLoad;
    7974             :                     // Losses to Ambient
    7975    31359840 :                     A[i] += -tank_node.OnCycLossCoeff;
    7976    31359840 :                     B[i] += tank_node.OnCycLossCoeff * this->AmbientTemp;
    7977             :                 } else {
    7978             :                     // Parasitic Loads
    7979   152780742 :                     B[i] += tank_node.OffCycParaLoad;
    7980             :                     // Losses to Ambient
    7981   152780742 :                     A[i] += -tank_node.OffCycLossCoeff;
    7982   152780742 :                     B[i] += tank_node.OffCycLossCoeff * this->AmbientTemp;
    7983             :                 }
    7984             : 
    7985             :                 // Conduction to adjacent nodes
    7986   184140582 :                 A[i] += -(tank_node.CondCoeffDn + tank_node.CondCoeffUp);
    7987   184140582 :                 if (NodeNum > 1) B[i] += tank_node.CondCoeffUp * Tavg[i - 1];
    7988   184140582 :                 if (NodeNum < nTankNodes) B[i] += tank_node.CondCoeffDn * Tavg[i + 1];
    7989             : 
    7990             :                 // Use side plant connection
    7991   184140582 :                 const Real64 use_e_mdot_cp = tank_node.UseMassFlowRate * Cp;
    7992   184140582 :                 A[i] += -use_e_mdot_cp;
    7993   184140582 :                 B[i] += use_e_mdot_cp * this->UseInletTemp;
    7994             : 
    7995             :                 // Source side heat transfer rate
    7996   184140582 :                 if ((this->HeatPumpNum > 0) && (HPWHCondenserConfig == DataPlant::PlantEquipmentType::HeatPumpWtrHeaterPumped)) {
    7997             :                     // Pumped Condenser Heat Pump Water Heater
    7998   124137456 :                     if (tank_node.SourceMassFlowRate > 0.0) B[i] += Qheatpump;
    7999             :                 } else {
    8000             :                     // Source side plant connection (constant temperature)
    8001    60003126 :                     const Real64 src_e_mdot_cp = tank_node.SourceMassFlowRate * Cp;
    8002    60003126 :                     A[i] += -src_e_mdot_cp;
    8003    60003126 :                     B[i] += src_e_mdot_cp * this->SourceInletTemp;
    8004             :                 }
    8005             : 
    8006             :                 // Wrapped condenser heat pump water heater
    8007   184140582 :                 if ((this->HeatPumpNum > 0) && (HPWHCondenserConfig == DataPlant::PlantEquipmentType::HeatPumpWtrHeaterWrapped)) {
    8008    27582976 :                     B[i] += Qheatpump * tank_node.HPWHWrappedCondenserHeatingFrac;
    8009             :                 }
    8010             : 
    8011             :                 // Internodal flow
    8012   184140582 :                 A[i] += -(tank_node.MassFlowFromUpper + tank_node.MassFlowFromLower) * Cp;
    8013   184140582 :                 if (NodeNum > 1) B[i] += tank_node.MassFlowFromUpper * Cp * Tavg[i - 1];
    8014   184140582 :                 if (NodeNum < nTankNodes) B[i] += tank_node.MassFlowFromLower * Cp * Tavg[i + 1];
    8015             : 
    8016             :                 // Divide by mass and specific heat
    8017             :                 // m * cp * dT/dt = q_net  =>  dT/dt = a * T + b
    8018   184140582 :                 A[i] /= tank_node.Mass * Cp;
    8019   184140582 :                 B[i] /= tank_node.Mass * Cp;
    8020             : 
    8021             :             } // end for each node
    8022             : 
    8023             :             // Calculate the average and final temperatures over the interval
    8024    22437820 :             Real64 TfinalDiff = 0.0;
    8025   206578402 :             for (int i = 0; i < nTankNodes; ++i) {
    8026   184140582 :                 const Real64 Tstart = this->Node[i].Temp;
    8027   184140582 :                 const Real64 b_a = B[i] / A[i];
    8028   184140582 :                 const Real64 e_a_dt = exp(A[i] * dt);
    8029   184140582 :                 Tavg[i] = (Tstart + b_a) * (e_a_dt - 1.0) / (A[i] * dt) - b_a;
    8030   184140582 :                 const Real64 Tfinal_old = Tfinal[i];
    8031   184140582 :                 Tfinal[i] = (Tstart + b_a) * e_a_dt - b_a;
    8032   184140582 :                 TfinalDiff = max(fabs(Tfinal[i] - Tfinal_old), TfinalDiff);
    8033             :             }
    8034             : 
    8035    22437820 :             if (TfinalDiff < TemperatureConvergenceCriteria) break;
    8036             : 
    8037    17630768 :             if (this->DesuperheaterNum > 0) {
    8038       47893 :                 DesuperheaterPLR = state.dataWaterThermalTanks->WaterHeaterDesuperheater(this->DesuperheaterNum).DesuperheaterPLR;
    8039       47893 :                 DesuperheaterHeaterRate = state.dataWaterThermalTanks->WaterHeaterDesuperheater(this->DesuperheaterNum).HeaterRate;
    8040       47893 :                 MdotDesuperheaterWater = state.dataWaterThermalTanks->WaterHeaterDesuperheater(this->DesuperheaterNum).OperatingWaterFlowRate *
    8041       47893 :                                          Psychrometrics::RhoH2O(Tavg[this->SourceOutletStratNode - 1]);
    8042       47893 :                 if (DesuperheaterPLR > 0.0 && MdotDesuperheaterWater > 0.0) {
    8043       34540 :                     this->SourceInletTemp =
    8044       34540 :                         Tavg[this->SourceOutletStratNode - 1] + (DesuperheaterHeaterRate / DesuperheaterPLR) / (MdotDesuperheaterWater * Cp);
    8045             :                 } else {
    8046       13353 :                     this->SourceInletTemp = Tavg[this->SourceOutletStratNode - 1];
    8047             :                 }
    8048             :             }
    8049             :         } // end temperature convergence loop
    8050             : 
    8051             :         // Inversion mixing
    8052             :         bool HasInversion;
    8053     8209118 :         do {
    8054     8209118 :             HasInversion = false;
    8055             :             // Starting from the top of the tank check if the node below has a temperature inversion.
    8056    47554278 :             for (int j = 0; j < nTankNodes - 1; ++j) {
    8057    42393415 :                 if (Tfinal[j] < Tfinal[j + 1]) {
    8058             : 
    8059             :                     // Temperature inversion!
    8060     3048255 :                     HasInversion = true;
    8061             : 
    8062             :                     // From the node above the inversion, move down calculating a weighted average
    8063             :                     // of node temperatures until the node below the group of mixed nodes isn't hotter
    8064             :                     // or we hit the bottom of the tank.
    8065     3048255 :                     Real64 Tmixed = 0.0;
    8066     3048255 :                     Real64 MassMixed = 0.0;
    8067             :                     int m;
    8068    15129678 :                     for (m = j; m < nTankNodes; ++m) {
    8069    15129678 :                         Tmixed += Tfinal[m] * this->Node[m].Mass;
    8070    15129678 :                         MassMixed += this->Node[m].Mass;
    8071    15129678 :                         if ((m == nTankNodes - 1) || (Tmixed / MassMixed > Tfinal[m + 1])) break;
    8072             :                     }
    8073     3048255 :                     Tmixed /= MassMixed;
    8074             : 
    8075             :                     // Now we have a range of nodes (j = top, m = bottom) that are mixed
    8076             :                     // and the mixed temperature (Tmixed).
    8077             :                     // Move through the mixed nodes and set the final temperature to the mixed temperature.
    8078             :                     // Also calculate a corrected average temperature for each node.
    8079    18177933 :                     for (int k = j; k <= m; ++k) {
    8080             :                         Real64 FinalFactorMixing;
    8081             :                         Real64 AvgFactorMixing;
    8082    15129678 :                         const Real64 NodeCapacitance = this->Node[k].Mass * Cp;
    8083    15129678 :                         if (A[k] == 0.0) {
    8084           0 :                             FinalFactorMixing = dt / NodeCapacitance;
    8085           0 :                             AvgFactorMixing = FinalFactorMixing / 2.0;
    8086             :                         } else {
    8087    15129678 :                             FinalFactorMixing = (exp(A[k] * dt) - 1.0) / A[k] / NodeCapacitance;
    8088    15129678 :                             AvgFactorMixing = ((exp(A[k] * dt) - 1.0) / A[k] / dt - 1.0) / A[k] / NodeCapacitance;
    8089             :                         }
    8090    15129678 :                         const Real64 Q_AdiabaticMixing = (Tmixed - Tfinal[k]) / FinalFactorMixing;
    8091    15129678 :                         Tfinal[k] = Tmixed;
    8092    15129678 :                         Tavg[k] += Q_AdiabaticMixing * AvgFactorMixing;
    8093             :                     }
    8094             : 
    8095             :                     // Since we mixed, get out of here and start from the top to check again for mixing.
    8096     3048255 :                     break;
    8097             :                 }
    8098             :             }
    8099             :         } while (HasInversion);
    8100             : 
    8101             :         // Venting
    8102     5160863 :         if (!this->IsChilledWaterTank) {
    8103     4809869 :             if (Tfinal[0] > this->TankTempLimit) {
    8104     1058206 :                 for (int i = 0; i < nTankNodes; ++i) {
    8105      914594 :                     if (Tfinal[i] > this->TankTempLimit) {
    8106      366497 :                         Event += this->Node[i].Mass * Cp * (this->TankTempLimit - Tfinal[i]);
    8107      366497 :                         Tfinal[i] = this->TankTempLimit;
    8108             :                     }
    8109             :                 }
    8110             :             }
    8111             :         }
    8112             : 
    8113             :         // Increment to next internal time step
    8114     5160863 :         TimeRemaining -= dt;
    8115     5160863 :         Real64 Qloss = 0.0;
    8116    39520677 :         for (int i = 0; i < nTankNodes; ++i) {
    8117    34359814 :             auto &node = this->Node[i];
    8118    34359814 :             node.Temp = Tfinal[i];
    8119    34359814 :             node.TempSum += Tavg[i] * dt;
    8120             : 
    8121             :             // Bookkeeping for reporting variables, mostly for Qunmet.
    8122    34359814 :             Real64 Qloss_node = (this->AmbientTemp - Tavg[i]);
    8123             :             Real64 Qheat_node;
    8124    34359814 :             const Real64 Quse_node = node.UseMassFlowRate * Cp * (this->UseInletTemp - Tavg[i]);
    8125    34359814 :             const Real64 Qsource_node = [&] {
    8126    34359814 :                 if (this->HeatPumpNum > 0) {
    8127    27896208 :                     if (HPWHCondenserConfig == DataPlant::PlantEquipmentType::HeatPumpWtrHeaterPumped) {
    8128    21368426 :                         if (node.SourceMassFlowRate > 0.0) {
    8129     1580231 :                             return Qheatpump;
    8130             :                         } else {
    8131    19788195 :                             return 0.0;
    8132             :                         }
    8133             :                     } else {
    8134     6527782 :                         assert(HPWHCondenserConfig == DataPlant::PlantEquipmentType::HeatPumpWtrHeaterWrapped);
    8135     6527782 :                         return Qheatpump * node.HPWHWrappedCondenserHeatingFrac;
    8136             :                     }
    8137             :                 } else {
    8138     6463606 :                     return node.SourceMassFlowRate * Cp * (this->SourceInletTemp - Tavg[i]);
    8139             :                 }
    8140    34359814 :             }();
    8141             : 
    8142    34359814 :             if (this->HeaterOn1 || this->HeaterOn2) {
    8143     5981750 :                 Qloss_node *= node.OnCycLossCoeff;
    8144     5981750 :                 Qheat_node = node.OnCycParaLoad * this->OnCycParaFracToTank;
    8145             :             } else {
    8146    28378064 :                 Qloss_node *= node.OffCycLossCoeff;
    8147    28378064 :                 Qheat_node = node.OffCycParaLoad * this->OffCycParaFracToTank;
    8148             :             }
    8149    34359814 :             Qloss += Qloss_node;
    8150    34359814 :             const Real64 Qneeded_node = max(-Quse_node - Qsource_node - Qloss_node - Qheat_node, 0.0);
    8151    34359814 :             const Real64 Qunmet_node = max(Qneeded_node - Qheater1 - Qheater2, 0.0);
    8152    34359814 :             Eunmet += Qunmet_node * dt;
    8153             :         }
    8154     5160863 :         SourceInletTempSum += this->SourceInletTemp * dt;
    8155             :         // More bookkeeping for reporting variables
    8156     5160863 :         Eloss += Qloss * dt;
    8157     5160863 :         const Real64 Quse = (this->UseOutletStratNode > 0)
    8158     5160863 :                                 ? this->UseEffectiveness * this->UseMassFlowRate * Cp * (this->UseInletTemp - Tavg[this->UseOutletStratNode - 1])
    8159     5160863 :                                 : 0.0;
    8160     5160863 :         Euse += Quse * dt;
    8161     5160863 :         const Real64 Qsource = [&] {
    8162     5160863 :             if (this->HeatPumpNum > 0) {
    8163     4338294 :                 if (HPWHCondenserConfig == DataPlant::PlantEquipmentType::HeatPumpWtrHeaterPumped) {
    8164     2404739 :                     return Qheatpump;
    8165             :                 } else {
    8166     1933555 :                     assert(HPWHCondenserConfig == DataPlant::PlantEquipmentType::HeatPumpWtrHeaterWrapped);
    8167     1933555 :                     return 0.0;
    8168             :                 }
    8169             :             } else {
    8170      822569 :                 if (this->SourceOutletStratNode > 0) {
    8171      576157 :                     return this->SourceEffectiveness * this->SourceMassFlowRate * Cp *
    8172      576157 :                            (this->SourceInletTemp - Tavg[this->SourceOutletStratNode - 1]);
    8173             :                 } else {
    8174      246412 :                     return 0.0;
    8175             :                 }
    8176             :             }
    8177     5160863 :         }();
    8178     5160863 :         Esource += Qsource * dt;
    8179     5160863 :         if (this->HeaterOn1) Runtime1 += dt;
    8180     5160863 :         if (this->HeaterOn2) Runtime2 += dt;
    8181     5160863 :         if (this->HeaterOn1 || this->HeaterOn2) Runtime += dt;
    8182     5160863 :         Eheater1 += Qheater1 * dt;
    8183     5160863 :         Eheater2 += Qheater2 * dt;
    8184             : 
    8185             :         // Calculation for standard ratings
    8186     5160863 :         if (!this->FirstRecoveryDone) {
    8187             :             Real64 Qrecovery;
    8188     3298474 :             if (this->HeaterOn1 || this->HeaterOn2) {
    8189      106652 :                 Qrecovery = (Qheater1 + Qheater1) / this->Efficiency + this->OnCycParaLoad;
    8190             :             } else {
    8191     3191822 :                 Qrecovery = this->OffCycParaLoad;
    8192             :             }
    8193     3298474 :             this->FirstRecoveryFuel += Qrecovery * dt;
    8194     3298474 :             if (SetPointRecovered) this->FirstRecoveryDone = true;
    8195             :         }
    8196             :     } // end while TimeRemaining > 0.0
    8197             : 
    8198     9387118 :     for (auto &e : this->Node) {
    8199     8222634 :         e.TempAvg = e.TempSum / SecInTimeStep;
    8200     8222634 :         e.TempSum = 0.0;
    8201             :     }
    8202             : 
    8203     1164484 :     this->TankTemp = sum(this->Node, &StratifiedNodeData::Temp) / this->Nodes;
    8204     1164484 :     this->TankTempAvg = sum(this->Node, &StratifiedNodeData::TempAvg) / this->Nodes;
    8205             : 
    8206     1164484 :     if (!state.dataGlobal->WarmupFlag) {
    8207             :         // Warn for potential freezing when avg of final temp over all nodes is below 2°C (nearing 0°C)
    8208      252428 :         if (this->TankTemp < 2) {
    8209           0 :             if (this->FreezingErrorIndex == 0) {
    8210           0 :                 ShowWarningError(state,
    8211           0 :                                  format("{}: {} = '{}':  Temperature of tank < 2C indicates of possibility of freeze. Tank Temperature = {:.2R} C.",
    8212             :                                         RoutineName,
    8213           0 :                                         this->Type,
    8214           0 :                                         this->Name,
    8215           0 :                                         this->TankTemp));
    8216           0 :                 ShowContinueErrorTimeStamp(state, "");
    8217             :             }
    8218           0 :             ShowRecurringWarningErrorAtEnd(state,
    8219           0 :                                            this->Type + " = '" + this->Name + "':  Temperature of tank < 2C indicates of possibility of freeze",
    8220           0 :                                            this->FreezingErrorIndex,
    8221           0 :                                            this->TankTemp, // Report Max
    8222           0 :                                            this->TankTemp, // Report Min
    8223             :                                            _,              // Don't report Sum
    8224             :                                            "{C}",          // Max Unit
    8225             :                                            "{C}");         // Min Unit
    8226             :         }
    8227             :     }
    8228             : 
    8229     1164484 :     if (this->UseOutletStratNode > 0) {
    8230     1164484 :         this->UseOutletTemp = this->Node(this->UseOutletStratNode).TempAvg;
    8231             :         // Revised use outlet temperature to ensure energy balance. Assumes a constant CP. CR8341/CR8570
    8232     1164484 :         if (this->UseMassFlowRate > 0.0) {
    8233      894247 :             this->UseOutletTemp = this->UseInletTemp * (1.0 - this->UseEffectiveness) + this->UseOutletTemp * this->UseEffectiveness;
    8234             :         }
    8235             :     }
    8236             : 
    8237     1164484 :     if (HPWHCondenserConfig == DataPlant::PlantEquipmentType::HeatPumpWtrHeaterWrapped) {
    8238             :         // If we have a wrapped condenser HPWH, set the source outlet to the weighted average of the node
    8239             :         // temperatures the condenser sees
    8240      476567 :         Real64 WeightedAverageSourceOutletTemp(0.0);
    8241     2912883 :         for (int i = 1; i <= this->Nodes; ++i) {
    8242     2436316 :             WeightedAverageSourceOutletTemp += this->Node(i).TempAvg * this->Node(i).HPWHWrappedCondenserHeatingFrac;
    8243             :         }
    8244      476567 :         this->SourceOutletTemp = WeightedAverageSourceOutletTemp;
    8245      687917 :     } else if (this->SourceOutletStratNode > 0) {
    8246             :         // otherwise set it to the temperature of the source outlet node
    8247      604769 :         this->SourceOutletTemp = this->Node(this->SourceOutletStratNode).TempAvg;
    8248             :         // Output the average inlet temperature for the DataGlobals::TimeStep
    8249      604769 :         this->SourceInletTemp = SourceInletTempSum / SecInTimeStep;
    8250             :     }
    8251     1164484 :     if (HPWHCondenserConfig == DataPlant::PlantEquipmentType::HeatPumpWtrHeaterPumped) {
    8252             :         // For pumped condensers, set the source inlet and outlets to match the delta T
    8253             :         // across the water side of the DX coil.
    8254      423625 :         HeatPumpWaterHeaterData const &HeatPump = state.dataWaterThermalTanks->HPWaterHeater(this->HeatPumpNum);
    8255      423625 :         DataLoopNode::NodeData const &HPWHCondWaterInletNode = state.dataLoopNodes->Node(HeatPump.CondWaterInletNode);
    8256      423625 :         DataLoopNode::NodeData const &HPWHCondWaterOutletNode = state.dataLoopNodes->Node(HeatPump.CondWaterOutletNode);
    8257      423625 :         Real64 const HPWHCondenserDeltaT = HPWHCondWaterOutletNode.Temp - HPWHCondWaterInletNode.Temp;
    8258      423625 :         this->SourceInletTemp = this->SourceOutletTemp + HPWHCondenserDeltaT;
    8259             :     }
    8260             : 
    8261             :     // Revised source outlet temperature to ensure energy balance. Assumes a constant CP. CR8341/CR8570
    8262     1164484 :     if (this->SourceOutletStratNode > 0) {
    8263      604769 :         if (this->SourceMassFlowRate > 0.0) {
    8264      276498 :             this->SourceOutletTemp = this->SourceInletTemp * (1.0 - this->SourceEffectiveness) + this->SourceOutletTemp * this->SourceEffectiveness;
    8265             :         }
    8266             :     }
    8267             : 
    8268     1164484 :     this->LossRate = Eloss / SecInTimeStep;
    8269     1164484 :     this->UseRate = Euse / SecInTimeStep;
    8270     1164484 :     Real64 WrappedCondenserHeatPumpRate = 0.0;
    8271     1164484 :     if ((this->HeatPumpNum > 0) && (HPWHCondenserConfig == DataPlant::PlantEquipmentType::HeatPumpWtrHeaterPumped)) {
    8272      423625 :         this->SourceRate = Qheatpump;
    8273             :     } else {
    8274      740859 :         this->SourceRate = Esource / SecInTimeStep;
    8275      740859 :         WrappedCondenserHeatPumpRate = Qheatpump;
    8276             :     }
    8277             : 
    8278     1164484 :     this->OffCycParaFuelRate = this->OffCycParaLoad * (SecInTimeStep - Runtime) / SecInTimeStep;
    8279     1164484 :     this->OnCycParaFuelRate = this->OnCycParaLoad * Runtime / SecInTimeStep;
    8280     1164484 :     this->OffCycParaRateToTank = this->OffCycParaFuelRate * this->OffCycParaFracToTank;
    8281     1164484 :     this->OnCycParaRateToTank = this->OnCycParaFuelRate * this->OnCycParaFracToTank;
    8282     1164484 :     this->TotalDemandRate =
    8283     1164484 :         -this->UseRate - this->SourceRate - this->LossRate - this->OffCycParaRateToTank - this->OnCycParaRateToTank - WrappedCondenserHeatPumpRate;
    8284     1164484 :     this->HeaterRate1 = Eheater1 / SecInTimeStep;
    8285     1164484 :     this->HeaterRate2 = Eheater2 / SecInTimeStep;
    8286     1164484 :     this->HeaterRate = this->HeaterRate1 + this->HeaterRate2;
    8287             : 
    8288     1164484 :     this->UnmetRate = Eunmet / SecInTimeStep;
    8289     1164484 :     this->VentRate = Event / SecInTimeStep;
    8290     1164484 :     this->NetHeatTransferRate = this->UseRate + this->SourceRate + this->LossRate + this->OffCycParaRateToTank + this->OnCycParaRateToTank +
    8291     1164484 :                                 this->HeaterRate + this->VentRate + WrappedCondenserHeatPumpRate;
    8292             : 
    8293     1164484 :     this->CycleOnCount = CycleOnCount1_loc + CycleOnCount2_loc;
    8294     1164484 :     this->CycleOnCount1 = CycleOnCount1_loc;
    8295     1164484 :     this->CycleOnCount2 = CycleOnCount2_loc;
    8296             : 
    8297     1164484 :     this->RuntimeFraction = Runtime / SecInTimeStep;
    8298     1164484 :     this->RuntimeFraction1 = Runtime1 / SecInTimeStep;
    8299     1164484 :     this->RuntimeFraction2 = Runtime2 / SecInTimeStep;
    8300             : 
    8301     1164484 :     this->FuelRate = (Eheater1 + Eheater2) / this->Efficiency / SecInTimeStep;
    8302             : 
    8303             :     // Add water heater skin losses and venting losses to ambient zone, if specified
    8304     1164484 :     if (this->AmbientTempZone > 0) this->AmbientZoneGain = -this->LossRate * this->SkinLossFracToZone - this->VentRate;
    8305     1164484 : }
    8306             : 
    8307     1340033 : void WaterThermalTankData::CalcNodeMassFlows(InletPositionMode inletMode)
    8308             : {
    8309             : 
    8310             :     // SUBROUTINE INFORMATION:
    8311             :     //       AUTHOR         Peter Graham Ellis
    8312             :     //       DATE WRITTEN   January 2007
    8313             :     //       MODIFIED       na
    8314             :     //       RE-ENGINEERED  na
    8315             : 
    8316             :     // PURPOSE OF THIS SUBROUTINE:
    8317             :     // Determines mass flow rates between nodes according to the locations of the use- and source-side inlet and outlet
    8318             :     // nodes.
    8319             : 
    8320             :     // METHODOLOGY EMPLOYED:
    8321             :     // In 'Seeking' mode, nodes are searched between the user-specified inlet and outlet nodes to find the node closest
    8322             :     // in temperature to the inlet fluid temperature.  In 'Fixed' mode, the user-specified nodes are always used.
    8323             :     // Upward and downward flows are added to each node between an inlet and outlet.  Flows in both directions cancel out
    8324             :     // to leave only the net flow in one direction.
    8325             : 
    8326     1340033 :     int useInletStratNod = this->UseInletStratNode;
    8327     1340033 :     int useOutletStratNode = this->UseOutletStratNode;
    8328     1340033 :     int sourceInletStratNode = this->SourceInletStratNode;
    8329     1340033 :     int sourceOutletStratNode = this->SourceOutletStratNode;
    8330             : 
    8331     1340033 :     Real64 useMassFlowRate = this->UseMassFlowRate * this->UseEffectiveness;
    8332     1340033 :     Real64 sourceMassFlowRate = this->SourceMassFlowRate * this->SourceEffectiveness;
    8333             : 
    8334    10615961 :     for (auto &e : this->Node) {
    8335     9275928 :         e.UseMassFlowRate = 0.0;
    8336     9275928 :         e.SourceMassFlowRate = 0.0;
    8337     9275928 :         e.MassFlowFromUpper = 0.0;
    8338     9275928 :         e.MassFlowFromLower = 0.0;
    8339     9275928 :         e.MassFlowToUpper = 0.0;
    8340     9275928 :         e.MassFlowToLower = 0.0;
    8341             :     }
    8342             : 
    8343     1340033 :     if (inletMode == InletPositionMode::Seeking) {
    8344             :         // 'Seek' the node with the temperature closest to the inlet temperature
    8345             :         // Start at the user-specified inlet node and search to the user-specified outlet node
    8346             :         int Step;
    8347      350994 :         if (useMassFlowRate > 0.0) {
    8348      164192 :             if (useInletStratNod > useOutletStratNode) {
    8349           0 :                 Step = -1;
    8350             :             } else {
    8351      164192 :                 Step = 1;
    8352             :             }
    8353      164192 :             Real64 MinDeltaTemp = 1.0e6; // Some big number
    8354      164192 :             int const NodeNum_stop(floop_end(useInletStratNod, useOutletStratNode, Step));
    8355      574740 :             for (int NodeNum = useInletStratNod; NodeNum != NodeNum_stop; NodeNum += Step) {
    8356      527781 :                 Real64 DeltaTemp = std::abs(this->Node(NodeNum).Temp - this->UseInletTemp);
    8357      527781 :                 if (DeltaTemp < MinDeltaTemp) {
    8358      345284 :                     MinDeltaTemp = DeltaTemp;
    8359      345284 :                     useInletStratNod = NodeNum;
    8360      182497 :                 } else if (DeltaTemp > MinDeltaTemp) {
    8361      117233 :                     break;
    8362             :                 }
    8363             :             }
    8364             :         }
    8365             : 
    8366      350994 :         if (sourceMassFlowRate > 0.0) {
    8367       44186 :             if (sourceInletStratNode > sourceOutletStratNode) {
    8368       44186 :                 Step = -1;
    8369             :             } else {
    8370           0 :                 Step = 1;
    8371             :             }
    8372       44186 :             Real64 MinDeltaTemp = 1.0e6; // Some big number
    8373       44186 :             int const NodeNum_stop(floop_end(sourceInletStratNode, sourceOutletStratNode, Step));
    8374       89120 :             for (int NodeNum = sourceInletStratNode; NodeNum != NodeNum_stop; NodeNum += Step) {
    8375       89120 :                 Real64 DeltaTemp = std::abs(this->Node(NodeNum).Temp - this->SourceInletTemp);
    8376       89120 :                 if (DeltaTemp < MinDeltaTemp) {
    8377       44186 :                     MinDeltaTemp = DeltaTemp;
    8378       44186 :                     sourceInletStratNode = NodeNum;
    8379       44934 :                 } else if (DeltaTemp > MinDeltaTemp) {
    8380       44186 :                     break;
    8381             :                 }
    8382             :             }
    8383             :         }
    8384             :     }
    8385             : 
    8386     1340033 :     if (useInletStratNod > 0) this->Node(useInletStratNod).UseMassFlowRate = useMassFlowRate;
    8387     1340033 :     if (sourceInletStratNode > 0) this->Node(sourceInletStratNode).SourceMassFlowRate = sourceMassFlowRate;
    8388             : 
    8389     1340033 :     if (useMassFlowRate > 0.0) {
    8390      976346 :         if (useOutletStratNode > useInletStratNod) {
    8391             :             // Use-side flow is down
    8392      776068 :             for (int NodeNum = useInletStratNod; NodeNum <= useOutletStratNode - 1; ++NodeNum) {
    8393      639868 :                 this->Node(NodeNum).MassFlowToLower += useMassFlowRate;
    8394             :             }
    8395      776068 :             for (int NodeNum = useInletStratNod + 1; NodeNum <= useOutletStratNode; ++NodeNum) {
    8396      639868 :                 this->Node(NodeNum).MassFlowFromUpper += useMassFlowRate;
    8397             :             }
    8398             : 
    8399      840146 :         } else if (useOutletStratNode < useInletStratNod) {
    8400             :             // Use-side flow is up
    8401     5127842 :             for (int NodeNum = useOutletStratNode; NodeNum <= useInletStratNod - 1; ++NodeNum) {
    8402     4613112 :                 this->Node(NodeNum).MassFlowFromLower += useMassFlowRate;
    8403             :             }
    8404     5127842 :             for (int NodeNum = useOutletStratNode + 1; NodeNum <= useInletStratNod; ++NodeNum) {
    8405     4613112 :                 this->Node(NodeNum).MassFlowToUpper += useMassFlowRate;
    8406             :             }
    8407             : 
    8408             :         } else {
    8409             :             // Use-side flow is across the node; no flow to other nodes
    8410             :         }
    8411             :     }
    8412             : 
    8413     1340033 :     if (sourceMassFlowRate > 0.0) {
    8414      298591 :         if (sourceOutletStratNode > sourceInletStratNode) {
    8415             :             // Source-side flow is down
    8416      672770 :             for (int NodeNum = sourceInletStratNode; NodeNum <= sourceOutletStratNode - 1; ++NodeNum) {
    8417      574385 :                 this->Node(NodeNum).MassFlowToLower += sourceMassFlowRate;
    8418             :             }
    8419      672770 :             for (int NodeNum = sourceInletStratNode + 1; NodeNum <= sourceOutletStratNode; ++NodeNum) {
    8420      574385 :                 this->Node(NodeNum).MassFlowFromUpper += sourceMassFlowRate;
    8421             :             }
    8422             : 
    8423      200206 :         } else if (sourceOutletStratNode < sourceInletStratNode) {
    8424             :             // Source-side flow is up
    8425     1121921 :             for (int NodeNum = sourceOutletStratNode; NodeNum <= sourceInletStratNode - 1; ++NodeNum) {
    8426      921715 :                 this->Node(NodeNum).MassFlowFromLower += sourceMassFlowRate;
    8427             :             }
    8428     1121921 :             for (int NodeNum = sourceOutletStratNode + 1; NodeNum <= sourceInletStratNode; ++NodeNum) {
    8429      921715 :                 this->Node(NodeNum).MassFlowToUpper += sourceMassFlowRate;
    8430             :             }
    8431             : 
    8432             :         } else {
    8433             :             // Source-side flow is across the node; no flow to other nodes
    8434             :         }
    8435             :     }
    8436             : 
    8437             :     // Cancel out any up and down flows
    8438    10615961 :     for (int NodeNum = 1; NodeNum <= this->Nodes; ++NodeNum) {
    8439     9275928 :         this->Node(NodeNum).MassFlowFromUpper = max((this->Node(NodeNum).MassFlowFromUpper - this->Node(NodeNum).MassFlowToUpper), 0.0);
    8440     9275928 :         this->Node(NodeNum).MassFlowFromLower = max((this->Node(NodeNum).MassFlowFromLower - this->Node(NodeNum).MassFlowToLower), 0.0);
    8441             :     }
    8442     1340033 : }
    8443             : 
    8444       29484 : void WaterThermalTankData::CalcDesuperheaterWaterHeater(EnergyPlusData &state, bool const FirstHVACIteration)
    8445             : {
    8446             : 
    8447             :     // SUBROUTINE INFORMATION:
    8448             :     //       AUTHOR         Richard Raustad
    8449             :     //       DATE WRITTEN   July 2005
    8450             :     //       MODIFIED       na
    8451             :     //       RE-ENGINEERED  na
    8452             : 
    8453             :     // PURPOSE OF THIS SUBROUTINE:
    8454             :     // Simulates a refrigerant desuperheater to heat water
    8455             : 
    8456             :     // METHODOLOGY EMPLOYED:
    8457             :     // This model uses the rated heat reclaim recovery efficiency, recovery efficiency modifier curve,
    8458             :     // set point temperature, and dead band temperature difference to simulate the desuperheater coil
    8459             :     // and sets up inputs to the tank model associated with the desuperheater coil
    8460             : 
    8461       29484 :     int constexpr MaxIte(500); // Maximum number of iterations for RegulaFalsi
    8462             : 
    8463       29484 :     auto &DesupHtr = state.dataWaterThermalTanks->WaterHeaterDesuperheater(this->DesuperheaterNum);
    8464             : 
    8465       29484 :     int WaterInletNode = DesupHtr.WaterInletNode;
    8466       29484 :     int WaterOutletNode = DesupHtr.WaterOutletNode;
    8467             : 
    8468             :     // store first iteration tank temperature and desuperheater mode of operation
    8469       29484 :     if (FirstHVACIteration && !state.dataHVACGlobal->ShortenTimeStepSys && DesupHtr.FirstTimeThroughFlag) {
    8470             :         // Save conditions from end of previous system timestep
    8471             :         // Every iteration that does not advance time should reset to these values
    8472       13796 :         this->SavedTankTemp = this->TankTemp;
    8473       13796 :         this->SavedSourceOutletTemp = this->SourceOutletTemp;
    8474       13796 :         DesupHtr.SaveMode = DesupHtr.Mode;
    8475       13796 :         DesupHtr.FirstTimeThroughFlag = false;
    8476             :     }
    8477             : 
    8478       15688 :     else if (!FirstHVACIteration) {
    8479       14742 :         DesupHtr.FirstTimeThroughFlag = true;
    8480             :     }
    8481             : 
    8482             :     // initialize variables before invoking any RETURN statement
    8483       29484 :     this->SourceMassFlowRate = 0.0;
    8484             :     // reset tank inlet temp from previous time step
    8485       29484 :     this->SourceInletTemp = this->SavedSourceOutletTemp;
    8486       29484 :     DesupHtr.DesuperheaterPLR = 0.0;
    8487             : 
    8488       29484 :     state.dataLoopNodes->Node(WaterInletNode).MassFlowRate = 0.0;
    8489       29484 :     state.dataLoopNodes->Node(WaterOutletNode).MassFlowRate = 0.0;
    8490       29484 :     state.dataLoopNodes->Node(WaterOutletNode).Temp = this->SavedSourceOutletTemp;
    8491             : 
    8492       29484 :     DesupHtr.DesuperheaterPLR = 0.0;
    8493       29484 :     DesupHtr.OnCycParaFuelRate = 0.0;
    8494       29484 :     DesupHtr.OnCycParaFuelEnergy = 0.0;
    8495       29484 :     DesupHtr.OffCycParaFuelRate = 0.0;
    8496       29484 :     DesupHtr.OffCycParaFuelEnergy = 0.0;
    8497       29484 :     DesupHtr.HEffFTempOutput = 0.0;
    8498       29484 :     DesupHtr.HeaterRate = 0.0;
    8499       29484 :     DesupHtr.HeaterEnergy = 0.0;
    8500       29484 :     DesupHtr.PumpPower = 0.0;
    8501       29484 :     DesupHtr.PumpEnergy = 0.0;
    8502             : 
    8503             :     // simulate only the water heater tank if the desuperheater coil is scheduled off
    8504       29484 :     Real64 AvailSchedule = ScheduleManager::GetCurrentScheduleValue(state, DesupHtr.AvailSchedPtr);
    8505       29484 :     if (AvailSchedule == 0.0) {
    8506           0 :         DesupHtr.Mode = TankOperatingMode::Floating;
    8507           0 :         this->CalcWaterThermalTank(state);
    8508       18199 :         return;
    8509             :     }
    8510             : 
    8511             :     // simulate only the water heater tank if the lowest temperature available from the desuperheater coil
    8512             :     // is less than water inlet temperature if the reclaim source is a refrigeration condenser
    8513       29484 :     if (DesupHtr.ValidSourceType) {
    8514       29484 :         int SourceID = DesupHtr.ReclaimHeatingSourceIndexNum;
    8515       29484 :         if (DesupHtr.ReclaimHeatingSource == ReclaimHeatObjectType::CondenserRefrigeration) {
    8516        4602 :             if (state.dataHeatBal->HeatReclaimRefrigCondenser(SourceID).AvailTemperature <= this->SourceInletTemp) {
    8517          24 :                 DesupHtr.Mode = TankOperatingMode::Floating;
    8518          24 :                 this->CalcWaterThermalTank(state);
    8519          72 :                 ShowRecurringWarningErrorAtEnd(state,
    8520          48 :                                                "WaterHeating:Desuperheater " + DesupHtr.Name +
    8521             :                                                    " - Waste heat source temperature was too low to be useful.",
    8522          24 :                                                DesupHtr.InsuffTemperatureWarn);
    8523          24 :                 return;
    8524             :             } // Temp too low
    8525             :         }     // desuperheater source is condenser_refrigeration
    8526             :     }         // validsourcetype
    8527             : 
    8528       29460 :     DesupHtr.OffCycParaFuelRate = DesupHtr.OffCycParaLoad;
    8529       29460 :     DesupHtr.OffCycParaFuelEnergy = DesupHtr.OffCycParaFuelRate * state.dataHVACGlobal->TimeStepSysSec;
    8530             : 
    8531             :     // check that water heater tank cut-in temp is greater than desuperheater cut-in temp
    8532       29460 :     Real64 desupHtrSetPointTemp = DesupHtr.SetPointTemp;
    8533       29460 :     Real64 DeadBandTempDiff = DesupHtr.DeadBandTempDiff;
    8534       29460 :     if ((desupHtrSetPointTemp - DeadBandTempDiff) <= this->SetPointTemp) {
    8535           4 :         if (!state.dataGlobal->WarmupFlag && !state.dataGlobal->DoingSizing && !state.dataGlobal->KickOffSimulation) {
    8536           0 :             Real64 MinTemp = desupHtrSetPointTemp - DeadBandTempDiff;
    8537           0 :             ++DesupHtr.SetPointError;
    8538           0 :             if (DesupHtr.SetPointError < 5) {
    8539           0 :                 ShowWarningError(state,
    8540           0 :                                  format("{} \"{}\":  Water heater tank set point temperature is greater than or equal to the cut-in temperature of "
    8541             :                                         "the desuperheater. Desuperheater will be disabled.",
    8542           0 :                                         DesupHtr.Type,
    8543           0 :                                         DesupHtr.Name));
    8544           0 :                 ShowContinueErrorTimeStamp(state, format(" ...Desuperheater cut-in temperature = {:.2R}", MinTemp));
    8545             :             } else {
    8546           0 :                 ShowRecurringWarningErrorAtEnd(state,
    8547           0 :                                                DesupHtr.Type + " \"" + DesupHtr.Name +
    8548             :                                                    "\":  Water heater tank set point temperature is greater than or equal to the cut-in "
    8549             :                                                    "temperature of the desuperheater. Desuperheater will be disabled warning continues...",
    8550           0 :                                                DesupHtr.SetPointErrIndex1,
    8551             :                                                MinTemp,
    8552             :                                                MinTemp);
    8553             :             }
    8554             :         }
    8555             : 
    8556             :         //   Simulate tank if desuperheater unavailable for water heating
    8557           4 :         this->CalcWaterThermalTank(state);
    8558           4 :         return;
    8559             :     }
    8560             : 
    8561       29456 :     Real64 Effic = DesupHtr.HeatReclaimRecoveryEff;
    8562             : 
    8563       29456 :     state.dataLoopNodes->Node(WaterInletNode).Temp = this->SavedSourceOutletTemp;
    8564       29456 :     DesupHtr.Mode = DesupHtr.SaveMode;
    8565             : 
    8566             :     Real64 HEffFTemp;
    8567       29456 :     if (DesupHtr.HEffFTemp > 0) {
    8568       29456 :         HEffFTemp = max(0.0, Curve::CurveValue(state, DesupHtr.HEffFTemp, this->SavedTankTemp, state.dataEnvrn->OutDryBulbTemp));
    8569             :     } else {
    8570           0 :         HEffFTemp = 1.0;
    8571             :     }
    8572             : 
    8573             :     // set limits on heat recovery efficiency
    8574       29456 :     if (DesupHtr.ReclaimHeatingSource == ReclaimHeatObjectType::CondenserRefrigeration) {
    8575        4578 :         if ((HEffFTemp * Effic) > 0.9) HEffFTemp = 0.9 / Effic;
    8576             :     } else { // max is 0.3 for all other sources
    8577       24878 :         if ((HEffFTemp * Effic) > 0.3) HEffFTemp = 0.3 / Effic;
    8578             :     } // setting limits on heat recovery efficiency
    8579             : 
    8580             :     // Access the appropriate structure to find the average heating capacity of the desuperheater heating coil
    8581       29456 :     Real64 AverageWasteHeat = 0.0;
    8582       29456 :     if (DesupHtr.ValidSourceType) {
    8583       29456 :         int SourceID = DesupHtr.ReclaimHeatingSourceIndexNum;
    8584       29456 :         if (DesupHtr.ReclaimHeatingSource == ReclaimHeatObjectType::CompressorRackRefrigeratedCase) {
    8585             :             // Refrigeration systems are solved outside the time step iteration, so the
    8586             :             //  appropriate decrement for other waste heat applications is handled differently
    8587           0 :             AverageWasteHeat = state.dataHeatBal->HeatReclaimRefrigeratedRack(SourceID).AvailCapacity -
    8588           0 :                                state.dataHeatBal->HeatReclaimRefrigeratedRack(SourceID).HVACDesuperheaterReclaimedHeatTotal;
    8589           0 :             DesupHtr.DXSysPLR = 1.0;
    8590       29456 :         } else if (DesupHtr.ReclaimHeatingSource == ReclaimHeatObjectType::CondenserRefrigeration) {
    8591        4578 :             AverageWasteHeat = state.dataHeatBal->HeatReclaimRefrigCondenser(SourceID).AvailCapacity -
    8592        4578 :                                state.dataHeatBal->HeatReclaimRefrigCondenser(SourceID).HVACDesuperheaterReclaimedHeatTotal;
    8593        4578 :             DesupHtr.DXSysPLR = 1.0;
    8594       24878 :         } else if (DesupHtr.ReclaimHeatingSource == ReclaimHeatObjectType::DXCooling ||
    8595       12978 :                    DesupHtr.ReclaimHeatingSource == ReclaimHeatObjectType::DXMultiSpeed ||
    8596       12978 :                    DesupHtr.ReclaimHeatingSource == ReclaimHeatObjectType::DXMultiMode) {
    8597       11900 :             AverageWasteHeat = state.dataHeatBal->HeatReclaimDXCoil(SourceID).AvailCapacity -
    8598       11900 :                                state.dataHeatBal->HeatReclaimDXCoil(SourceID).HVACDesuperheaterReclaimedHeatTotal;
    8599       11900 :             DesupHtr.DXSysPLR = state.dataDXCoils->DXCoil(SourceID).PartLoadRatio;
    8600       12978 :         } else if (DesupHtr.ReclaimHeatingSource == ReclaimHeatObjectType::DXVariableCooling) {
    8601        3782 :             AverageWasteHeat = state.dataHeatBal->HeatReclaimVS_DXCoil(SourceID).AvailCapacity -
    8602        3782 :                                state.dataHeatBal->HeatReclaimVS_DXCoil(SourceID).HVACDesuperheaterReclaimedHeatTotal;
    8603        3782 :             DesupHtr.DXSysPLR = state.dataVariableSpeedCoils->VarSpeedCoil(SourceID).PartLoadRatio;
    8604        9196 :         } else if (DesupHtr.ReclaimHeatingSource == ReclaimHeatObjectType::AirWaterHeatPumpEQ) {
    8605        3246 :             AverageWasteHeat = state.dataHeatBal->HeatReclaimSimple_WAHPCoil(SourceID).AvailCapacity -
    8606        3246 :                                state.dataHeatBal->HeatReclaimSimple_WAHPCoil(SourceID).HVACDesuperheaterReclaimedHeatTotal;
    8607        3246 :             DesupHtr.DXSysPLR = state.dataWaterToAirHeatPumpSimple->SimpleWatertoAirHP(SourceID).PartLoadRatio;
    8608        5950 :         } else if (DesupHtr.ReclaimHeatingSource == ReclaimHeatObjectType::CoilCoolingDX) {
    8609        5950 :             AverageWasteHeat =
    8610        5950 :                 state.dataCoilCooingDX->coilCoolingDXs[DesupHtr.ReclaimHeatingSourceIndexNum].reclaimHeat.AvailCapacity -
    8611        5950 :                 state.dataCoilCooingDX->coilCoolingDXs[DesupHtr.ReclaimHeatingSourceIndexNum].reclaimHeat.HVACDesuperheaterReclaimedHeatTotal;
    8612        5950 :             DesupHtr.DXSysPLR = state.dataCoilCooingDX->coilCoolingDXs[DesupHtr.ReclaimHeatingSourceIndexNum].partLoadRatioReport;
    8613             :         }
    8614             :     } else {
    8615           0 :         AverageWasteHeat = 0.0;
    8616             :     }
    8617             : 
    8618             :     // simulate only water heater tank if reclaim heating source is off
    8619       29456 :     if (DesupHtr.DXSysPLR == 0.0) {
    8620       18171 :         this->CalcWaterThermalTank(state);
    8621       18171 :         return;
    8622             :     }
    8623             : 
    8624             :     // If the set point is higher than the maximum water temp, reset both the set point and the dead band temperature difference
    8625       11285 :     if (desupHtrSetPointTemp > DesupHtr.MaxInletWaterTemp) {
    8626       11285 :         Real64 CutInTemp = desupHtrSetPointTemp - DeadBandTempDiff;
    8627       11285 :         desupHtrSetPointTemp = DesupHtr.MaxInletWaterTemp;
    8628       11285 :         DeadBandTempDiff = max(0.0, (desupHtrSetPointTemp - CutInTemp));
    8629             :     }
    8630             : 
    8631             :     Real64 Acc; // Accuracy of result from RegulaFalsi
    8632       11285 :     if (DesupHtr.TankTypeNum == DataPlant::PlantEquipmentType::WtrHeaterStratified) {
    8633         951 :         Acc = 0.001;
    8634             :     } else {
    8635       10334 :         Acc = 0.00001;
    8636             :     }
    8637             : 
    8638             :     // set the water-side mass flow rate
    8639       11285 :     Real64 CpWater = Psychrometrics::CPHW(state.dataLoopNodes->Node(WaterInletNode).Temp);
    8640       11285 :     Real64 MdotWater = DesupHtr.OperatingWaterFlowRate * Psychrometrics::RhoH2O(state.dataLoopNodes->Node(WaterInletNode).Temp);
    8641       11285 :     Real64 QHeatRate = 0.0;
    8642       11285 :     if (state.dataLoopNodes->Node(WaterInletNode).Temp <= DesupHtr.MaxInletWaterTemp + Acc) {
    8643       10099 :         QHeatRate = ((AverageWasteHeat * Effic * HEffFTemp) / DesupHtr.DXSysPLR) + (DesupHtr.PumpElecPower * DesupHtr.PumpFracToWater);
    8644             :     }
    8645             : 
    8646             :     // change to tanktypenum using parameters?
    8647       11285 :     Real64 partLoadRatio = 0.0;
    8648             :     Real64 NewTankTemp;
    8649             :     {
    8650       11285 :         DataPlant::PlantEquipmentType const TankType = DesupHtr.TankTypeNum;
    8651             : 
    8652       11285 :         if (TankType == DataPlant::PlantEquipmentType::WtrHeaterMixed || TankType == DataPlant::PlantEquipmentType::WtrHeaterStratified) {
    8653             : 
    8654       11285 :             DesupHtr.SaveWHMode = this->Mode;
    8655       11285 :             Real64 PreTankAvgTemp = this->TankTempAvg;
    8656       11285 :             Real64 NewTankAvgTemp = 0.0; // Initialization
    8657       11285 :             int max_count = 200;
    8658       11285 :             int count = 0;
    8659       11285 :             bool firstThrough = true;
    8660       11285 :             switch (DesupHtr.Mode) {
    8661       10391 :             case TankOperatingMode::Heating:
    8662             :                 // Calculate until consistency of desuperheater and tank source side energy transfer achieved
    8663       30514 :                 while ((std::abs(PreTankAvgTemp - NewTankAvgTemp) > HVAC::SmallTempDiff || firstThrough) && count < max_count) {
    8664       20123 :                     count++;
    8665       20123 :                     firstThrough = false;
    8666       20123 :                     PreTankAvgTemp = this->TankTempAvg;
    8667       20123 :                     partLoadRatio = DesupHtr.DXSysPLR;
    8668       20123 :                     if (MdotWater > 0.0) {
    8669       20123 :                         state.dataLoopNodes->Node(WaterOutletNode).Temp = this->SourceOutletTemp + QHeatRate / (MdotWater * CpWater);
    8670             :                     } else {
    8671           0 :                         state.dataLoopNodes->Node(WaterOutletNode).Temp = this->SourceOutletTemp;
    8672             :                     }
    8673             : 
    8674             :                     //         set the full load outlet temperature on the water heater source inlet node (init has already been called)
    8675       20123 :                     this->SourceInletTemp = state.dataLoopNodes->Node(WaterOutletNode).Temp;
    8676             : 
    8677             :                     //         set the source mass flow rate for the tank
    8678       20123 :                     this->SourceMassFlowRate = MdotWater * partLoadRatio;
    8679             : 
    8680       20123 :                     this->MaxCapacity = DesupHtr.BackupElementCapacity;
    8681       20123 :                     this->MinCapacity = DesupHtr.BackupElementCapacity;
    8682       20123 :                     DesupHtr.DesuperheaterPLR = partLoadRatio;
    8683       20123 :                     DesupHtr.HeaterRate = QHeatRate * partLoadRatio;
    8684       20123 :                     this->CalcWaterThermalTank(state);
    8685       20123 :                     Real64 NewTankTemp = this->TankTemp;
    8686             : 
    8687       20123 :                     if (NewTankTemp > desupHtrSetPointTemp) {
    8688             :                         //           Only revert to floating mode if the tank temperature is higher than the cut out temperature
    8689        6809 :                         if (NewTankTemp > DesupHtr.SetPointTemp) {
    8690           0 :                             DesupHtr.Mode = TankOperatingMode::Floating;
    8691             :                         }
    8692             :                         int SolFla;
    8693        6809 :                         std::string IterNum;
    8694       54454 :                         auto f = [&state, this, desupHtrSetPointTemp, &DesupHtr, MdotWater](Real64 const HPPartLoadRatio) {
    8695       27227 :                             this->Mode = DesupHtr.SaveWHMode;
    8696       27227 :                             this->SourceMassFlowRate = MdotWater * HPPartLoadRatio;
    8697       27227 :                             this->CalcWaterThermalTank(state);
    8698       27227 :                             Real64 NewTankTemp = this->TankTemp;
    8699       27227 :                             Real64 PLRResidualWaterThermalTank = desupHtrSetPointTemp - NewTankTemp;
    8700       27227 :                             return PLRResidualWaterThermalTank;
    8701        6809 :                         };
    8702        6809 :                         General::SolveRoot(state, Acc, MaxIte, SolFla, partLoadRatio, f, 0.0, DesupHtr.DXSysPLR);
    8703        6809 :                         if (SolFla == -1) {
    8704           0 :                             IterNum = fmt::to_string(MaxIte);
    8705           0 :                             if (!state.dataGlobal->WarmupFlag) {
    8706           0 :                                 ++DesupHtr.IterLimitExceededNum1;
    8707           0 :                                 if (DesupHtr.IterLimitExceededNum1 == 1) {
    8708           0 :                                     ShowWarningError(state, format("{} \"{}\"", DesupHtr.Type, DesupHtr.Name));
    8709           0 :                                     ShowContinueError(state,
    8710           0 :                                                       format("Iteration limit exceeded calculating desuperheater unit part-load ratio, "
    8711             :                                                              "maximum iterations = {}. Part-load ratio returned = {:.3R}",
    8712             :                                                              IterNum,
    8713             :                                                              partLoadRatio));
    8714           0 :                                     ShowContinueErrorTimeStamp(state, "This error occurred in heating mode.");
    8715             :                                 } else {
    8716           0 :                                     ShowRecurringWarningErrorAtEnd(state,
    8717           0 :                                                                    DesupHtr.Type + " \"" + DesupHtr.Name +
    8718             :                                                                        "\":  Iteration limit exceeded in heating mode warning continues. "
    8719             :                                                                        "Part-load ratio statistics follow.",
    8720           0 :                                                                    DesupHtr.IterLimitErrIndex1,
    8721             :                                                                    partLoadRatio,
    8722             :                                                                    partLoadRatio);
    8723             :                                 }
    8724             :                             }
    8725        6809 :                         } else if (SolFla == -2) {
    8726           0 :                             partLoadRatio =
    8727           0 :                                 max(0.0, min(DesupHtr.DXSysPLR, (desupHtrSetPointTemp - this->SavedTankTemp) / (NewTankTemp - this->SavedTankTemp)));
    8728           0 :                             this->SourceMassFlowRate = MdotWater * partLoadRatio;
    8729           0 :                             this->CalcWaterThermalTank(state);
    8730           0 :                             if (!state.dataGlobal->WarmupFlag) {
    8731           0 :                                 ++DesupHtr.RegulaFalsiFailedNum1;
    8732           0 :                                 if (DesupHtr.RegulaFalsiFailedNum1 == 1) {
    8733           0 :                                     ShowWarningError(state, format("{} \"{}\"", DesupHtr.Type, DesupHtr.Name));
    8734           0 :                                     ShowContinueError(state,
    8735           0 :                                                       format("Desuperheater unit part-load ratio calculation failed: PLR limits of 0 to 1 "
    8736             :                                                              "exceeded. Part-load ratio used = {:.3R}",
    8737             :                                                              partLoadRatio));
    8738           0 :                                     ShowContinueError(state, "Please send this information to the EnergyPlus support group.");
    8739           0 :                                     ShowContinueErrorTimeStamp(state, "This error occurred in heating mode.");
    8740             :                                 } else {
    8741           0 :                                     ShowRecurringWarningErrorAtEnd(state,
    8742           0 :                                                                    DesupHtr.Type + " \"" + DesupHtr.Name +
    8743             :                                                                        "\":  Part-load ratio calculation failed in heating mode warning "
    8744             :                                                                        "continues. Part-load ratio statistics follow.",
    8745           0 :                                                                    DesupHtr.RegulaFalsiFailedIndex1,
    8746             :                                                                    partLoadRatio,
    8747             :                                                                    partLoadRatio);
    8748             :                                 }
    8749             :                             }
    8750             :                         }
    8751        6809 :                     } else {
    8752       13314 :                         partLoadRatio = DesupHtr.DXSysPLR;
    8753             :                     }
    8754       20123 :                     NewTankAvgTemp = this->TankTempAvg;
    8755             :                 }
    8756       10391 :                 break;
    8757         894 :             case TankOperatingMode::Floating:
    8758         894 :                 if (MdotWater > 0.0) {
    8759         894 :                     state.dataLoopNodes->Node(WaterOutletNode).Temp =
    8760         894 :                         state.dataLoopNodes->Node(WaterInletNode).Temp + QHeatRate / (MdotWater * CpWater);
    8761             :                 } else {
    8762           0 :                     state.dataLoopNodes->Node(WaterOutletNode).Temp = state.dataLoopNodes->Node(WaterInletNode).Temp;
    8763             :                 }
    8764             :                 //         check tank temperature by setting source inlet mass flow rate to zero
    8765         894 :                 partLoadRatio = 0.0;
    8766             : 
    8767             :                 //         set the full load outlet temperature on the water heater source inlet node (init has already been called)
    8768         894 :                 this->SourceInletTemp = state.dataLoopNodes->Node(WaterOutletNode).Temp;
    8769             : 
    8770             :                 //         check tank temperature by setting source inlet mass flow rate to zero
    8771         894 :                 this->SourceMassFlowRate = 0.0;
    8772             : 
    8773             :                 //         disable the tank heater to find PLR of the HPWH
    8774         894 :                 this->MaxCapacity = 0.0;
    8775         894 :                 this->MinCapacity = 0.0;
    8776         894 :                 DesupHtr.DesuperheaterPLR = partLoadRatio;
    8777         894 :                 DesupHtr.HeaterRate = QHeatRate * partLoadRatio;
    8778         894 :                 this->CalcWaterThermalTank(state);
    8779         894 :                 NewTankTemp = this->TankTemp;
    8780             : 
    8781         894 :                 if (NewTankTemp <= (desupHtrSetPointTemp - DeadBandTempDiff)) {
    8782          44 :                     this->Mode = DesupHtr.SaveWHMode;
    8783          44 :                     if ((this->SavedTankTemp - NewTankTemp) != 0.0) {
    8784          44 :                         partLoadRatio =
    8785          44 :                             min(DesupHtr.DXSysPLR,
    8786          44 :                                 max(0.0, ((desupHtrSetPointTemp - DeadBandTempDiff) - NewTankTemp) / (this->SavedTankTemp - NewTankTemp)));
    8787             :                     } else {
    8788           0 :                         partLoadRatio = DesupHtr.DXSysPLR;
    8789             :                     }
    8790         201 :                     while ((std::abs(PreTankAvgTemp - NewTankAvgTemp) > HVAC::SmallTempDiff || firstThrough) && count < max_count) {
    8791         157 :                         count++;
    8792         157 :                         firstThrough = false;
    8793         157 :                         PreTankAvgTemp = this->TankTempAvg;
    8794         157 :                         DesupHtr.Mode = TankOperatingMode::Heating;
    8795         157 :                         if (MdotWater > 0.0) {
    8796         157 :                             state.dataLoopNodes->Node(WaterOutletNode).Temp = this->SourceOutletTemp + QHeatRate / (MdotWater * CpWater);
    8797             :                         } else {
    8798           0 :                             state.dataLoopNodes->Node(WaterOutletNode).Temp = this->SourceOutletTemp;
    8799             :                         }
    8800             : 
    8801             :                         //           set the full load outlet temperature on the water heater source inlet node
    8802         157 :                         this->SourceInletTemp = state.dataLoopNodes->Node(WaterOutletNode).Temp;
    8803             : 
    8804             :                         //           set the source mass flow rate for the tank and enable backup heating element
    8805         157 :                         this->SourceMassFlowRate = MdotWater * partLoadRatio;
    8806         157 :                         this->MaxCapacity = DesupHtr.BackupElementCapacity;
    8807         157 :                         this->MinCapacity = DesupHtr.BackupElementCapacity;
    8808         157 :                         DesupHtr.DesuperheaterPLR = partLoadRatio;
    8809         157 :                         DesupHtr.HeaterRate = QHeatRate * partLoadRatio;
    8810         157 :                         this->CalcWaterThermalTank(state);
    8811         157 :                         NewTankTemp = this->TankTemp;
    8812             : 
    8813         157 :                         if (NewTankTemp > desupHtrSetPointTemp) {
    8814             :                             //           Only revert to floating mode if the tank temperature is higher than the cut-out temperature
    8815           0 :                             if (NewTankTemp > DesupHtr.SetPointTemp) {
    8816           0 :                                 DesupHtr.Mode = TankOperatingMode::Floating;
    8817             :                             }
    8818             :                             int SolFla;
    8819           0 :                             std::string IterNum;
    8820           0 :                             auto f = [&state, this, desupHtrSetPointTemp, &DesupHtr, MdotWater](Real64 const HPPartLoadRatio) {
    8821           0 :                                 this->Mode = DesupHtr.SaveWHMode;
    8822           0 :                                 this->SourceMassFlowRate = MdotWater * HPPartLoadRatio;
    8823           0 :                                 this->CalcWaterThermalTank(state);
    8824           0 :                                 Real64 NewTankTemp = this->TankTemp;
    8825           0 :                                 Real64 PLRResidualWaterThermalTank = desupHtrSetPointTemp - NewTankTemp;
    8826           0 :                                 return PLRResidualWaterThermalTank;
    8827           0 :                             };
    8828           0 :                             General::SolveRoot(state, Acc, MaxIte, SolFla, partLoadRatio, f, 0.0, DesupHtr.DXSysPLR);
    8829           0 :                             if (SolFla == -1) {
    8830           0 :                                 IterNum = fmt::to_string(MaxIte);
    8831           0 :                                 if (!state.dataGlobal->WarmupFlag) {
    8832           0 :                                     ++DesupHtr.IterLimitExceededNum2;
    8833           0 :                                     if (DesupHtr.IterLimitExceededNum2 == 1) {
    8834           0 :                                         ShowWarningError(state, format("{} \"{}\"", DesupHtr.Type, DesupHtr.Name));
    8835           0 :                                         ShowContinueError(state,
    8836           0 :                                                           format("Iteration limit exceeded calculating desuperheater unit part-load ratio, "
    8837             :                                                                  "maximum iterations = {}. Part-load ratio returned = {:.3R}",
    8838             :                                                                  IterNum,
    8839             :                                                                  partLoadRatio));
    8840           0 :                                         ShowContinueErrorTimeStamp(state, "This error occurred in float mode.");
    8841             :                                     } else {
    8842           0 :                                         ShowRecurringWarningErrorAtEnd(state,
    8843           0 :                                                                        DesupHtr.Type + " \"" + DesupHtr.Name +
    8844             :                                                                            "\":  Iteration limit exceeded in float mode warning continues. "
    8845             :                                                                            "Part-load ratio statistics follow.",
    8846           0 :                                                                        DesupHtr.IterLimitErrIndex2,
    8847             :                                                                        partLoadRatio,
    8848             :                                                                        partLoadRatio);
    8849             :                                     }
    8850             :                                 }
    8851           0 :                             } else if (SolFla == -2) {
    8852           0 :                                 partLoadRatio = max(
    8853           0 :                                     0.0, min(DesupHtr.DXSysPLR, (desupHtrSetPointTemp - this->SavedTankTemp) / (NewTankTemp - this->SavedTankTemp)));
    8854           0 :                                 if (!state.dataGlobal->WarmupFlag) {
    8855           0 :                                     ++DesupHtr.RegulaFalsiFailedNum2;
    8856           0 :                                     if (DesupHtr.RegulaFalsiFailedNum2 == 1) {
    8857           0 :                                         ShowWarningError(state, format("{} \"{}\"", DesupHtr.Type, DesupHtr.Name));
    8858           0 :                                         ShowContinueError(state,
    8859           0 :                                                           format("Desuperheater unit part-load ratio calculation failed: PLR limits of 0 to "
    8860             :                                                                  "1 exceeded. Part-load ratio used = {:.3R}",
    8861             :                                                                  partLoadRatio));
    8862           0 :                                         ShowContinueError(state, "Please send this information to the EnergyPlus support group.");
    8863           0 :                                         ShowContinueErrorTimeStamp(state, "This error occurred in float mode.");
    8864             :                                     } else {
    8865           0 :                                         ShowRecurringWarningErrorAtEnd(
    8866             :                                             state,
    8867           0 :                                             DesupHtr.Type + " \"" + DesupHtr.Name +
    8868             :                                                 "\": Part-load ratio calculation failed in float mode warning "
    8869             :                                                 "continues. Part-load ratio statistics follow.",
    8870           0 :                                             state.dataWaterThermalTanks->WaterHeaterDesuperheater(DesuperheaterNum).RegulaFalsiFailedIndex2,
    8871             :                                             partLoadRatio,
    8872             :                                             partLoadRatio);
    8873             :                                     }
    8874             :                                 }
    8875             :                             }
    8876           0 :                         }
    8877         157 :                         NewTankAvgTemp = this->TankTempAvg;
    8878             :                     }
    8879             :                 } else {
    8880         850 :                     this->MaxCapacity = DesupHtr.BackupElementCapacity;
    8881         850 :                     this->MinCapacity = DesupHtr.BackupElementCapacity;
    8882             :                 }
    8883         894 :                 break;
    8884           0 :             default:
    8885           0 :                 break;
    8886             :             }
    8887             : 
    8888             :             //   should never get here, case is checked in GetWaterThermalTankInput
    8889       11285 :         } else {
    8890           0 :             ShowFatalError(state,
    8891           0 :                            format("Coil:WaterHeating:Desuperheater = {}:  invalid water heater tank type and name entered = {}, {}",
    8892           0 :                                   state.dataWaterThermalTanks->WaterHeaterDesuperheater(DesuperheaterNum).Name,
    8893           0 :                                   state.dataWaterThermalTanks->WaterHeaterDesuperheater(DesuperheaterNum).TankType,
    8894           0 :                                   state.dataWaterThermalTanks->WaterHeaterDesuperheater(DesuperheaterNum).TankName));
    8895             :         }
    8896             :     }
    8897             : 
    8898       11285 :     if (QHeatRate == 0) partLoadRatio = 0.0;
    8899             : 
    8900       11285 :     state.dataLoopNodes->Node(WaterOutletNode).MassFlowRate = MdotWater * partLoadRatio;
    8901       11285 :     DesupHtr.HEffFTempOutput = HEffFTemp;
    8902       11285 :     DesupHtr.HeaterRate = QHeatRate * partLoadRatio;
    8903       11285 :     this->SourceMassFlowRate = MdotWater * partLoadRatio;
    8904             : 
    8905       11285 :     if (partLoadRatio == 0) {
    8906        1186 :         this->SourceInletTemp = this->SourceOutletTemp;
    8907        1186 :         state.dataLoopNodes->Node(WaterOutletNode).Temp = this->SourceOutletTemp;
    8908        1186 :         DesupHtr.HEffFTempOutput = 0.0;
    8909        1186 :         DesupHtr.HeaterRate = 0.0;
    8910             :     }
    8911             : 
    8912       11285 :     DesupHtr.HeaterEnergy = DesupHtr.HeaterRate * state.dataHVACGlobal->TimeStepSysSec;
    8913       11285 :     DesupHtr.DesuperheaterPLR = partLoadRatio;
    8914       11285 :     DesupHtr.OnCycParaFuelRate = DesupHtr.OnCycParaLoad * partLoadRatio;
    8915       11285 :     DesupHtr.OnCycParaFuelEnergy = DesupHtr.OnCycParaFuelRate * state.dataHVACGlobal->TimeStepSysSec;
    8916       11285 :     DesupHtr.OffCycParaFuelRate = DesupHtr.OffCycParaLoad * (1 - partLoadRatio);
    8917       11285 :     DesupHtr.OffCycParaFuelEnergy = DesupHtr.OffCycParaFuelRate * state.dataHVACGlobal->TimeStepSysSec;
    8918       11285 :     DesupHtr.PumpPower = DesupHtr.PumpElecPower * (partLoadRatio);
    8919       11285 :     DesupHtr.PumpEnergy = DesupHtr.PumpPower * state.dataHVACGlobal->TimeStepSysSec;
    8920             : 
    8921             :     // Update used waste heat (just in case multiple users of waste heat use same source)
    8922       11285 :     if (DesupHtr.ValidSourceType) {
    8923       11285 :         int SourceID = DesupHtr.ReclaimHeatingSourceIndexNum;
    8924       11285 :         if (DesupHtr.ReclaimHeatingSource == ReclaimHeatObjectType::CompressorRackRefrigeratedCase) {
    8925           0 :             state.dataHeatBal->HeatReclaimRefrigeratedRack(SourceID).WaterHeatingDesuperheaterReclaimedHeat(DesuperheaterNum) = DesupHtr.HeaterRate;
    8926           0 :             state.dataHeatBal->HeatReclaimRefrigeratedRack(SourceID).WaterHeatingDesuperheaterReclaimedHeatTotal = 0.0;
    8927           0 :             for (auto &num : state.dataHeatBal->HeatReclaimRefrigeratedRack(SourceID).WaterHeatingDesuperheaterReclaimedHeat)
    8928           0 :                 state.dataHeatBal->HeatReclaimRefrigeratedRack(SourceID).WaterHeatingDesuperheaterReclaimedHeatTotal += num;
    8929       11285 :         } else if (DesupHtr.ReclaimHeatingSource == ReclaimHeatObjectType::CondenserRefrigeration) {
    8930        4578 :             state.dataHeatBal->HeatReclaimRefrigCondenser(SourceID).WaterHeatingDesuperheaterReclaimedHeat(DesuperheaterNum) = DesupHtr.HeaterRate;
    8931        4578 :             state.dataHeatBal->HeatReclaimRefrigCondenser(SourceID).WaterHeatingDesuperheaterReclaimedHeatTotal = 0.0;
    8932        9156 :             for (auto &num : state.dataHeatBal->HeatReclaimRefrigCondenser(SourceID).WaterHeatingDesuperheaterReclaimedHeat)
    8933        4578 :                 state.dataHeatBal->HeatReclaimRefrigCondenser(SourceID).WaterHeatingDesuperheaterReclaimedHeatTotal += num;
    8934        6707 :         } else if (DesupHtr.ReclaimHeatingSource == ReclaimHeatObjectType::DXCooling ||
    8935        4467 :                    DesupHtr.ReclaimHeatingSource == ReclaimHeatObjectType::DXMultiSpeed ||
    8936        4467 :                    DesupHtr.ReclaimHeatingSource == ReclaimHeatObjectType::DXMultiMode) {
    8937        2240 :             state.dataHeatBal->HeatReclaimDXCoil(SourceID).WaterHeatingDesuperheaterReclaimedHeat(DesuperheaterNum) = DesupHtr.HeaterRate;
    8938        2240 :             state.dataHeatBal->HeatReclaimDXCoil(SourceID).WaterHeatingDesuperheaterReclaimedHeatTotal = 0.0;
    8939        4480 :             for (auto &num : state.dataHeatBal->HeatReclaimDXCoil(SourceID).WaterHeatingDesuperheaterReclaimedHeat)
    8940        2240 :                 state.dataHeatBal->HeatReclaimDXCoil(SourceID).WaterHeatingDesuperheaterReclaimedHeatTotal += num;
    8941        6707 :         } else if (DesupHtr.ReclaimHeatingSource == ReclaimHeatObjectType::DXVariableCooling) {
    8942        2396 :             state.dataHeatBal->HeatReclaimVS_DXCoil(SourceID).WaterHeatingDesuperheaterReclaimedHeat(DesuperheaterNum) = DesupHtr.HeaterRate;
    8943        2396 :             state.dataHeatBal->HeatReclaimVS_DXCoil(SourceID).WaterHeatingDesuperheaterReclaimedHeatTotal = 0.0;
    8944        4792 :             for (auto &num : state.dataHeatBal->HeatReclaimVS_DXCoil(SourceID).WaterHeatingDesuperheaterReclaimedHeat)
    8945        2396 :                 state.dataHeatBal->HeatReclaimVS_DXCoil(SourceID).WaterHeatingDesuperheaterReclaimedHeatTotal += num;
    8946        2071 :         } else if (DesupHtr.ReclaimHeatingSource == ReclaimHeatObjectType::AirWaterHeatPumpEQ) {
    8947         951 :             state.dataHeatBal->HeatReclaimSimple_WAHPCoil(SourceID).WaterHeatingDesuperheaterReclaimedHeat(DesuperheaterNum) = DesupHtr.HeaterRate;
    8948         951 :             state.dataHeatBal->HeatReclaimSimple_WAHPCoil(SourceID).WaterHeatingDesuperheaterReclaimedHeatTotal = 0.0;
    8949        1902 :             for (auto &num : state.dataHeatBal->HeatReclaimSimple_WAHPCoil(SourceID).WaterHeatingDesuperheaterReclaimedHeat)
    8950         951 :                 state.dataHeatBal->HeatReclaimSimple_WAHPCoil(SourceID).WaterHeatingDesuperheaterReclaimedHeatTotal += num;
    8951        1120 :         } else if (DesupHtr.ReclaimHeatingSource == ReclaimHeatObjectType::CoilCoolingDX) {
    8952        1120 :             state.dataCoilCooingDX->coilCoolingDXs[DesupHtr.ReclaimHeatingSourceIndexNum].reclaimHeat.WaterHeatingDesuperheaterReclaimedHeat(
    8953        1120 :                 DesuperheaterNum) = DesupHtr.HeaterRate;
    8954        1120 :             state.dataCoilCooingDX->coilCoolingDXs[DesupHtr.ReclaimHeatingSourceIndexNum].reclaimHeat.WaterHeatingDesuperheaterReclaimedHeatTotal =
    8955             :                 0.0;
    8956        1120 :             for (auto &num :
    8957        3360 :                  state.dataCoilCooingDX->coilCoolingDXs[DesupHtr.ReclaimHeatingSourceIndexNum].reclaimHeat.WaterHeatingDesuperheaterReclaimedHeat)
    8958        1120 :                 state.dataCoilCooingDX->coilCoolingDXs[DesupHtr.ReclaimHeatingSourceIndexNum]
    8959        1120 :                     .reclaimHeat.WaterHeatingDesuperheaterReclaimedHeatTotal += num;
    8960             :         }
    8961             :     }
    8962             : }
    8963             : 
    8964      448686 : void WaterThermalTankData::CalcHeatPumpWaterHeater(EnergyPlusData &state, bool const FirstHVACIteration)
    8965             : {
    8966             : 
    8967             :     // SUBROUTINE INFORMATION:
    8968             :     //       AUTHOR         Richard Raustad
    8969             :     //       DATE WRITTEN   March 2005
    8970             :     //       MODIFIED       B. Griffith, Jan 2012 for stratified tank
    8971             :     //                        B. Shen 12/2014, add air-source variable-speed heat pump water heating
    8972             :     //       RE-ENGINEERED  na
    8973             : 
    8974             :     // PURPOSE OF THIS SUBROUTINE:
    8975             :     // Simulates a heat pump water heater
    8976             : 
    8977             :     // METHODOLOGY EMPLOYED:
    8978             :     // Simulate the water heater tank, DX coil, and fan to meet the water heating requirements.
    8979             : 
    8980      448686 :     int constexpr MaxIte(500);   // maximum number of iterations
    8981      448686 :     Real64 constexpr Acc(0.001); // Accuracy of result from RegulaFalsi
    8982             : 
    8983             :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    8984             :     Real64 MdotWater;                                                                         // mass flow rate of condenser water, kg/s
    8985      448686 :     IntegratedHeatPump::IHPOperationMode IHPMode(IntegratedHeatPump::IHPOperationMode::Idle); // IHP working mode
    8986             : 
    8987             :     // References to objects used in this function
    8988      448686 :     HeatPumpWaterHeaterData &HeatPump = state.dataWaterThermalTanks->HPWaterHeater(this->HeatPumpNum);
    8989             : 
    8990             :     // initialize local variables
    8991      448686 :     int AvailSchedule = ScheduleManager::GetCurrentScheduleValue(state, HeatPump.AvailSchedPtr);
    8992      448686 :     int HPAirInletNode = HeatPump.HeatPumpAirInletNode;
    8993      448686 :     int HPAirOutletNode = HeatPump.HeatPumpAirOutletNode;
    8994      448686 :     int OutdoorAirNode = HeatPump.OutsideAirNode;
    8995      448686 :     int ExhaustAirNode = HeatPump.ExhaustAirNode;
    8996      448686 :     int HPWaterInletNode = HeatPump.CondWaterInletNode;
    8997      448686 :     int HPWaterOutletNode = HeatPump.CondWaterOutletNode;
    8998      448686 :     int InletAirMixerNode = HeatPump.InletAirMixerNode;
    8999      448686 :     int OutletAirSplitterNode = HeatPump.OutletAirSplitterNode;
    9000      448686 :     int DXCoilAirInletNode = HeatPump.DXCoilAirInletNode;
    9001      448686 :     state.dataWaterThermalTanks->hpPartLoadRatio = 0.0;
    9002      448686 :     HVAC::CompressorOp compressorOp = HVAC::CompressorOp::Off; // DX compressor operation; 1=on, 0=off
    9003      448686 :     HeatPump.OnCycParaFuelRate = 0.0;
    9004      448686 :     HeatPump.OnCycParaFuelEnergy = 0.0;
    9005      448686 :     HeatPump.OffCycParaFuelRate = 0.0;
    9006      448686 :     HeatPump.OffCycParaFuelEnergy = 0.0;
    9007      448686 :     state.dataLoopNodes->Node(HPWaterOutletNode) = state.dataLoopNodes->Node(HPWaterInletNode);
    9008      448686 :     int MaxSpeedNum = HeatPump.NumofSpeed; // speed number of variable speed HPWH coil
    9009             : 
    9010             :     // assign set point temperature (cut-out) and dead band temp diff (cut-in = cut-out minus dead band temp diff)
    9011      448686 :     Real64 HPSetPointTemp = HeatPump.SetPointTemp;
    9012      448686 :     Real64 DeadBandTempDiff = HeatPump.DeadBandTempDiff;
    9013      448686 :     Real64 RhoWater = Psychrometrics::RhoH2O(HPSetPointTemp); // initialize
    9014             : 
    9015             :     // store first iteration tank temperature and HP mode of operation
    9016             :     // this code can be called more than once with FirstHVACIteration = .TRUE., use FirstTimeThroughFlag to control save
    9017      448686 :     if (FirstHVACIteration && !state.dataHVACGlobal->ShortenTimeStepSys && HeatPump.FirstTimeThroughFlag) {
    9018       63376 :         this->SavedTankTemp = this->TankTemp;
    9019       63376 :         HeatPump.SaveMode = HeatPump.Mode;
    9020       63376 :         HeatPump.SaveWHMode = this->Mode;
    9021       63376 :         HeatPump.FirstTimeThroughFlag = false;
    9022             :     }
    9023             : 
    9024      448686 :     if (!FirstHVACIteration) HeatPump.FirstTimeThroughFlag = true;
    9025             : 
    9026             :     // check if HPWH is off for some reason and simulate HPWH air- and water-side mass flow rates of 0
    9027             :     // simulate only water heater tank if HP compressor is scheduled off
    9028             :     //   simulate only water heater tank if HP compressor cut-out temperature is lower than the tank's cut-in temperature
    9029             :     //    simulate only water heater tank if HP inlet air temperature is below minimum temperature for HP compressor operation
    9030             :     //    if the tank maximum temperature limit is less than the HPWH set point temp, disable HPWH
    9031      448686 :     if (AvailSchedule == 0.0 || (HPSetPointTemp - DeadBandTempDiff) <= this->SetPointTemp ||
    9032      448686 :         state.dataHVACGlobal->HPWHInletDBTemp < HeatPump.MinAirTempForHPOperation ||
    9033      338494 :         state.dataHVACGlobal->HPWHInletDBTemp > HeatPump.MaxAirTempForHPOperation || HPSetPointTemp >= this->TankTempLimit ||
    9034      338494 :         (!HeatPump.AllowHeatingElementAndHeatPumpToRunAtSameTime && this->WaterThermalTankType == DataPlant::PlantEquipmentType::WtrHeaterMixed &&
    9035      897372 :          this->SavedMode == TankOperatingMode::Heating) ||
    9036      338494 :         (!HeatPump.AllowHeatingElementAndHeatPumpToRunAtSameTime &&
    9037      103940 :          this->WaterThermalTankType == DataPlant::PlantEquipmentType::WtrHeaterStratified && (this->SavedHeaterOn1 || this->SavedHeaterOn2))) {
    9038             :         //   revert to float mode any time HPWH compressor is OFF
    9039      112312 :         HeatPump.Mode = TankOperatingMode::Floating;
    9040      112312 :         if (InletAirMixerNode > 0) {
    9041           0 :             state.dataLoopNodes->Node(InletAirMixerNode) = state.dataLoopNodes->Node(HPAirInletNode);
    9042             :         }
    9043             :         //   pass node info and simulate crankcase heater
    9044      112312 :         if (MaxSpeedNum > 0) {
    9045       58228 :             int VSCoilNum = HeatPump.DXCoilNum;
    9046             : 
    9047       58228 :             if (HeatPump.bIsIHP) {
    9048        4976 :                 VSCoilNum = state.dataIntegratedHP->IntegratedHeatPumps(VSCoilNum).SCWHCoilIndex;
    9049             :             }
    9050             :             // set the SCWH mode
    9051       58228 :             Real64 SpeedRatio = 1.0; // speed ratio for interpolating between two speed levels
    9052       58228 :             int SpeedNum = 1;
    9053       58228 :             if (HeatPump.fanPlace == HVAC::FanPlace::BlowThru) {
    9054       58228 :                 state.dataFans->fans(HeatPump.FanNum)->simulate(state, FirstHVACIteration, _, _);
    9055             : 
    9056       58228 :                 this->SetVSHPWHFlowRates(state, HeatPump, SpeedNum, SpeedRatio, RhoWater, MdotWater, FirstHVACIteration);
    9057       58228 :                 if (HeatPump.bIsIHP)
    9058        4976 :                     VariableSpeedCoils::SimVariableSpeedCoils(state,
    9059             :                                                               "",
    9060             :                                                               VSCoilNum,
    9061             :                                                               HVAC::FanOp::Cycling,
    9062             :                                                               HVAC::CompressorOp::On,
    9063        4976 :                                                               state.dataWaterThermalTanks->hpPartLoadRatio,
    9064             :                                                               SpeedNum,
    9065             :                                                               SpeedRatio,
    9066             :                                                               0.0,
    9067             :                                                               0.0,
    9068             :                                                               1.0);
    9069             :                 else
    9070       53252 :                     VariableSpeedCoils::SimVariableSpeedCoils(state,
    9071             :                                                               HeatPump.DXCoilName,
    9072             :                                                               VSCoilNum,
    9073             :                                                               HVAC::FanOp::Cycling,
    9074             :                                                               HVAC::CompressorOp::On,
    9075       53252 :                                                               state.dataWaterThermalTanks->hpPartLoadRatio,
    9076             :                                                               SpeedNum,
    9077             :                                                               SpeedRatio,
    9078             :                                                               0.0,
    9079             :                                                               0.0,
    9080             :                                                               1.0);
    9081             :             } else {
    9082           0 :                 this->SetVSHPWHFlowRates(state, HeatPump, SpeedNum, SpeedRatio, RhoWater, MdotWater, FirstHVACIteration);
    9083           0 :                 if (HeatPump.bIsIHP)
    9084           0 :                     VariableSpeedCoils::SimVariableSpeedCoils(state,
    9085             :                                                               "",
    9086             :                                                               VSCoilNum,
    9087             :                                                               HVAC::FanOp::Cycling,
    9088             :                                                               HVAC::CompressorOp::On,
    9089           0 :                                                               state.dataWaterThermalTanks->hpPartLoadRatio,
    9090             :                                                               SpeedNum,
    9091             :                                                               SpeedRatio,
    9092             :                                                               0.0,
    9093             :                                                               0.0,
    9094             :                                                               1.0);
    9095             :                 else
    9096           0 :                     VariableSpeedCoils::SimVariableSpeedCoils(state,
    9097             :                                                               HeatPump.DXCoilName,
    9098             :                                                               VSCoilNum,
    9099             :                                                               HVAC::FanOp::Cycling,
    9100             :                                                               HVAC::CompressorOp::On,
    9101           0 :                                                               state.dataWaterThermalTanks->hpPartLoadRatio,
    9102             :                                                               SpeedNum,
    9103             :                                                               SpeedRatio,
    9104             :                                                               0.0,
    9105             :                                                               0.0,
    9106             :                                                               1.0);
    9107           0 :                 state.dataFans->fans(HeatPump.FanNum)->simulate(state, FirstHVACIteration, _, _);
    9108             :             }
    9109             : 
    9110             :             // set the DWH mode
    9111       58228 :             if (HeatPump.bIsIHP) {
    9112        4976 :                 VSCoilNum = state.dataIntegratedHP->IntegratedHeatPumps(HeatPump.DXCoilNum).DWHCoilIndex;
    9113             : 
    9114        4976 :                 if (VSCoilNum > 0) // if DWH coil exists
    9115             :                 {
    9116        4976 :                     if (HeatPump.fanPlace == HVAC::FanPlace::BlowThru) {
    9117        4976 :                         state.dataFans->fans(HeatPump.FanNum)->simulate(state, FirstHVACIteration, _, _);
    9118             : 
    9119        4976 :                         this->SetVSHPWHFlowRates(state, HeatPump, SpeedNum, SpeedRatio, RhoWater, MdotWater, FirstHVACIteration);
    9120        4976 :                         VariableSpeedCoils::SimVariableSpeedCoils(state,
    9121             :                                                                   "",
    9122             :                                                                   VSCoilNum,
    9123             :                                                                   HVAC::FanOp::Cycling,
    9124             :                                                                   HVAC::CompressorOp::On,
    9125        4976 :                                                                   state.dataWaterThermalTanks->hpPartLoadRatio,
    9126             :                                                                   SpeedNum,
    9127             :                                                                   SpeedRatio,
    9128             :                                                                   0.0,
    9129             :                                                                   0.0,
    9130             :                                                                   1.0);
    9131             :                     } else {
    9132           0 :                         this->SetVSHPWHFlowRates(state, HeatPump, SpeedNum, SpeedRatio, RhoWater, MdotWater, FirstHVACIteration);
    9133           0 :                         VariableSpeedCoils::SimVariableSpeedCoils(state,
    9134             :                                                                   "",
    9135             :                                                                   VSCoilNum,
    9136             :                                                                   HVAC::FanOp::Cycling,
    9137             :                                                                   HVAC::CompressorOp::On,
    9138           0 :                                                                   state.dataWaterThermalTanks->hpPartLoadRatio,
    9139             :                                                                   SpeedNum,
    9140             :                                                                   SpeedRatio,
    9141             :                                                                   0.0,
    9142             :                                                                   0.0,
    9143             :                                                                   1.0);
    9144           0 :                         state.dataFans->fans(HeatPump.FanNum)->simulate(state, FirstHVACIteration, _, _);
    9145             :                     }
    9146             :                 }
    9147             :             }
    9148             : 
    9149             :         } else {
    9150       54084 :             if (HeatPump.fanPlace == HVAC::FanPlace::BlowThru) {
    9151       51964 :                 state.dataFans->fans(HeatPump.FanNum)->simulate(state, FirstHVACIteration, _, _);
    9152             : 
    9153      103928 :                 DXCoils::SimDXCoil(state,
    9154             :                                    HeatPump.DXCoilName,
    9155             :                                    compressorOp,
    9156             :                                    FirstHVACIteration,
    9157       51964 :                                    HeatPump.DXCoilNum,
    9158             :                                    HVAC::FanOp::Cycling,
    9159       51964 :                                    state.dataWaterThermalTanks->hpPartLoadRatio);
    9160             :             } else {
    9161        4240 :                 DXCoils::SimDXCoil(state,
    9162             :                                    HeatPump.DXCoilName,
    9163             :                                    compressorOp,
    9164             :                                    FirstHVACIteration,
    9165        2120 :                                    HeatPump.DXCoilNum,
    9166             :                                    HVAC::FanOp::Cycling,
    9167        2120 :                                    state.dataWaterThermalTanks->hpPartLoadRatio);
    9168        2120 :                 state.dataFans->fans(HeatPump.FanNum)->simulate(state, FirstHVACIteration, _, _);
    9169             :             }
    9170             :         }
    9171             : 
    9172      112312 :         if (OutletAirSplitterNode > 0) {
    9173           0 :             state.dataLoopNodes->Node(HPAirOutletNode) = state.dataLoopNodes->Node(OutletAirSplitterNode);
    9174             :         }
    9175             : 
    9176             :         //   Simulate tank if HP compressor unavailable for water heating
    9177      112312 :         this->CalcWaterThermalTank(state);
    9178             : 
    9179             :         //   If HPWH compressor is available and unit is off for another reason, off-cycle parasitics are calculated
    9180      112312 :         if (AvailSchedule != 0) {
    9181      112312 :             HeatPump.OffCycParaFuelRate = HeatPump.OffCycParaLoad * (1.0 - state.dataWaterThermalTanks->hpPartLoadRatio);
    9182      112312 :             HeatPump.OffCycParaFuelEnergy = HeatPump.OffCycParaFuelRate * state.dataHVACGlobal->TimeStepSysSec;
    9183             :         }
    9184             : 
    9185             :         //   Warn if HPWH compressor cut-in temperature is less than the water heater tank's set point temp
    9186      112312 :         if (!state.dataGlobal->WarmupFlag && !state.dataGlobal->DoingSizing && !state.dataGlobal->KickOffSimulation) {
    9187       13656 :             if ((HPSetPointTemp - DeadBandTempDiff) <= this->SetPointTemp) {
    9188           0 :                 Real64 HPMinTemp = HPSetPointTemp - DeadBandTempDiff;
    9189           0 :                 const std::string HPMinTempChar = fmt::to_string(HPMinTemp);
    9190           0 :                 ++HeatPump.HPSetPointError;
    9191             :                 //  add logic for warmup, DataGlobals::KickOffSimulation and doing sizing here
    9192           0 :                 if (HeatPump.HPSetPointError == 1) {
    9193           0 :                     ShowWarningError(state,
    9194           0 :                                      format("{} \"{}:  Water heater tank set point temperature is greater than or equal to the cut-in temperature of "
    9195             :                                             "the heat pump water heater. Heat Pump will be disabled and simulation continues.",
    9196           0 :                                             HeatPump.Type,
    9197           0 :                                             HeatPump.Name));
    9198           0 :                     ShowContinueErrorTimeStamp(state, format(" ...Heat Pump cut-in temperature={}", HPMinTempChar));
    9199             :                 } else {
    9200           0 :                     ShowRecurringWarningErrorAtEnd(state,
    9201           0 :                                                    HeatPump.Type + " \"" + HeatPump.Name +
    9202             :                                                        ":  Water heater tank set point temperature is greater than or equal to the cut-in "
    9203             :                                                        "temperature of the heat pump water heater. Heat Pump will be disabled error continues...",
    9204           0 :                                                    HeatPump.HPSetPointErrIndex1,
    9205             :                                                    HPMinTemp,
    9206             :                                                    HPMinTemp);
    9207             :                 }
    9208           0 :             }
    9209             :         }
    9210      112312 :         return;
    9211             :     }
    9212      336374 :     Real64 savedTankTemp = this->SavedTankTemp;
    9213      336374 :     HeatPump.Mode = HeatPump.SaveMode;
    9214             : 
    9215      336374 :     RhoWater = Psychrometrics::RhoH2O(savedTankTemp); // update water density using tank temp
    9216             : 
    9217             :     // set the heat pump air- and water-side mass flow rate
    9218      336374 :     MdotWater = HeatPump.OperatingWaterFlowRate * Psychrometrics::RhoH2O(savedTankTemp);
    9219             : 
    9220             :     // Select mode of operation (float mode or heat mode) from last iteration.
    9221             :     // Determine if heating will occur this iteration and get an estimate of the PLR
    9222      336374 :     if (HeatPump.Mode == TankOperatingMode::Heating) {
    9223             :         // HPWH was heating last iteration and will continue to heat until the set point is reached
    9224      110083 :         state.dataWaterThermalTanks->hpPartLoadRatio = 1.0;
    9225      110083 :         if (savedTankTemp > HPSetPointTemp) { // tank set point temp may have been reduced since last iteration and float mode may be needed
    9226         202 :             HeatPump.Mode = TankOperatingMode::Floating;
    9227         202 :             state.dataWaterThermalTanks->hpPartLoadRatio = 0.0;
    9228             :             // check to see if HP needs to operate
    9229             :             // set the condenser inlet node temperature and full mass flow rate prior to calling the HPWH DX coil
    9230         202 :             if (HeatPump.HPWHTankType == DataPlant::PlantEquipmentType::WtrHeaterMixed) {
    9231         202 :                 state.dataLoopNodes->Node(HPWaterInletNode).Temp = savedTankTemp;
    9232         202 :                 state.dataLoopNodes->Node(HPWaterOutletNode).Temp = savedTankTemp;
    9233           0 :             } else if (HeatPump.HPWHTankType == DataPlant::PlantEquipmentType::WtrHeaterStratified) {
    9234           0 :                 state.dataLoopNodes->Node(HPWaterInletNode).Temp = this->SourceOutletTemp;
    9235           0 :                 state.dataLoopNodes->Node(HPWaterOutletNode).Temp = this->SourceInletTemp;
    9236             :             }
    9237         202 :             state.dataLoopNodes->Node(HPWaterInletNode).MassFlowRate = 0.0;
    9238         202 :             state.dataLoopNodes->Node(HPWaterOutletNode).MassFlowRate = 0.0;
    9239             : 
    9240             :             // Check tank temperature by setting source inlet mass flow rate to zero.
    9241         202 :             state.dataWaterThermalTanks->hpPartLoadRatio = 0.0;
    9242             : 
    9243             :             // Set the full load outlet temperature on the water heater source inlet node (init has already been called).
    9244         202 :             this->SourceInletTemp = state.dataLoopNodes->Node(HPWaterOutletNode).Temp;
    9245             : 
    9246             :             // Disable the tank's internal heating element to find PLR of the HPWH using floating temperatures.
    9247         202 :             this->MaxCapacity = 0.0;
    9248         202 :             this->MinCapacity = 0.0;
    9249         202 :             this->SourceMassFlowRate = 0.0; // disables heat pump for mixed tanks
    9250         202 :             Real64 SourceEffectivenessBackup = this->SourceEffectiveness;
    9251         202 :             this->SourceEffectiveness = 0.0; // disables heat pump for stratified tanks
    9252         202 :             this->CalcWaterThermalTank(state);
    9253         202 :             this->SourceEffectiveness = SourceEffectivenessBackup;
    9254         202 :             Real64 NewTankTemp = this->GetHPWHSensedTankTemp(state);
    9255             : 
    9256             :             // Reset the tank's internal heating element capacity.
    9257         202 :             this->MaxCapacity = HeatPump.BackupElementCapacity;
    9258         202 :             this->MinCapacity = HeatPump.BackupElementCapacity;
    9259             : 
    9260             :             // Check to see if the tank drifts below set point if no heating happens.
    9261         202 :             if (NewTankTemp <= (HPSetPointTemp - DeadBandTempDiff)) {
    9262             : 
    9263             :                 // HPWH is now in heating mode
    9264         100 :                 HeatPump.Mode = TankOperatingMode::Heating;
    9265             : 
    9266             :                 // Reset the water heater's mode (call above may have changed modes)
    9267         100 :                 this->Mode = HeatPump.SaveWHMode;
    9268             : 
    9269         100 :                 state.dataWaterThermalTanks->hpPartLoadRatio = 1.0;
    9270             :             }
    9271             :         } else { // or use side nodes may meet set point without need for heat pump compressor operation
    9272             :                  // check to see if HP needs to operate
    9273      109881 :             if (HeatPump.HPWHTankType == DataPlant::PlantEquipmentType::WtrHeaterMixed) {
    9274       32144 :                 state.dataLoopNodes->Node(HPWaterInletNode).Temp = savedTankTemp;
    9275       32144 :                 state.dataLoopNodes->Node(HPWaterOutletNode).Temp = savedTankTemp;
    9276       77737 :             } else if (HeatPump.HPWHTankType == DataPlant::PlantEquipmentType::WtrHeaterStratified) {
    9277       77737 :                 state.dataLoopNodes->Node(HPWaterInletNode).Temp = this->SourceOutletTemp;
    9278       77737 :                 state.dataLoopNodes->Node(HPWaterOutletNode).Temp = this->SourceInletTemp;
    9279             :             }
    9280             :             // Check tank temperature by setting source inlet mass flow rate to zero.
    9281      109881 :             state.dataLoopNodes->Node(HPWaterInletNode).MassFlowRate = 0.0;
    9282      109881 :             state.dataLoopNodes->Node(HPWaterOutletNode).MassFlowRate = 0.0;
    9283             : 
    9284      109881 :             state.dataWaterThermalTanks->hpPartLoadRatio = 0.0;
    9285             : 
    9286             :             // Set the full load outlet temperature on the water heater source inlet node (init has already been called).
    9287      109881 :             this->SourceInletTemp = state.dataLoopNodes->Node(HPWaterOutletNode).Temp;
    9288             : 
    9289             :             // Disable the tank's internal heating element to find PLR of the HPWH using floating temperatures.
    9290      109881 :             this->MaxCapacity = 0.0;
    9291      109881 :             this->MinCapacity = 0.0;
    9292      109881 :             this->SourceMassFlowRate = 0.0; // disables heat pump for mixed tanks
    9293      109881 :             Real64 SourceEffectivenessBackup = this->SourceEffectiveness;
    9294      109881 :             this->SourceEffectiveness = 0.0; // disables heat pump for stratified tanks
    9295      109881 :             this->CalcWaterThermalTank(state);
    9296      109881 :             this->SourceEffectiveness = SourceEffectivenessBackup;
    9297      109881 :             Real64 NewTankTemp = this->GetHPWHSensedTankTemp(state);
    9298             : 
    9299             :             // Reset the tank's internal heating element capacity.
    9300      109881 :             this->MaxCapacity = HeatPump.BackupElementCapacity;
    9301      109881 :             this->MinCapacity = HeatPump.BackupElementCapacity;
    9302             : 
    9303             :             // Check to see if the tank meets set point if no heating happens.
    9304      109881 :             if (NewTankTemp > HPSetPointTemp) {
    9305             : 
    9306             :                 // HPWH is now in floating mode
    9307           0 :                 HeatPump.Mode = TankOperatingMode::Floating;
    9308             : 
    9309             :             } else {
    9310             : 
    9311             :                 // HPWH remains in heating mode
    9312      109881 :                 state.dataWaterThermalTanks->hpPartLoadRatio = 1.0;
    9313             :             }
    9314             : 
    9315             :             // Reset the water heater's mode (call above may have changed modes)
    9316      109881 :             this->Mode = HeatPump.SaveWHMode;
    9317             :         }
    9318             :     } else {
    9319      226291 :         assert(HeatPump.Mode == TankOperatingMode::Floating);
    9320             :         // HPWH was floating last iteration and will continue to float until the cut-in temperature is reached
    9321             : 
    9322             :         // set the condenser inlet node temperature and full mass flow rate prior to calling the HPWH DX coil
    9323      226291 :         if (HeatPump.HPWHTankType == DataPlant::PlantEquipmentType::WtrHeaterMixed) {
    9324      104586 :             state.dataLoopNodes->Node(HPWaterInletNode).Temp = savedTankTemp;
    9325      104586 :             state.dataLoopNodes->Node(HPWaterOutletNode).Temp = savedTankTemp;
    9326      121705 :         } else if (HeatPump.HPWHTankType == DataPlant::PlantEquipmentType::WtrHeaterStratified) {
    9327      121705 :             state.dataLoopNodes->Node(HPWaterInletNode).Temp = this->SourceOutletTemp;
    9328      121705 :             state.dataLoopNodes->Node(HPWaterOutletNode).Temp = this->SourceInletTemp;
    9329             :         }
    9330      226291 :         state.dataLoopNodes->Node(HPWaterInletNode).MassFlowRate = 0.0;
    9331      226291 :         state.dataLoopNodes->Node(HPWaterOutletNode).MassFlowRate = 0.0;
    9332             : 
    9333             :         // Check tank temperature by setting source inlet mass flow rate to zero.
    9334      226291 :         state.dataWaterThermalTanks->hpPartLoadRatio = 0.0;
    9335             : 
    9336             :         // Set the full load outlet temperature on the water heater source inlet node (init has already been called).
    9337      226291 :         this->SourceInletTemp = state.dataLoopNodes->Node(HPWaterOutletNode).Temp;
    9338             : 
    9339             :         // Disable the tank's internal heating element to find PLR of the HPWH using floating temperatures.
    9340      226291 :         this->MaxCapacity = 0.0;
    9341      226291 :         this->MinCapacity = 0.0;
    9342      226291 :         this->SourceMassFlowRate = 0.0; // disables heat pump for mixed tanks
    9343      226291 :         Real64 SourceEffectivenessBackup = this->SourceEffectiveness;
    9344      226291 :         this->SourceEffectiveness = 0.0; // disables heat pump for stratified tanks
    9345      226291 :         this->CalcWaterThermalTank(state);
    9346      226291 :         this->SourceEffectiveness = SourceEffectivenessBackup;
    9347      226291 :         Real64 NewTankTemp = this->GetHPWHSensedTankTemp(state);
    9348             : 
    9349             :         // Reset the tank's internal heating element capacity.
    9350      226291 :         this->MaxCapacity = HeatPump.BackupElementCapacity;
    9351      226291 :         this->MinCapacity = HeatPump.BackupElementCapacity;
    9352             : 
    9353             :         // Check to see if the tank drifts below set point if no heating happens.
    9354      226291 :         if (NewTankTemp <= (HPSetPointTemp - DeadBandTempDiff)) {
    9355             : 
    9356             :             // HPWH is now in heating mode
    9357       45931 :             HeatPump.Mode = TankOperatingMode::Heating;
    9358             : 
    9359             :             // Reset the water heater's mode (call above may have changed modes)
    9360       45931 :             this->Mode = HeatPump.SaveWHMode;
    9361             : 
    9362       45931 :             state.dataWaterThermalTanks->hpPartLoadRatio = 1.0;
    9363             :         }
    9364             :     }
    9365             : 
    9366      336374 :     if (HeatPump.bIsIHP) // mark the water heating call, if existing
    9367             :     {
    9368        5070 :         if (state.dataIntegratedHP->IntegratedHeatPumps(HeatPump.DXCoilNum).CheckWHCall) {
    9369        2534 :             if (HeatPump.Mode == TankOperatingMode::Heating)
    9370        1258 :                 state.dataIntegratedHP->IntegratedHeatPumps(HeatPump.DXCoilNum).IsWHCallAvail = true;
    9371             :             else
    9372        1276 :                 state.dataIntegratedHP->IntegratedHeatPumps(HeatPump.DXCoilNum).IsWHCallAvail = false;
    9373             :         }
    9374             :     }
    9375             : 
    9376             :     // If the HPWH was in heating mode during the last DataGlobals::TimeStep or if it was determined that
    9377             :     // heating would be needed during this DataGlobals::TimeStep to maintain setpoint, do the heating calculation.
    9378      336374 :     int SpeedNum = 0;
    9379      336374 :     Real64 SpeedRatio = 0.0;
    9380      336374 :     if (HeatPump.Mode == TankOperatingMode::Heating) {
    9381             : 
    9382             :         // set up air flow on DX coil inlet node
    9383      155912 :         state.dataLoopNodes->Node(DXCoilAirInletNode).MassFlowRate =
    9384      155912 :             state.dataWaterThermalTanks->mdotAir * state.dataWaterThermalTanks->hpPartLoadRatio;
    9385             : 
    9386             :         // set the condenser inlet node mass flow rate prior to calling the DXCoils::CalcHPWHDXCoil
    9387      155912 :         state.dataLoopNodes->Node(HPWaterInletNode).MassFlowRate = MdotWater * state.dataWaterThermalTanks->hpPartLoadRatio;
    9388      155912 :         this->SourceMassFlowRate = MdotWater * state.dataWaterThermalTanks->hpPartLoadRatio;
    9389             : 
    9390             :         // Do the coil and tank calculations at full PLR to see if it overshoots setpoint.
    9391      155912 :         bool bIterSpeed = false;
    9392      155912 :         if (MaxSpeedNum > 0) { // lowest speed of VS HPWH coil
    9393       22227 :             SpeedRatio = 1.0;
    9394       22227 :             state.dataWaterThermalTanks->hpPartLoadRatio = 1.0;
    9395       22227 :             bIterSpeed = true; // prepare for iterating between speed levels
    9396       22227 :             SpeedNum = 1;
    9397       22227 :             this->SetVSHPWHFlowRates(state, HeatPump, SpeedNum, SpeedRatio, RhoWater, MdotWater, FirstHVACIteration);
    9398             : 
    9399       22227 :             if (HeatPump.bIsIHP) {
    9400        2517 :                 bIterSpeed = false; // don't iterate speed unless match conditions below
    9401        2517 :                 IHPMode = IntegratedHeatPump::GetCurWorkMode(state, HeatPump.DXCoilNum);
    9402             : 
    9403        2517 :                 if (state.dataIntegratedHP->IntegratedHeatPumps(HeatPump.DXCoilNum).CheckWHCall) {
    9404             :                     int VSCoilNum;
    9405        1258 :                     if (IntegratedHeatPump::IHPOperationMode::DedicatedWaterHtg == IHPMode) {
    9406          48 :                         VSCoilNum = state.dataIntegratedHP->IntegratedHeatPumps(HeatPump.DXCoilNum).DWHCoilIndex;
    9407          48 :                         state.dataIntegratedHP->IntegratedHeatPumps(HeatPump.DXCoilNum).CurMode =
    9408             :                             IntegratedHeatPump::IHPOperationMode::DedicatedWaterHtg;
    9409             :                     } else {
    9410        1210 :                         VSCoilNum = state.dataIntegratedHP->IntegratedHeatPumps(HeatPump.DXCoilNum).SCWHCoilIndex;
    9411        1210 :                         state.dataIntegratedHP->IntegratedHeatPumps(HeatPump.DXCoilNum).CurMode = IntegratedHeatPump::IHPOperationMode::SCWHMatchWH;
    9412             :                     }
    9413             : 
    9414        1258 :                     this->SetVSHPWHFlowRates(state, HeatPump, SpeedNum, SpeedRatio, RhoWater, MdotWater, FirstHVACIteration);
    9415             : 
    9416        1258 :                     VariableSpeedCoils::SimVariableSpeedCoils(state,
    9417             :                                                               "",
    9418             :                                                               VSCoilNum,
    9419             :                                                               HVAC::FanOp::Cycling,
    9420             :                                                               HVAC::CompressorOp::On,
    9421        1258 :                                                               state.dataWaterThermalTanks->hpPartLoadRatio,
    9422             :                                                               SpeedNum,
    9423             :                                                               SpeedRatio,
    9424             :                                                               0.0,
    9425             :                                                               0.0,
    9426             :                                                               1.0);
    9427             : 
    9428        1258 :                     state.dataIntegratedHP->IntegratedHeatPumps(HeatPump.DXCoilNum).CurMode = IHPMode;
    9429        1258 :                     this->SetVSHPWHFlowRates(state, HeatPump, SpeedNum, SpeedRatio, RhoWater, MdotWater, FirstHVACIteration);
    9430             :                 } else {
    9431        1259 :                     SpeedNum = IntegratedHeatPump::GetLowSpeedNumIHP(state, HeatPump.DXCoilNum);
    9432             : 
    9433        1259 :                     this->SetVSHPWHFlowRates(state, HeatPump, SpeedNum, SpeedRatio, RhoWater, MdotWater, FirstHVACIteration);
    9434        1259 :                     IntegratedHeatPump::SimIHP(state,
    9435             :                                                HeatPump.DXCoilName,
    9436        1259 :                                                HeatPump.DXCoilNum,
    9437             :                                                HVAC::FanOp::Cycling,
    9438             :                                                HVAC::CompressorOp::On,
    9439        1259 :                                                state.dataWaterThermalTanks->hpPartLoadRatio,
    9440             :                                                SpeedNum,
    9441             :                                                SpeedRatio,
    9442             :                                                0.0,
    9443             :                                                0.0,
    9444             :                                                true,
    9445             :                                                false,
    9446        1259 :                                                1.0);
    9447             : 
    9448        1259 :                     if ((IntegratedHeatPump::IHPOperationMode::SCWHMatchWH == IHPMode) ||
    9449             :                         (IntegratedHeatPump::IHPOperationMode::DedicatedWaterHtg == IHPMode)) {
    9450         112 :                         bIterSpeed = true;
    9451             :                     } else {
    9452        1147 :                         this->SourceMassFlowRate = state.dataIntegratedHP->IntegratedHeatPumps(HeatPump.DXCoilNum).TankSourceWaterMassFlowRate;
    9453        1147 :                         MdotWater = this->SourceMassFlowRate;
    9454             :                     }
    9455             : 
    9456        1259 :                     if (IntegratedHeatPump::IHPOperationMode::SHDWHElecHeatOff == IHPMode) // turn off heater element
    9457             :                     {
    9458           0 :                         this->MaxCapacity = 0.0;
    9459           0 :                         this->MinCapacity = 0.0;
    9460             :                     }
    9461             :                 }
    9462             :             } else {
    9463       19710 :                 VariableSpeedCoils::SimVariableSpeedCoils(state,
    9464             :                                                           HeatPump.DXCoilName,
    9465       19710 :                                                           HeatPump.DXCoilNum,
    9466             :                                                           HVAC::FanOp::Cycling,
    9467             :                                                           HVAC::CompressorOp::On,
    9468       19710 :                                                           state.dataWaterThermalTanks->hpPartLoadRatio,
    9469             :                                                           SpeedNum,
    9470             :                                                           SpeedRatio,
    9471             :                                                           0.0,
    9472             :                                                           0.0,
    9473             :                                                           1.0);
    9474             :             }
    9475             : 
    9476       22227 :             this->CalcWaterThermalTank(state);
    9477             :         } else {
    9478      133685 :             this->ConvergeSingleSpeedHPWHCoilAndTank(state, state.dataWaterThermalTanks->hpPartLoadRatio);
    9479             :         }
    9480             : 
    9481      155912 :         Real64 NewTankTemp = this->GetHPWHSensedTankTemp(state);
    9482      155912 :         Real64 LowSpeedTankTemp = NewTankTemp;
    9483      155912 :         Real64 HPWHCondInletNodeLast = state.dataLoopNodes->Node(HPWaterInletNode).Temp;
    9484             : 
    9485      155912 :         if (NewTankTemp > HPSetPointTemp) {
    9486       11666 :             HeatPump.Mode = TankOperatingMode::Floating;
    9487       11666 :             TankOperatingMode tmpMode = HeatPump.SaveWHMode;
    9488       56526 :             auto f = [&state, this, HPSetPointTemp, tmpMode, MdotWater](Real64 const HPPartLoadRatio) {
    9489       56526 :                 return this->PLRResidualHPWH(state, HPPartLoadRatio, HPSetPointTemp, tmpMode, MdotWater);
    9490       11666 :             };
    9491       11666 :             Real64 zeroResidual = 1.0;
    9492       11666 :             if (MaxSpeedNum > 0) {
    9493             :                 // square the solving, and avoid warning
    9494             :                 // due to very small capacity at lowest speed of VSHPWH coil
    9495        1137 :                 if (bIterSpeed)
    9496        1121 :                     zeroResidual = this->PLRResidualHPWH(state, 0.0, HPSetPointTemp, tmpMode, MdotWater);
    9497             :                 else
    9498          16 :                     zeroResidual = -1.0;
    9499             :             }
    9500             : 
    9501       11666 :             if (zeroResidual > 0.0) { // then iteration
    9502             :                 int SolFla;
    9503       11317 :                 General::SolveRoot(state, Acc, MaxIte, SolFla, state.dataWaterThermalTanks->hpPartLoadRatio, f, 0.0, 1.0);
    9504       11317 :                 if (SolFla == -1) {
    9505           0 :                     std::string IterNum;
    9506           0 :                     IterNum = fmt::to_string(MaxIte);
    9507           0 :                     if (!state.dataGlobal->WarmupFlag) {
    9508           0 :                         ++HeatPump.IterLimitExceededNum2;
    9509           0 :                         if (HeatPump.IterLimitExceededNum2 == 1) {
    9510           0 :                             ShowWarningError(state, format("{} \"{}\"", HeatPump.Type, HeatPump.Name));
    9511           0 :                             ShowContinueError(state,
    9512           0 :                                               format("Iteration limit exceeded calculating heat pump water heater compressor part-load ratio, "
    9513             :                                                      "maximum iterations = {}. Part-load ratio returned = {:.3R}",
    9514             :                                                      IterNum,
    9515           0 :                                                      state.dataWaterThermalTanks->hpPartLoadRatio));
    9516           0 :                             ShowContinueErrorTimeStamp(state, "This error occurred in float mode.");
    9517             :                         } else {
    9518           0 :                             ShowRecurringWarningErrorAtEnd(
    9519             :                                 state,
    9520           0 :                                 HeatPump.Type + " \"" + HeatPump.Name +
    9521             :                                     "\":  Iteration limit exceeded in float mode warning continues. Part-load ratio statistics follow.",
    9522           0 :                                 HeatPump.IterLimitErrIndex2,
    9523           0 :                                 state.dataWaterThermalTanks->hpPartLoadRatio,
    9524           0 :                                 state.dataWaterThermalTanks->hpPartLoadRatio);
    9525             :                         }
    9526             :                     }
    9527       11317 :                 } else if (SolFla == -2) {
    9528         304 :                     state.dataWaterThermalTanks->hpPartLoadRatio =
    9529         304 :                         max(0.0, min(1.0, (HPSetPointTemp - savedTankTemp) / (NewTankTemp - savedTankTemp)));
    9530         304 :                     if (!state.dataGlobal->WarmupFlag) {
    9531         152 :                         ++HeatPump.RegulaFalsiFailedNum2;
    9532         152 :                         if (HeatPump.RegulaFalsiFailedNum2 == 1) {
    9533           1 :                             ShowWarningError(state, format("{} \"{}\"", HeatPump.Type, HeatPump.Name));
    9534           2 :                             ShowContinueError(state,
    9535           2 :                                               format("Heat pump water heater compressor part-load ratio calculation failed: PLR limits of 0 to 1 "
    9536             :                                                      "exceeded. Part-load ratio used = {:.3R}",
    9537           1 :                                                      state.dataWaterThermalTanks->hpPartLoadRatio));
    9538           1 :                             ShowContinueError(state, "Please send this information to the EnergyPlus support group.");
    9539           1 :                             ShowContinueErrorTimeStamp(state, "This error occurred in float mode.");
    9540             :                         } else {
    9541         453 :                             ShowRecurringWarningErrorAtEnd(
    9542             :                                 state,
    9543         302 :                                 HeatPump.Type + " \"" + HeatPump.Name +
    9544             :                                     "\": Part-load ratio calculation failed in float mode warning continues. Part-load ratio statistics follow.",
    9545         151 :                                 HeatPump.RegulaFalsiFailedIndex2,
    9546         151 :                                 state.dataWaterThermalTanks->hpPartLoadRatio,
    9547         151 :                                 state.dataWaterThermalTanks->hpPartLoadRatio);
    9548             :                         }
    9549             :                     }
    9550             :                 }
    9551             :             } else {
    9552         349 :                 state.dataWaterThermalTanks->hpPartLoadRatio = 0.0;
    9553             :             }
    9554             : 
    9555             :             // Re-calculate the HPWH Coil to get the correct heat transfer rate.
    9556       11666 :             state.dataLoopNodes->Node(HPWaterInletNode).Temp = this->SourceOutletTemp;
    9557       11666 :             if (MaxSpeedNum > 0) {
    9558        1137 :                 SpeedRatio = 1.0;
    9559        1137 :                 SpeedNum = 1;
    9560             : 
    9561        1137 :                 this->SetVSHPWHFlowRates(state, HeatPump, SpeedNum, SpeedRatio, RhoWater, MdotWater, FirstHVACIteration);
    9562             : 
    9563        1137 :                 if (HeatPump.bIsIHP) {
    9564          32 :                     if (bIterSpeed) {
    9565          16 :                         IntegratedHeatPump::SimIHP(state,
    9566             :                                                    HeatPump.DXCoilName,
    9567          16 :                                                    HeatPump.DXCoilNum,
    9568             :                                                    HVAC::FanOp::Cycling,
    9569             :                                                    HVAC::CompressorOp::On,
    9570          16 :                                                    state.dataWaterThermalTanks->hpPartLoadRatio,
    9571             :                                                    SpeedNum,
    9572             :                                                    SpeedRatio,
    9573             :                                                    0.0,
    9574             :                                                    0.0,
    9575             :                                                    true,
    9576             :                                                    false,
    9577          32 :                                                    1.0);
    9578             :                     }
    9579             :                 } else {
    9580        1105 :                     VariableSpeedCoils::SimVariableSpeedCoils(state,
    9581             :                                                               HeatPump.DXCoilName,
    9582        1105 :                                                               HeatPump.DXCoilNum,
    9583             :                                                               HVAC::FanOp::Cycling,
    9584             :                                                               HVAC::CompressorOp::On,
    9585        1105 :                                                               state.dataWaterThermalTanks->hpPartLoadRatio,
    9586             :                                                               SpeedNum,
    9587             :                                                               SpeedRatio,
    9588             :                                                               0.0,
    9589             :                                                               0.0,
    9590             :                                                               1.0);
    9591             :                 }
    9592             : 
    9593             :             } else {
    9594       10529 :                 DXCoils::CalcHPWHDXCoil(state, HeatPump.DXCoilNum, state.dataWaterThermalTanks->hpPartLoadRatio);
    9595             :             }
    9596      144246 :         } else if (bIterSpeed) {
    9597       46759 :             for (int loopIter = 1; loopIter <= 4; ++loopIter) {
    9598       46759 :                 HeatPump.Mode = TankOperatingMode::Heating; // modHeatMode is important for system convergence
    9599       46759 :                 state.dataWaterThermalTanks->hpPartLoadRatio = 1.0;
    9600       46759 :                 SpeedRatio = 1.0;
    9601       46759 :                 int LowSpeedNum = 2;
    9602       46759 :                 if (HeatPump.bIsIHP) {
    9603         272 :                     LowSpeedNum = IntegratedHeatPump::GetLowSpeedNumIHP(state, HeatPump.DXCoilNum);
    9604         272 :                     MaxSpeedNum = IntegratedHeatPump::GetMaxSpeedNumIHP(state, HeatPump.DXCoilNum);
    9605             :                 }
    9606             : 
    9607      380632 :                 for (int i = LowSpeedNum; i <= MaxSpeedNum; ++i) {
    9608      346300 :                     SpeedNum = i;
    9609      346300 :                     this->SetVSHPWHFlowRates(state, HeatPump, SpeedNum, SpeedRatio, RhoWater, MdotWater, FirstHVACIteration);
    9610      346300 :                     if (HeatPump.bIsIHP) {
    9611        2624 :                         IntegratedHeatPump::SimIHP(state,
    9612             :                                                    HeatPump.DXCoilName,
    9613        2624 :                                                    HeatPump.DXCoilNum,
    9614             :                                                    HVAC::FanOp::Cycling,
    9615             :                                                    HVAC::CompressorOp::On,
    9616        2624 :                                                    state.dataWaterThermalTanks->hpPartLoadRatio,
    9617             :                                                    SpeedNum,
    9618             :                                                    SpeedRatio,
    9619             :                                                    0.0,
    9620             :                                                    0.0,
    9621             :                                                    true,
    9622             :                                                    false,
    9623        5248 :                                                    1.0);
    9624             :                     } else {
    9625      343676 :                         VariableSpeedCoils::SimVariableSpeedCoils(state,
    9626             :                                                                   HeatPump.DXCoilName,
    9627      343676 :                                                                   HeatPump.DXCoilNum,
    9628             :                                                                   HVAC::FanOp::Cycling,
    9629             :                                                                   HVAC::CompressorOp::On,
    9630      343676 :                                                                   state.dataWaterThermalTanks->hpPartLoadRatio,
    9631             :                                                                   SpeedNum,
    9632             :                                                                   SpeedRatio,
    9633             :                                                                   0.0,
    9634             :                                                                   0.0,
    9635             :                                                                   1.0);
    9636             :                     }
    9637             : 
    9638             :                     // HPWH condenser water temperature difference
    9639      346300 :                     Real64 CondenserDeltaT = state.dataLoopNodes->Node(HPWaterOutletNode).Temp - state.dataLoopNodes->Node(HPWaterInletNode).Temp;
    9640             : 
    9641             :                     //           move the full load outlet temperature rate to the water heater structure variables
    9642             :                     //           (water heaters source inlet node temperature/mdot are set in Init, set it here after DXCoils::CalcHPWHDXCoil has
    9643             :                     //           been called)
    9644      346300 :                     this->SourceInletTemp = state.dataLoopNodes->Node(HPWaterInletNode).Temp + CondenserDeltaT;
    9645             :                     //           this CALL does not update node temps, must use WaterThermalTank variables
    9646             :                     // select tank type
    9647      346300 :                     if (HeatPump.HPWHTankType == DataPlant::PlantEquipmentType::WtrHeaterMixed) {
    9648      339338 :                         this->CalcWaterThermalTankMixed(state);
    9649      339338 :                         NewTankTemp = this->TankTemp;
    9650        6962 :                     } else if (HeatPump.HPWHTankType == DataPlant::PlantEquipmentType::WtrHeaterStratified) {
    9651        6962 :                         this->CalcWaterThermalTankStratified(state);
    9652        6962 :                         NewTankTemp = this->FindStratifiedTankSensedTemp(state);
    9653             :                     }
    9654             : 
    9655      346300 :                     if (NewTankTemp > HPSetPointTemp) {
    9656       12427 :                         SpeedNum = i;
    9657       12427 :                         break;
    9658             :                     } else {
    9659      333873 :                         LowSpeedTankTemp = NewTankTemp;
    9660             :                     }
    9661             :                 }
    9662             : 
    9663       46759 :                 if (NewTankTemp > HPSetPointTemp) {
    9664             :                     int SolFla;
    9665       12427 :                     std::string IterNum;
    9666       77990 :                     auto f = [&state, this, SpeedNum, HPWaterInletNode, HPWaterOutletNode, RhoWater, HPSetPointTemp, &HeatPump, FirstHVACIteration](
    9667       77990 :                                  Real64 const SpeedRatio) {
    9668       77990 :                         return this->PLRResidualIterSpeed(state,
    9669             :                                                           SpeedRatio,
    9670             :                                                           this->HeatPumpNum,
    9671             :                                                           SpeedNum,
    9672             :                                                           HPWaterInletNode,
    9673             :                                                           HPWaterOutletNode,
    9674             :                                                           RhoWater,
    9675             :                                                           HPSetPointTemp,
    9676             :                                                           HeatPump.SaveWHMode,
    9677       77990 :                                                           FirstHVACIteration);
    9678       12427 :                     };
    9679       12427 :                     General::SolveRoot(state, Acc, MaxIte, SolFla, SpeedRatio, f, 1.0e-10, 1.0);
    9680             : 
    9681       12427 :                     if (SolFla == -1) {
    9682           0 :                         IterNum = fmt::to_string(MaxIte);
    9683           0 :                         if (!state.dataGlobal->WarmupFlag) {
    9684           0 :                             ++HeatPump.IterLimitExceededNum1;
    9685           0 :                             if (HeatPump.IterLimitExceededNum1 == 1) {
    9686           0 :                                 ShowWarningError(state, format("{} \"{}\"", HeatPump.Type, HeatPump.Name));
    9687           0 :                                 ShowContinueError(state,
    9688           0 :                                                   format("Iteration limit exceeded calculating heat pump water heater speed speed ratio ratio, "
    9689             :                                                          "maximum iterations = {}. speed ratio returned = {:.3R}",
    9690             :                                                          IterNum,
    9691             :                                                          SpeedRatio));
    9692           0 :                                 ShowContinueErrorTimeStamp(state, "This error occurred in heating mode.");
    9693             :                             } else {
    9694           0 :                                 ShowRecurringWarningErrorAtEnd(
    9695             :                                     state,
    9696           0 :                                     HeatPump.Type + " \"" + HeatPump.Name +
    9697             :                                         "\":  Iteration limit exceeded in heating mode warning continues. speed ratio statistics follow.",
    9698           0 :                                     HeatPump.IterLimitErrIndex1,
    9699             :                                     SpeedRatio,
    9700             :                                     SpeedRatio);
    9701             :                             }
    9702             :                         }
    9703       12427 :                     } else if (SolFla == -2) {
    9704           0 :                         SpeedRatio = max(0.0, min(1.0, (HPSetPointTemp - LowSpeedTankTemp) / (NewTankTemp - LowSpeedTankTemp)));
    9705           0 :                         if (!state.dataGlobal->WarmupFlag) {
    9706           0 :                             ++HeatPump.RegulaFalsiFailedNum1;
    9707           0 :                             if (HeatPump.RegulaFalsiFailedNum1 == 1) {
    9708           0 :                                 ShowWarningError(state, format("{} \"{}\"", HeatPump.Type, HeatPump.Name));
    9709           0 :                                 ShowContinueError(state,
    9710           0 :                                                   format("Heat pump water heater speed ratio calculation failed: speed ratio limits of 0 to 1 "
    9711             :                                                          "exceeded. speed ratio used = {:.3R}",
    9712             :                                                          SpeedRatio));
    9713           0 :                                 ShowContinueError(state, "Please send this information to the EnergyPlus support group.");
    9714           0 :                                 ShowContinueErrorTimeStamp(state, "This error occurred in heating mode.");
    9715             :                             } else {
    9716           0 :                                 ShowRecurringWarningErrorAtEnd(
    9717             :                                     state,
    9718           0 :                                     HeatPump.Type + " \"" + HeatPump.Name +
    9719             :                                         "\":  Speed ratio calculation failed in heating mode warning continues. Speed ratio statistics follow.",
    9720           0 :                                     HeatPump.RegulaFalsiFailedIndex1,
    9721             :                                     SpeedRatio,
    9722             :                                     SpeedRatio);
    9723             :                             }
    9724             :                         }
    9725             :                     }
    9726       12427 :                 } else {
    9727       34332 :                     SpeedNum = MaxSpeedNum;
    9728       34332 :                     SpeedRatio = 1.0;
    9729             :                 }
    9730             : 
    9731       46759 :                 state.dataWaterThermalTanks->hpPartLoadRatio = 1.0;
    9732       46759 :                 this->SetVSHPWHFlowRates(state, HeatPump, SpeedNum, SpeedRatio, RhoWater, MdotWater, FirstHVACIteration);
    9733             : 
    9734       46759 :                 if (HeatPump.bIsIHP) {
    9735         272 :                     IntegratedHeatPump::SimIHP(state,
    9736             :                                                HeatPump.DXCoilName,
    9737         272 :                                                HeatPump.DXCoilNum,
    9738             :                                                HVAC::FanOp::Cycling,
    9739             :                                                HVAC::CompressorOp::On,
    9740         272 :                                                state.dataWaterThermalTanks->hpPartLoadRatio,
    9741             :                                                SpeedNum,
    9742             :                                                SpeedRatio,
    9743             :                                                0.0,
    9744             :                                                0.0,
    9745             :                                                true,
    9746             :                                                false,
    9747         544 :                                                1.0);
    9748             :                 } else {
    9749       46487 :                     VariableSpeedCoils::SimVariableSpeedCoils(state,
    9750             :                                                               HeatPump.DXCoilName,
    9751       46487 :                                                               HeatPump.DXCoilNum,
    9752             :                                                               HVAC::FanOp::Cycling,
    9753             :                                                               HVAC::CompressorOp::On,
    9754       46487 :                                                               state.dataWaterThermalTanks->hpPartLoadRatio,
    9755             :                                                               SpeedNum,
    9756             :                                                               SpeedRatio,
    9757             :                                                               0.0,
    9758             :                                                               0.0,
    9759             :                                                               1.0);
    9760             :                 }
    9761             : 
    9762             :                 // HPWH condenser water temperature difference
    9763       46759 :                 Real64 CondenserDeltaT = state.dataLoopNodes->Node(HPWaterOutletNode).Temp - state.dataLoopNodes->Node(HPWaterInletNode).Temp;
    9764             : 
    9765             :                 //           move the full load outlet temperature rate to the water heater structure variables
    9766             :                 //           (water heaters source inlet node temperature/mdot are set in Init, set it here after DXCoils::CalcHPWHDXCoil has been
    9767             :                 //           called)
    9768       46759 :                 this->SourceInletTemp = state.dataLoopNodes->Node(HPWaterInletNode).Temp + CondenserDeltaT;
    9769             :                 //           this CALL does not update node temps, must use WaterThermalTank variables
    9770             :                 // select tank type
    9771       46759 :                 if (HeatPump.HPWHTankType == DataPlant::PlantEquipmentType::WtrHeaterMixed) {
    9772       43278 :                     this->CalcWaterThermalTankMixed(state);
    9773       43278 :                     NewTankTemp = this->TankTemp;
    9774        3481 :                 } else if (HeatPump.HPWHTankType == DataPlant::PlantEquipmentType::WtrHeaterStratified) {
    9775        3481 :                     this->CalcWaterThermalTankStratified(state);
    9776        3481 :                     NewTankTemp = this->FindStratifiedTankSensedTemp(state);
    9777             :                 }
    9778             :                 // update inlet temp
    9779       46759 :                 state.dataLoopNodes->Node(HPWaterInletNode).Temp = this->SourceOutletTemp;
    9780       46759 :                 if (std::abs(state.dataLoopNodes->Node(HPWaterInletNode).Temp - HPWHCondInletNodeLast) < HVAC::SmallTempDiff) break;
    9781       28058 :                 HPWHCondInletNodeLast = state.dataLoopNodes->Node(HPWaterInletNode).Temp;
    9782             :             }
    9783             : 
    9784             :         } else {
    9785             :             // Set the PLR to 1 if we're not going to reach setpoint during this DataGlobals::TimeStep.
    9786      125545 :             state.dataWaterThermalTanks->hpPartLoadRatio = 1.0;
    9787             :         }
    9788             :     }
    9789             : 
    9790      336374 :     if (HeatPump.bIsIHP) {
    9791        5070 :         if (state.dataIntegratedHP->IntegratedHeatPumps(HeatPump.DXCoilNum).CheckWHCall) {
    9792        2534 :             IntegratedHeatPump::ClearCoils(state, HeatPump.DXCoilNum); // clear node info when checking the heating load
    9793             :         }
    9794             :     }
    9795             : 
    9796             :     // set air-side mass flow rate for final calculation
    9797      336374 :     if (InletAirMixerNode > 0) {
    9798       20029 :         state.dataLoopNodes->Node(InletAirMixerNode).MassFlowRate =
    9799       20029 :             state.dataWaterThermalTanks->mdotAir * state.dataWaterThermalTanks->hpPartLoadRatio;
    9800       40058 :         state.dataLoopNodes->Node(HPAirInletNode).MassFlowRate = state.dataWaterThermalTanks->mdotAir * state.dataWaterThermalTanks->hpPartLoadRatio *
    9801       20029 :                                                                  (1.0 - state.dataWaterThermalTanks->mixerInletAirSchedule);
    9802       20029 :         state.dataLoopNodes->Node(OutdoorAirNode).MassFlowRate =
    9803       20029 :             state.dataWaterThermalTanks->mdotAir * state.dataWaterThermalTanks->hpPartLoadRatio * state.dataWaterThermalTanks->mixerInletAirSchedule;
    9804             :         //   IF HPWH is off, pass zone node conditions through HPWH air-side
    9805       20029 :         if (state.dataWaterThermalTanks->hpPartLoadRatio == 0)
    9806       14806 :             state.dataLoopNodes->Node(InletAirMixerNode) = state.dataLoopNodes->Node(HPAirInletNode);
    9807             :     } else {
    9808      316345 :         if (OutdoorAirNode == 0) {
    9809      189127 :             state.dataLoopNodes->Node(HPAirInletNode).MassFlowRate =
    9810      189127 :                 state.dataWaterThermalTanks->mdotAir * state.dataWaterThermalTanks->hpPartLoadRatio;
    9811             :         } else {
    9812      127218 :             state.dataLoopNodes->Node(OutdoorAirNode).MassFlowRate =
    9813      127218 :                 state.dataWaterThermalTanks->mdotAir * state.dataWaterThermalTanks->hpPartLoadRatio;
    9814             :         }
    9815             :     }
    9816      336374 :     if (state.dataWaterThermalTanks->hpPartLoadRatio == 0) this->SourceInletTemp = this->SourceOutletTemp;
    9817             : 
    9818             :     // set water-side mass flow rate for final calculation
    9819      336374 :     state.dataLoopNodes->Node(HPWaterInletNode).MassFlowRate = MdotWater * state.dataWaterThermalTanks->hpPartLoadRatio;
    9820             : 
    9821      336374 :     if (MaxSpeedNum > 0) {
    9822             : 
    9823             :         // it is important to use mdotAir to reset the notes, otherwise, could fail to converge
    9824       50526 :         if (InletAirMixerNode > 0) {
    9825        7890 :             state.dataLoopNodes->Node(InletAirMixerNode).MassFlowRateMax = state.dataWaterThermalTanks->mdotAir;
    9826        7890 :             state.dataLoopNodes->Node(InletAirMixerNode).MassFlowRateMaxAvail = state.dataWaterThermalTanks->mdotAir;
    9827             :         } else {
    9828       42636 :             if (OutdoorAirNode == 0) {
    9829       15710 :                 state.dataLoopNodes->Node(HPAirInletNode).MassFlowRateMax = state.dataWaterThermalTanks->mdotAir;
    9830       15710 :                 state.dataLoopNodes->Node(HPAirInletNode).MassFlowRateMaxAvail = state.dataWaterThermalTanks->mdotAir;
    9831             :             } else {
    9832       26926 :                 state.dataLoopNodes->Node(OutdoorAirNode).MassFlowRateMax = state.dataWaterThermalTanks->mdotAir;
    9833       26926 :                 state.dataLoopNodes->Node(OutdoorAirNode).MassFlowRateMaxAvail = state.dataWaterThermalTanks->mdotAir;
    9834             :             }
    9835             :         }
    9836             : 
    9837             :         //   set the max mass flow rate for outdoor fans
    9838       50526 :         state.dataLoopNodes->Node(HeatPump.FanOutletNode).MassFlowRateMax = state.dataWaterThermalTanks->mdotAir;
    9839             : 
    9840       50526 :         if (HeatPump.bIsIHP) {
    9841             :             // pass node information using resulting PLR
    9842        5070 :             if (HeatPump.fanPlace == HVAC::FanPlace::BlowThru) {
    9843             :                 //   simulate fan and DX coil twice to pass PLF (OnOffFanPartLoadFraction) to fan
    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        5070 :                                            1.0);
    9859        5070 :                 state.dataFans->fans(HeatPump.FanNum)->simulate(state, FirstHVACIteration, _, _);
    9860             : 
    9861        5070 :                 IntegratedHeatPump::SimIHP(state,
    9862             :                                            HeatPump.DXCoilName,
    9863        5070 :                                            HeatPump.DXCoilNum,
    9864             :                                            HVAC::FanOp::Cycling,
    9865             :                                            compressorOp,
    9866        5070 :                                            state.dataWaterThermalTanks->hpPartLoadRatio,
    9867             :                                            SpeedNum,
    9868             :                                            SpeedRatio,
    9869             :                                            0.0,
    9870             :                                            0.0,
    9871             :                                            true,
    9872             :                                            false,
    9873       10140 :                                            1.0);
    9874             :             } else {
    9875             :                 //   simulate DX coil and fan twice to pass fan power (FanElecPower) to DX coil
    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           0 :                 IntegratedHeatPump::SimIHP(state,
    9892             :                                            HeatPump.DXCoilName,
    9893           0 :                                            HeatPump.DXCoilNum,
    9894             :                                            HVAC::FanOp::Cycling,
    9895             :                                            compressorOp,
    9896           0 :                                            state.dataWaterThermalTanks->hpPartLoadRatio,
    9897             :                                            SpeedNum,
    9898             :                                            SpeedRatio,
    9899             :                                            0.0,
    9900             :                                            0.0,
    9901             :                                            true,
    9902             :                                            false,
    9903           0 :                                            1.0);
    9904           0 :                 state.dataFans->fans(HeatPump.FanNum)->simulate(state, FirstHVACIteration, _, _);
    9905             :             }
    9906             :         } else {
    9907             :             // pass node information using resulting PLR
    9908       45456 :             if (HeatPump.fanPlace == HVAC::FanPlace::BlowThru) {
    9909             :                 //   simulate fan and DX coil twice to pass PLF (OnOffFanPartLoadFraction) to fan
    9910       29676 :                 state.dataFans->fans(HeatPump.FanNum)->simulate(state, FirstHVACIteration, _, _);
    9911             : 
    9912       29676 :                 VariableSpeedCoils::SimVariableSpeedCoils(state,
    9913             :                                                           HeatPump.DXCoilName,
    9914       29676 :                                                           HeatPump.DXCoilNum,
    9915             :                                                           HVAC::FanOp::Cycling,
    9916             :                                                           compressorOp,
    9917       29676 :                                                           state.dataWaterThermalTanks->hpPartLoadRatio,
    9918             :                                                           SpeedNum,
    9919             :                                                           SpeedRatio,
    9920             :                                                           0.0,
    9921             :                                                           0.0,
    9922             :                                                           1.0);
    9923             : 
    9924       29676 :                 state.dataFans->fans(HeatPump.FanNum)->simulate(state, FirstHVACIteration, _, _);
    9925             : 
    9926       29676 :                 VariableSpeedCoils::SimVariableSpeedCoils(state,
    9927             :                                                           HeatPump.DXCoilName,
    9928       29676 :                                                           HeatPump.DXCoilNum,
    9929             :                                                           HVAC::FanOp::Cycling,
    9930             :                                                           compressorOp,
    9931       29676 :                                                           state.dataWaterThermalTanks->hpPartLoadRatio,
    9932             :                                                           SpeedNum,
    9933             :                                                           SpeedRatio,
    9934             :                                                           0.0,
    9935             :                                                           0.0,
    9936             :                                                           1.0);
    9937             :             } else {
    9938             :                 //   simulate DX coil and fan twice to pass fan power (FanElecPower) to DX coil
    9939       15780 :                 VariableSpeedCoils::SimVariableSpeedCoils(state,
    9940             :                                                           HeatPump.DXCoilName,
    9941       15780 :                                                           HeatPump.DXCoilNum,
    9942             :                                                           HVAC::FanOp::Cycling,
    9943             :                                                           compressorOp,
    9944       15780 :                                                           state.dataWaterThermalTanks->hpPartLoadRatio,
    9945             :                                                           SpeedNum,
    9946             :                                                           SpeedRatio,
    9947             :                                                           0.0,
    9948             :                                                           0.0,
    9949             :                                                           1.0);
    9950             : 
    9951       15780 :                 state.dataFans->fans(HeatPump.FanNum)->simulate(state, FirstHVACIteration, _, _);
    9952             : 
    9953       15780 :                 VariableSpeedCoils::SimVariableSpeedCoils(state,
    9954             :                                                           HeatPump.DXCoilName,
    9955       15780 :                                                           HeatPump.DXCoilNum,
    9956             :                                                           HVAC::FanOp::Cycling,
    9957             :                                                           compressorOp,
    9958       15780 :                                                           state.dataWaterThermalTanks->hpPartLoadRatio,
    9959             :                                                           SpeedNum,
    9960             :                                                           SpeedRatio,
    9961             :                                                           0.0,
    9962             :                                                           0.0,
    9963             :                                                           1.0);
    9964             : 
    9965       15780 :                 state.dataFans->fans(HeatPump.FanNum)->simulate(state, FirstHVACIteration, _, _);
    9966             :             }
    9967             :         }
    9968             :     } else { // single speed
    9969             : 
    9970             :         // pass node information using resulting PLR
    9971      285848 :         if (HeatPump.fanPlace == HVAC::FanPlace::BlowThru) {
    9972             :             //   simulate fan and DX coil twice to pass PLF (OnOffFanPartLoadFraction) to fan
    9973       67738 :             state.dataFans->fans(HeatPump.FanNum)->simulate(state, FirstHVACIteration, _, _);
    9974             : 
    9975      135476 :             DXCoils::SimDXCoil(state,
    9976             :                                HeatPump.DXCoilName,
    9977             :                                compressorOp,
    9978             :                                FirstHVACIteration,
    9979       67738 :                                HeatPump.DXCoilNum,
    9980             :                                HVAC::FanOp::Cycling,
    9981       67738 :                                state.dataWaterThermalTanks->hpPartLoadRatio);
    9982             : 
    9983       67738 :             state.dataFans->fans(HeatPump.FanNum)->simulate(state, FirstHVACIteration, _, _);
    9984             : 
    9985      135476 :             DXCoils::SimDXCoil(state,
    9986             :                                HeatPump.DXCoilName,
    9987             :                                compressorOp,
    9988             :                                FirstHVACIteration,
    9989       67738 :                                HeatPump.DXCoilNum,
    9990             :                                HVAC::FanOp::Cycling,
    9991       67738 :                                state.dataWaterThermalTanks->hpPartLoadRatio);
    9992             :         } else {
    9993             :             //   simulate DX coil and fan twice to pass fan power (FanElecPower) to DX coil
    9994      436220 :             DXCoils::SimDXCoil(state,
    9995             :                                HeatPump.DXCoilName,
    9996             :                                compressorOp,
    9997             :                                FirstHVACIteration,
    9998      218110 :                                HeatPump.DXCoilNum,
    9999             :                                HVAC::FanOp::Cycling,
   10000      218110 :                                state.dataWaterThermalTanks->hpPartLoadRatio);
   10001             : 
   10002      218110 :             state.dataFans->fans(HeatPump.FanNum)->simulate(state, FirstHVACIteration, _, _);
   10003             : 
   10004      436220 :             DXCoils::SimDXCoil(state,
   10005             :                                HeatPump.DXCoilName,
   10006             :                                compressorOp,
   10007             :                                FirstHVACIteration,
   10008      218110 :                                HeatPump.DXCoilNum,
   10009             :                                HVAC::FanOp::Cycling,
   10010      218110 :                                state.dataWaterThermalTanks->hpPartLoadRatio);
   10011             : 
   10012      218110 :             state.dataFans->fans(HeatPump.FanNum)->simulate(state, FirstHVACIteration, _, _);
   10013             :         }
   10014             :     }
   10015             : 
   10016             :     // Call the tank one more time with the final PLR
   10017      336374 :     if (HeatPump.HPWHTankType == DataPlant::PlantEquipmentType::WtrHeaterMixed) {
   10018      136932 :         this->CalcWaterThermalTankMixed(state);
   10019      199442 :     } else if (HeatPump.HPWHTankType == DataPlant::PlantEquipmentType::WtrHeaterStratified) {
   10020      199442 :         this->CalcWaterThermalTankStratified(state);
   10021             :     } else {
   10022           0 :         assert(0);
   10023             :     }
   10024             : 
   10025             :     // set HPWH outlet node equal to the outlet air splitter node conditions if outlet air splitter node exists
   10026      336374 :     if (OutletAirSplitterNode > 0) {
   10027       20029 :         state.dataLoopNodes->Node(HPAirOutletNode) = state.dataLoopNodes->Node(OutletAirSplitterNode);
   10028       20029 :         state.dataLoopNodes->Node(ExhaustAirNode) = state.dataLoopNodes->Node(OutletAirSplitterNode);
   10029             :     }
   10030             : 
   10031             :     // Check schedule to divert air-side cooling to outdoors.
   10032      336374 :     if (HeatPump.OutletAirSplitterSchPtr > 0) {
   10033       20029 :         Real64 OutletAirSplitterSch = ScheduleManager::GetCurrentScheduleValue(state, HeatPump.OutletAirSplitterSchPtr);
   10034       20029 :         state.dataLoopNodes->Node(HPAirOutletNode).MassFlowRate =
   10035       20029 :             state.dataWaterThermalTanks->mdotAir * state.dataWaterThermalTanks->hpPartLoadRatio * (1.0 - OutletAirSplitterSch);
   10036       20029 :         state.dataLoopNodes->Node(ExhaustAirNode).MassFlowRate =
   10037       20029 :             state.dataWaterThermalTanks->mdotAir * state.dataWaterThermalTanks->hpPartLoadRatio * OutletAirSplitterSch;
   10038             :     }
   10039             : 
   10040      336374 :     HeatPump.HeatingPLR = state.dataWaterThermalTanks->hpPartLoadRatio;
   10041      336374 :     HeatPump.OnCycParaFuelRate = HeatPump.OnCycParaLoad * state.dataWaterThermalTanks->hpPartLoadRatio;
   10042      336374 :     HeatPump.OnCycParaFuelEnergy = HeatPump.OnCycParaFuelRate * state.dataHVACGlobal->TimeStepSysSec;
   10043      336374 :     HeatPump.OffCycParaFuelRate = HeatPump.OffCycParaLoad * (1.0 - state.dataWaterThermalTanks->hpPartLoadRatio);
   10044      336374 :     HeatPump.OffCycParaFuelEnergy = HeatPump.OffCycParaFuelRate * state.dataHVACGlobal->TimeStepSysSec;
   10045      336374 :     if (HeatPump.HPWHTankType == DataPlant::PlantEquipmentType::WtrHeaterMixed) {
   10046      136932 :         HeatPump.ControlTempAvg = this->TankTempAvg;
   10047      136932 :         HeatPump.ControlTempFinal = this->TankTemp;
   10048      199442 :     } else if (HeatPump.HPWHTankType == DataPlant::PlantEquipmentType::WtrHeaterStratified) {
   10049      199442 :         HeatPump.ControlTempAvg = this->FindStratifiedTankSensedTemp(state, true);
   10050      199442 :         HeatPump.ControlTempFinal = this->FindStratifiedTankSensedTemp(state);
   10051             :     } else {
   10052           0 :         assert(0);
   10053             :     }
   10054             : 
   10055      336374 :     switch (HeatPump.InletAirConfiguration) {
   10056             : 
   10057             :     //   no sensible capacity to zone for outdoor and scheduled HPWH
   10058      146532 :     case WTTAmbientTemp::OutsideAir:
   10059             :     case WTTAmbientTemp::Schedule: {
   10060      146532 :         HeatPump.HPWaterHeaterSensibleCapacity = 0.0;
   10061      146532 :         HeatPump.HPWaterHeaterLatentCapacity = 0.0;
   10062             : 
   10063             :         //   calculate sensible capacity to zone for inlet air configuration equals Zone Only or Zone And Outdoor Air configurations
   10064      146532 :         break;
   10065             :     }
   10066      189842 :     default:
   10067             : 
   10068      189842 :         Real64 CpAir = Psychrometrics::PsyCpAirFnW(state.dataLoopNodes->Node(HPAirInletNode).HumRat);
   10069             : 
   10070             :         //     add parasitics to zone heat balance if parasitic heat load is to zone otherwise neglect parasitics
   10071      189842 :         if (HeatPump.ParasiticTempIndicator == WTTAmbientTemp::TempZone) {
   10072      132070 :             HeatPump.HPWaterHeaterSensibleCapacity =
   10073      132070 :                 (state.dataLoopNodes->Node(HPAirOutletNode).MassFlowRate * CpAir *
   10074      132070 :                  (state.dataLoopNodes->Node(HPAirOutletNode).Temp - state.dataLoopNodes->Node(HPAirInletNode).Temp)) +
   10075      132070 :                 HeatPump.OnCycParaFuelRate + HeatPump.OffCycParaFuelRate;
   10076             :         } else {
   10077       57772 :             HeatPump.HPWaterHeaterSensibleCapacity =
   10078       57772 :                 state.dataLoopNodes->Node(HPAirOutletNode).MassFlowRate * CpAir *
   10079       57772 :                 (state.dataLoopNodes->Node(HPAirOutletNode).Temp - state.dataLoopNodes->Node(HPAirInletNode).Temp);
   10080             :         }
   10081             : 
   10082      189842 :         HeatPump.HPWaterHeaterLatentCapacity = state.dataLoopNodes->Node(HPAirOutletNode).MassFlowRate *
   10083      189842 :                                                (state.dataLoopNodes->Node(HPAirOutletNode).HumRat - state.dataLoopNodes->Node(HPAirInletNode).HumRat);
   10084      189842 :         break;
   10085             :     }
   10086             : }
   10087             : 
   10088      993781 : void WaterThermalTankData::CalcWaterThermalTank(EnergyPlusData &state)
   10089             : {
   10090      993781 :     switch (this->WaterThermalTankType) {
   10091      387270 :     case DataPlant::PlantEquipmentType::WtrHeaterMixed:
   10092      387270 :         this->CalcWaterThermalTankMixed(state);
   10093      387270 :         break;
   10094      606511 :     case DataPlant::PlantEquipmentType::WtrHeaterStratified:
   10095      606511 :         this->CalcWaterThermalTankStratified(state);
   10096      606511 :         break;
   10097           0 :     default:
   10098           0 :         assert(false);
   10099             :     }
   10100      993781 : }
   10101             : 
   10102      549933 : Real64 WaterThermalTankData::GetHPWHSensedTankTemp(EnergyPlusData &state)
   10103             : {
   10104      549933 :     switch (this->WaterThermalTankType) {
   10105      209584 :     case DataPlant::PlantEquipmentType::WtrHeaterMixed:
   10106      209584 :         return this->TankTemp;
   10107             :         break;
   10108      340349 :     case DataPlant::PlantEquipmentType::WtrHeaterStratified:
   10109      340349 :         return this->FindStratifiedTankSensedTemp(state);
   10110             :         break;
   10111           0 :     default:
   10112           0 :         assert(false);
   10113             :         return 0.0; // silence compiler
   10114             :     }
   10115             : }
   10116             : 
   10117      133685 : void WaterThermalTankData::ConvergeSingleSpeedHPWHCoilAndTank(EnergyPlusData &state, Real64 const partLoadRatio)
   10118             : {
   10119      133685 :     HeatPumpWaterHeaterData &HPWH = state.dataWaterThermalTanks->HPWaterHeater(this->HeatPumpNum);
   10120      133685 :     DXCoils::DXCoilData &Coil = state.dataDXCoils->DXCoil(HPWH.DXCoilNum);
   10121             : 
   10122      133685 :     Real64 PrevTankTemp = this->SourceOutletTemp;
   10123      456268 :     for (int i = 1; i <= 10; ++i) {
   10124             : 
   10125      456268 :         DXCoils::CalcHPWHDXCoil(state, HPWH.DXCoilNum, partLoadRatio);
   10126      456268 :         this->SourceInletTemp = state.dataLoopNodes->Node(HPWH.CondWaterOutletNode).Temp;
   10127             : 
   10128      456268 :         this->CalcWaterThermalTank(state);
   10129      456268 :         state.dataLoopNodes->Node(Coil.WaterInNode).Temp = this->SourceOutletTemp;
   10130             : 
   10131      456268 :         if (std::abs(this->SourceOutletTemp - PrevTankTemp) < HVAC::SmallTempDiff) {
   10132      133685 :             break;
   10133             :         }
   10134             : 
   10135      322583 :         PrevTankTemp = this->SourceOutletTemp;
   10136             :     }
   10137      133685 : }
   10138             : 
   10139      562160 : void WaterThermalTankData::SetVSHPWHFlowRates(EnergyPlusData &state,
   10140             :                                               HeatPumpWaterHeaterData &HPWH, // heat pump coil
   10141             :                                               int const SpeedNum,            // upper speed number
   10142             :                                               Real64 const SpeedRatio,       // interpolation ration between upper and lower speed
   10143             :                                               Real64 const WaterDens,        // tank water density
   10144             :                                               Real64 &MdotWater,             // water flow rate
   10145             :                                               bool const FirstHVACIteration)
   10146             : {
   10147             :     // FUNCTION INFORMATION:
   10148             :     //       AUTHOR         B.Shen, ORNL, 12/2014
   10149             :     //       DATE WRITTEN   May 2005
   10150             :     //       MODIFIED
   10151             :     //       RE-ENGINEERED
   10152             : 
   10153             :     // PURPOSE OF THIS FUNCTION:
   10154             :     //  set water and air flow rates driven by the variable-speed HPWH coil
   10155             :     //  calculate resultant HPWH coil output
   10156             : 
   10157      562160 :     int SpeedLow = SpeedNum - 1;
   10158      562160 :     if (SpeedLow < 1) SpeedLow = 1;
   10159             : 
   10160      562160 :     int HPWaterInletNode = HPWH.CondWaterInletNode;
   10161      562160 :     int DXCoilAirInletNode = HPWH.DXCoilAirInletNode;
   10162      562160 :     if (HPWH.bIsIHP) {
   10163       19412 :         HPWH.OperatingWaterFlowRate = IntegratedHeatPump::GetWaterVolFlowRateIHP(state, HPWH.DXCoilNum, SpeedNum, SpeedRatio);
   10164       19412 :         state.dataWaterThermalTanks->mdotAir = IntegratedHeatPump::GetAirMassFlowRateIHP(state, HPWH.DXCoilNum, SpeedNum, SpeedRatio, true);
   10165       19412 :         HPWH.OperatingAirFlowRate = IntegratedHeatPump::GetAirVolFlowRateIHP(state, HPWH.DXCoilNum, SpeedNum, SpeedRatio, true);
   10166       19412 :         state.dataLoopNodes->Node(DXCoilAirInletNode).MassFlowRate = state.dataWaterThermalTanks->mdotAir;
   10167       19412 :         state.dataLoopNodes->Node(DXCoilAirInletNode).MassFlowRateMaxAvail = state.dataWaterThermalTanks->mdotAir;
   10168       19412 :         state.dataLoopNodes->Node(DXCoilAirInletNode).MassFlowRateMax = state.dataWaterThermalTanks->mdotAir;
   10169             :     } else {
   10170      542748 :         HPWH.OperatingWaterFlowRate = HPWH.HPWHWaterVolFlowRate(SpeedNum) * SpeedRatio + HPWH.HPWHWaterVolFlowRate(SpeedLow) * (1.0 - SpeedRatio);
   10171      542748 :         HPWH.OperatingAirFlowRate = HPWH.HPWHAirVolFlowRate(SpeedNum) * SpeedRatio + HPWH.HPWHAirVolFlowRate(SpeedLow) * (1.0 - SpeedRatio);
   10172      542748 :         state.dataWaterThermalTanks->mdotAir =
   10173      542748 :             HPWH.HPWHAirMassFlowRate(SpeedNum) * SpeedRatio + HPWH.HPWHAirMassFlowRate(SpeedLow) * (1.0 - SpeedRatio);
   10174             :     }
   10175             : 
   10176      562160 :     MdotWater = HPWH.OperatingWaterFlowRate * WaterDens;
   10177      562160 :     this->SourceMassFlowRate = MdotWater;
   10178             : 
   10179      562160 :     state.dataLoopNodes->Node(DXCoilAirInletNode).MassFlowRate = state.dataWaterThermalTanks->mdotAir;
   10180      562160 :     state.dataLoopNodes->Node(HPWaterInletNode).MassFlowRate = MdotWater;
   10181      562160 :     this->SourceMassFlowRate = MdotWater;
   10182             : 
   10183      562160 :     if (HPWH.InletAirMixerNode > 0) {
   10184       32423 :         state.dataLoopNodes->Node(HPWH.InletAirMixerNode).MassFlowRate = state.dataWaterThermalTanks->mdotAir;
   10185       32423 :         state.dataLoopNodes->Node(HPWH.InletAirMixerNode).MassFlowRateMaxAvail = state.dataWaterThermalTanks->mdotAir;
   10186             :     } else {
   10187      529737 :         if (HPWH.OutsideAirNode == 0) {
   10188       48807 :             state.dataLoopNodes->Node(HPWH.HeatPumpAirInletNode).MassFlowRate = state.dataWaterThermalTanks->mdotAir;
   10189       48807 :             state.dataLoopNodes->Node(HPWH.HeatPumpAirInletNode).MassFlowRateMaxAvail = state.dataWaterThermalTanks->mdotAir;
   10190             :         } else {
   10191      480930 :             state.dataLoopNodes->Node(HPWH.OutsideAirNode).MassFlowRate = state.dataWaterThermalTanks->mdotAir;
   10192      480930 :             state.dataLoopNodes->Node(HPWH.OutsideAirNode).MassFlowRateMaxAvail = state.dataWaterThermalTanks->mdotAir;
   10193             :         }
   10194             :     }
   10195             : 
   10196             :     // put fan component first, regardless placement, to calculate fan power
   10197      562160 :     int FanInNode = state.dataFans->fans(HPWH.FanNum)->inletNodeNum;
   10198             : 
   10199      562160 :     state.dataLoopNodes->Node(FanInNode).MassFlowRate = state.dataWaterThermalTanks->mdotAir;
   10200      562160 :     state.dataLoopNodes->Node(FanInNode).MassFlowRateMaxAvail = state.dataWaterThermalTanks->mdotAir;
   10201      562160 :     state.dataLoopNodes->Node(FanInNode).MassFlowRateMax = state.dataWaterThermalTanks->mdotAir;
   10202      562160 :     if (HPWH.fanType != HVAC::FanType::SystemModel) {
   10203       84846 :         state.dataFans->fans(HPWH.FanNum)->massFlowRateMaxAvail = state.dataWaterThermalTanks->mdotAir;
   10204             :     } // system fan will use the inlet node max avail.
   10205             : 
   10206      562160 :     state.dataFans->fans(HPWH.FanNum)->simulate(state, FirstHVACIteration, _, _);
   10207      562160 : }
   10208             : 
   10209       77990 : Real64 WaterThermalTankData::PLRResidualIterSpeed(EnergyPlusData &state,
   10210             :                                                   Real64 const SpeedRatio, // speed ratio between two speed levels
   10211             :                                                   int const HPNum,
   10212             :                                                   int const SpeedNum,
   10213             :                                                   int const HPWaterInletNode,
   10214             :                                                   int const HPWaterOutletNode,
   10215             :                                                   Real64 const RhoWater,
   10216             :                                                   Real64 const desTankTemp,
   10217             :                                                   TankOperatingMode const mode,
   10218             :                                                   bool const FirstHVACIteration)
   10219             : {
   10220             :     // FUNCTION INFORMATION:
   10221             :     //       AUTHOR         B.Shen, ORNL, 12/2014
   10222             :     //       MODIFIED
   10223             :     //       RE-ENGINEERED
   10224             : 
   10225             :     // PURPOSE OF THIS FUNCTION:
   10226             :     //  Calculates residual function (desired tank temp - actual tank temp), when iterating speed ration between two speed levels
   10227             :     //  HP water heater output depends on the speed ratio which is being varied to zero the residual.
   10228             : 
   10229             :     // METHODOLOGY EMPLOYED:
   10230             :     //  Calls residuals to get tank temperature at the given speed ratio between a lower and an upper speed levels
   10231             :     //  and calculates the residual as defined respectively for DataPlant::PlantEquipmentType::WtrHeaterMixed or
   10232             :     //  DataPlant::PlantEquipmentType::WtrHeaterStratified
   10233             : 
   10234       77990 :     this->Mode = mode;
   10235       77990 :     state.dataWaterThermalTanks->hpPartLoadRatio = 1.0;
   10236       77990 :     Real64 MdotWater = 0.0;
   10237             : 
   10238       77990 :     auto &HPWH = state.dataWaterThermalTanks->HPWaterHeater(HPNum);
   10239             : 
   10240       77990 :     this->SetVSHPWHFlowRates(state, HPWH, SpeedNum, SpeedRatio, RhoWater, MdotWater, FirstHVACIteration);
   10241             : 
   10242       77990 :     if (state.dataWaterThermalTanks->HPWaterHeater(HPNum).bIsIHP) {
   10243          96 :         IntegratedHeatPump::SimIHP(state,
   10244          96 :                                    state.dataWaterThermalTanks->HPWaterHeater(HPNum).DXCoilName,
   10245          96 :                                    state.dataWaterThermalTanks->HPWaterHeater(HPNum).DXCoilNum,
   10246             :                                    HVAC::FanOp::Cycling,
   10247             :                                    HVAC::CompressorOp::On,
   10248          96 :                                    state.dataWaterThermalTanks->hpPartLoadRatio,
   10249             :                                    SpeedNum,
   10250             :                                    SpeedRatio,
   10251             :                                    0.0,
   10252             :                                    0.0,
   10253             :                                    true,
   10254             :                                    false,
   10255         192 :                                    1.0);
   10256             :     } else {
   10257       77894 :         VariableSpeedCoils::SimVariableSpeedCoils(state,
   10258       77894 :                                                   state.dataWaterThermalTanks->HPWaterHeater(HPNum).DXCoilName,
   10259       77894 :                                                   state.dataWaterThermalTanks->HPWaterHeater(HPNum).DXCoilNum,
   10260             :                                                   HVAC::FanOp::Cycling,
   10261             :                                                   HVAC::CompressorOp::On,
   10262       77894 :                                                   state.dataWaterThermalTanks->hpPartLoadRatio,
   10263             :                                                   SpeedNum,
   10264             :                                                   SpeedRatio,
   10265             :                                                   0.0,
   10266             :                                                   0.0,
   10267             :                                                   1.0);
   10268             :     }
   10269             : 
   10270             :     Real64 CondenserDeltaT;
   10271       77990 :     CondenserDeltaT = state.dataLoopNodes->Node(HPWaterOutletNode).Temp - state.dataLoopNodes->Node(HPWaterInletNode).Temp;
   10272             : 
   10273             :     //           move the full load outlet temperature rate to the water heater structure variables
   10274             :     //           (water heaters source inlet node temperature/mdot are set in Init, set it here after DXCoils::CalcHPWHDXCoil has been called)
   10275       77990 :     this->SourceInletTemp = state.dataLoopNodes->Node(HPWaterInletNode).Temp + CondenserDeltaT;
   10276             : 
   10277             :     //           this CALL does not update node temps, must use WaterThermalTank variables
   10278             :     // select tank type
   10279       77990 :     Real64 NewTankTemp = 0.0;
   10280       77990 :     if (state.dataWaterThermalTanks->HPWaterHeater(HPNum).HPWHTankType == DataPlant::PlantEquipmentType::WtrHeaterMixed) {
   10281       26838 :         this->CalcWaterThermalTankMixed(state);
   10282       26838 :         NewTankTemp = this->TankTemp;
   10283       51152 :     } else if (state.dataWaterThermalTanks->HPWaterHeater(HPNum).HPWHTankType == DataPlant::PlantEquipmentType::WtrHeaterStratified) {
   10284       51152 :         this->CalcWaterThermalTankStratified(state);
   10285       51152 :         NewTankTemp = this->FindStratifiedTankSensedTemp(state);
   10286             :     }
   10287             : 
   10288       77990 :     return desTankTemp - NewTankTemp;
   10289             : }
   10290             : 
   10291       57647 : Real64 WaterThermalTankData::PLRResidualHPWH(
   10292             :     EnergyPlusData &state, Real64 const HPPartLoadRatio, Real64 const desTankTemp, TankOperatingMode const mode, Real64 const mDotWater)
   10293             : {
   10294             :     // FUNCTION INFORMATION:
   10295             :     //       AUTHOR         B.Griffith,  Richard Raustad
   10296             :     //       DATE WRITTEN   Jan 2012
   10297             :     //       MODIFIED
   10298             :     //       RE-ENGINEERED  Noel Merket, Oct 2015
   10299             : 
   10300             :     // PURPOSE OF THIS FUNCTION:
   10301             :     //  Calculates residual function (desired tank temp - actual tank temp)
   10302             :     //  HP water heater output depends on the part load ratio which is being varied to zero the residual.
   10303             : 
   10304             :     // METHODOLOGY EMPLOYED:
   10305             :     //  Calls with CalcWaterThermalTankMixed or CalcWaterThermalTankStratified to get tank temperature at the given part load ratio (source water
   10306             :     //  mass flow rate) and calculates the residual as defined above
   10307             : 
   10308       57647 :     HeatPumpWaterHeaterData &HeatPump = state.dataWaterThermalTanks->HPWaterHeater(this->HeatPumpNum);
   10309       57647 :     bool const isVariableSpeed = (HeatPump.NumofSpeed > 0);
   10310       57647 :     this->Mode = mode;
   10311             :     // Apply the PLR
   10312       57647 :     if (this->WaterThermalTankType == DataPlant::PlantEquipmentType::WtrHeaterMixed) {
   10313             :         // For a mixed tank, the PLR is applied to the source mass flow rate.
   10314       22169 :         this->SourceMassFlowRate = mDotWater * HPPartLoadRatio;
   10315       22169 :         this->CalcWaterThermalTankMixed(state);
   10316             :     } else {
   10317       35478 :         assert(this->WaterThermalTankType == DataPlant::PlantEquipmentType::WtrHeaterStratified);
   10318             :         // For a stratified tank, the PLR is applied to the Coil.TotalHeatingEnergyRate
   10319             :         // whether that's a VarSpeedCoil or DXCoils::DXCoil.
   10320             :         // Here we create a pointer to the TotalHeatingEnergyRate for the appropriate coil type.
   10321             :         Real64 *CoilTotalHeatingEnergyRatePtr;
   10322       35478 :         if (isVariableSpeed) {
   10323         621 :             if (HeatPump.bIsIHP)
   10324           0 :                 CoilTotalHeatingEnergyRatePtr = &state.dataIntegratedHP->IntegratedHeatPumps(HeatPump.DXCoilNum).TotalWaterHeatingRate;
   10325             :             else
   10326         621 :                 CoilTotalHeatingEnergyRatePtr = &state.dataVariableSpeedCoils->VarSpeedCoil(HeatPump.DXCoilNum).TotalHeatingEnergyRate;
   10327             :         } else {
   10328       34857 :             CoilTotalHeatingEnergyRatePtr = &state.dataDXCoils->DXCoil(HeatPump.DXCoilNum).TotalHeatingEnergyRate;
   10329             :         }
   10330             :         // Copy the value of the total heating energy rate
   10331       35478 :         Real64 const CoilTotalHeatingEnergyRateBackup = *CoilTotalHeatingEnergyRatePtr;
   10332             :         // Apply the PLR
   10333       35478 :         *CoilTotalHeatingEnergyRatePtr *= HPPartLoadRatio;
   10334             :         // Tank Calculation
   10335       35478 :         this->CalcWaterThermalTankStratified(state);
   10336             :         // Restore the original value
   10337       35478 :         *CoilTotalHeatingEnergyRatePtr = CoilTotalHeatingEnergyRateBackup;
   10338             :     }
   10339       57647 :     Real64 NewTankTemp = this->GetHPWHSensedTankTemp(state);
   10340       57647 :     return desTankTemp - NewTankTemp;
   10341             : }
   10342             : 
   10343     1380552 : bool WaterThermalTankData::SourceHeatNeed(EnergyPlusData &state, Real64 const OutletTemp, Real64 const DeadBandTemp, Real64 const SetPointTemp_loc)
   10344             : {
   10345             :     // FUNCTION INFORMATION:
   10346             :     //       AUTHOR         Yueyue Zhou
   10347             :     //       DATE WRITTEN   May 2019
   10348             :     //       MODIFIED       na
   10349             :     //       RE-ENGINEERED  na
   10350             : 
   10351             :     // PURPOSE OF THIS FUNCTION:
   10352             :     // Determine by tank type, tank temperature and control mode if source side flow is needed
   10353             : 
   10354             :     // return value initialization
   10355     1380552 :     bool NeedsHeatOrCool = false;
   10356             : 
   10357     1380552 :     if (!this->IsChilledWaterTank) {
   10358      962056 :         if (this->SourceSideControlMode == SourceSideControl::IndirectHeatPrimarySetpoint) {
   10359      962056 :             if (OutletTemp < DeadBandTemp) {
   10360      143302 :                 NeedsHeatOrCool = true;
   10361      818754 :             } else if ((OutletTemp >= DeadBandTemp) && (OutletTemp < SetPointTemp_loc)) {
   10362             :                 // inside the deadband, use saved mode from water heater calcs
   10363      378433 :                 if (this->SavedMode == TankOperatingMode::Heating) {
   10364       88317 :                     NeedsHeatOrCool = true;
   10365      290116 :                 } else if (this->SavedMode == TankOperatingMode::Floating) {
   10366      290116 :                     NeedsHeatOrCool = false;
   10367             :                 }
   10368             : 
   10369      440321 :             } else if (OutletTemp >= SetPointTemp_loc) {
   10370      440321 :                 NeedsHeatOrCool = false;
   10371             :             }
   10372           0 :         } else if (this->SourceSideControlMode == SourceSideControl::IndirectHeatAltSetpoint) {
   10373             :             // get alternate setpoint
   10374           0 :             Real64 const AltSetpointTemp = ScheduleManager::GetCurrentScheduleValue(state, this->SourceSideAltSetpointSchedNum);
   10375           0 :             Real64 const AltDeadBandTemp = AltSetpointTemp - this->DeadBandDeltaTemp;
   10376           0 :             if (OutletTemp < AltDeadBandTemp) {
   10377           0 :                 NeedsHeatOrCool = true;
   10378           0 :             } else if ((OutletTemp >= AltDeadBandTemp) && (OutletTemp < AltSetpointTemp)) {
   10379             :                 // inside the deadband, use saved mode from water heater calcs
   10380           0 :                 if (this->SavedMode == TankOperatingMode::Heating) {
   10381           0 :                     NeedsHeatOrCool = true;
   10382           0 :                 } else if (this->SavedMode == TankOperatingMode::Floating) {
   10383           0 :                     NeedsHeatOrCool = false;
   10384             :                 }
   10385             : 
   10386           0 :             } else if (OutletTemp >= AltSetpointTemp) {
   10387           0 :                 NeedsHeatOrCool = false;
   10388             :             }
   10389           0 :         } else if (this->SourceSideControlMode == SourceSideControl::StorageTank) {
   10390           0 :             if (OutletTemp < this->TankTempLimit) {
   10391           0 :                 NeedsHeatOrCool = true;
   10392             :             } else {
   10393           0 :                 NeedsHeatOrCool = false;
   10394             :             }
   10395             :         }
   10396             :     } else { // is a chilled water tank so flip logic
   10397      418496 :         if (OutletTemp > DeadBandTemp) {
   10398       10920 :             NeedsHeatOrCool = true;
   10399      407576 :         } else if ((OutletTemp <= DeadBandTemp) && (OutletTemp > SetPointTemp_loc)) {
   10400             :             // inside the deadband, use saved mode from water thermal tank calcs (modes only for mixed)
   10401      301506 :             if (this->WaterThermalTankType == DataPlant::PlantEquipmentType::ChilledWaterTankMixed) {
   10402      275181 :                 if (this->SavedMode == TankOperatingMode::Cooling) {
   10403       36160 :                     NeedsHeatOrCool = true;
   10404      239021 :                 } else if (this->SavedMode == TankOperatingMode::Floating) {
   10405      239021 :                     NeedsHeatOrCool = false;
   10406             :                 }
   10407       26325 :             } else if (this->WaterThermalTankType == DataPlant::PlantEquipmentType::ChilledWaterTankStratified) {
   10408       26325 :                 NeedsHeatOrCool = true;
   10409             :             }
   10410             : 
   10411      106070 :         } else if (OutletTemp <= SetPointTemp_loc) {
   10412      106070 :             NeedsHeatOrCool = false;
   10413             :         }
   10414             :     }
   10415     1380552 :     return NeedsHeatOrCool;
   10416             : }
   10417             : 
   10418     7721520 : Real64 WaterThermalTankData::PlantMassFlowRatesFunc(EnergyPlusData &state,
   10419             :                                                     int const InNodeNum,
   10420             :                                                     bool const FirstHVACIteration,
   10421             :                                                     WaterHeaterSide const WaterThermalTankSide,
   10422             :                                                     const DataPlant::LoopSideLocation PlantLoopSide,
   10423             :                                                     [[maybe_unused]] bool const PlumbedInSeries,
   10424             :                                                     DataBranchAirLoopPlant::ControlType const BranchControlType,
   10425             :                                                     Real64 const OutletTemp,
   10426             :                                                     Real64 const DeadBandTemp,
   10427             :                                                     Real64 const SetPointTemp_loc)
   10428             : {
   10429             : 
   10430             :     // FUNCTION INFORMATION:
   10431             :     //       AUTHOR         Brent Griffith
   10432             :     //       DATE WRITTEN   October 2007
   10433             :     //       MODIFIED       na
   10434             :     //       RE-ENGINEERED  na
   10435             : 
   10436             :     // PURPOSE OF THIS FUNCTION:
   10437             :     // collect routines for setting flow rates for Water heaters
   10438             :     // with plant connections.
   10439             : 
   10440             :     // determine current mode.  there are three possible
   10441             :     //  1.  passing thru what was given to inlet node
   10442             :     //  2.  potentially making a flow request
   10443             :     //  3.  throttling flow in response to Plant's restrictions (MassFlowRateMaxAvail)
   10444             :     // init default mode changed to Unassigned
   10445     7721520 :     FlowMode CurrentMode = FlowMode::Invalid; // default
   10446             : 
   10447     7721520 :     if (PlantLoopSide == DataPlant::LoopSideLocation::Invalid) {
   10448      478220 :         CurrentMode = FlowMode::PassingFlowThru;
   10449     7243300 :     } else if (PlantLoopSide == DataPlant::LoopSideLocation::Supply) {
   10450             :         // If FlowLock is False (0), the tank sets the plant loop mdot
   10451             :         // If FlowLock is True (1),  the new resolved plant loop mdot is used
   10452     6683608 :         if (this->UseCurrentFlowLock == DataPlant::FlowLock::Unlocked) {
   10453     2781163 :             CurrentMode = FlowMode::PassingFlowThru;
   10454     2781163 :             if ((this->UseSideLoadRequested > 0.0) && (WaterThermalTankSide == WaterHeaterSide::Use)) {
   10455     2115551 :                 CurrentMode = FlowMode::MaybeRequestingFlow;
   10456             :             }
   10457             :         } else {
   10458     3902445 :             CurrentMode = FlowMode::PassingFlowThru;
   10459             :         }
   10460     6683608 :         if (WaterThermalTankSide == WaterHeaterSide::Source) {
   10461      820860 :             CurrentMode = FlowMode::MaybeRequestingFlow;
   10462             :         }
   10463      559692 :     } else if (PlantLoopSide == DataPlant::LoopSideLocation::Demand) {
   10464             : 
   10465             :         //  2.  Might be Requesting Flow.
   10466      559692 :         if (FirstHVACIteration) {
   10467      279604 :             if (BranchControlType == DataBranchAirLoopPlant::ControlType::Bypass) {
   10468           0 :                 CurrentMode = FlowMode::PassingFlowThru;
   10469             :             } else {
   10470      279604 :                 CurrentMode = FlowMode::MaybeRequestingFlow;
   10471             :             }
   10472             :         } else {
   10473      280088 :             if (BranchControlType == DataBranchAirLoopPlant::ControlType::Bypass) {
   10474           0 :                 CurrentMode = FlowMode::PassingFlowThru;
   10475             :             } else {
   10476      280088 :                 CurrentMode = FlowMode::ThrottlingFlow;
   10477             :             }
   10478             :         }
   10479             :     }
   10480             : 
   10481             :     // evaluate Availability schedule,
   10482     7721520 :     bool ScheduledAvail = true;
   10483     7721520 :     if (WaterThermalTankSide == WaterHeaterSide::Use) {
   10484     5862748 :         if (ScheduleManager::GetCurrentScheduleValue(state, this->UseSideAvailSchedNum) == 0.0) {
   10485           0 :             ScheduledAvail = false;
   10486             :         }
   10487     1858772 :     } else if (WaterThermalTankSide == WaterHeaterSide::Source) {
   10488     1858772 :         if (ScheduleManager::GetCurrentScheduleValue(state, this->SourceSideAvailSchedNum) == 0.0) {
   10489       58864 :             ScheduledAvail = false;
   10490             :         }
   10491             :     }
   10492             : 
   10493             :     // now act based on current mode
   10494     7721520 :     Real64 FlowResult = 0.0;
   10495     7721520 :     switch (CurrentMode) {
   10496             : 
   10497     4225417 :     case FlowMode::PassingFlowThru: {
   10498     4225417 :         if (!ScheduledAvail) {
   10499           0 :             FlowResult = 0.0;
   10500             :         } else {
   10501     4225417 :             FlowResult = state.dataLoopNodes->Node(InNodeNum).MassFlowRate;
   10502             :         }
   10503             : 
   10504     4225417 :         break;
   10505             :     }
   10506      280088 :     case FlowMode::ThrottlingFlow: {
   10507             :         // first determine what mass flow would be if it is to requested
   10508      280088 :         Real64 MassFlowRequest = 0.0;
   10509      280088 :         if (!ScheduledAvail) {
   10510       29432 :             MassFlowRequest = 0.0;
   10511             :         } else {
   10512      250656 :             if (WaterThermalTankSide == WaterHeaterSide::Use) {
   10513           0 :                 MassFlowRequest = this->PlantUseMassFlowRateMax;
   10514      250656 :             } else if (WaterThermalTankSide == WaterHeaterSide::Source) {
   10515      250656 :                 MassFlowRequest = this->PlantSourceMassFlowRateMax;
   10516             :             } else {
   10517           0 :                 assert(false);
   10518             :             }
   10519             :         }
   10520             : 
   10521             :         // next determine if tank temperature is such that source side flow might be requested
   10522      280088 :         bool NeedsHeatOrCool = this->SourceHeatNeed(state, OutletTemp, DeadBandTemp, SetPointTemp_loc);
   10523             : 
   10524      280088 :         if (MassFlowRequest > 0.0) {
   10525      250656 :             if (WaterThermalTankSide == WaterHeaterSide::Use) {
   10526           0 :                 FlowResult = MassFlowRequest;
   10527      250656 :             } else if (WaterThermalTankSide == WaterHeaterSide::Source) {
   10528      250656 :                 if (NeedsHeatOrCool) {
   10529       54324 :                     FlowResult = MassFlowRequest;
   10530             :                 } else {
   10531      196332 :                     FlowResult = 0.0;
   10532             :                 }
   10533             :             } else {
   10534           0 :                 assert(false);
   10535             :             }
   10536             :         } else {
   10537       29432 :             FlowResult = 0.0;
   10538             :         }
   10539             : 
   10540             :         // now throttle against MassFlowRateMaxAvail, MassFlowRateMinAvail, MassFlowRateMax, and MassFlowRateMin
   10541             :         // see notes about reverse dd compliance (specifically 5ZoneWaterSystems file)
   10542      280088 :         FlowResult = max(state.dataLoopNodes->Node(InNodeNum).MassFlowRateMinAvail, FlowResult); // okay for compliance (reverse dd)
   10543      280088 :         FlowResult = max(state.dataLoopNodes->Node(InNodeNum).MassFlowRateMin, FlowResult);      // okay for compliance (reverse dd)
   10544      280088 :         FlowResult = min(state.dataLoopNodes->Node(InNodeNum).MassFlowRateMaxAvail, FlowResult);
   10545             :         //=> following might take out of reverse dd compliance
   10546      280088 :         FlowResult = min(state.dataLoopNodes->Node(InNodeNum).MassFlowRateMax, FlowResult);
   10547             : 
   10548      280088 :         break;
   10549             :     }
   10550     3216015 :     case FlowMode::MaybeRequestingFlow: {
   10551             : 
   10552             :         // first determine what mass flow would be if it is to requested
   10553     3216015 :         Real64 MassFlowRequest = 0.0;
   10554     3216015 :         if (!ScheduledAvail) {
   10555       29432 :             MassFlowRequest = 0.0;
   10556             :         } else {
   10557     3186583 :             if (WaterThermalTankSide == WaterHeaterSide::Use) {
   10558     2115551 :                 if ((this->IsChilledWaterTank) && (this->UseSideLoadRequested > 0.0)) {
   10559       26542 :                     MassFlowRequest = this->PlantUseMassFlowRateMax;
   10560     2089009 :                 } else if ((this->IsChilledWaterTank) && (this->UseSideLoadRequested == 0.0)) {
   10561           0 :                     MassFlowRequest = 0.0;
   10562             :                 } else {
   10563     2089009 :                     MassFlowRequest = this->PlantUseMassFlowRateMax;
   10564             :                 }
   10565             : 
   10566     1071032 :             } else if (WaterThermalTankSide == WaterHeaterSide::Source) {
   10567     1071032 :                 MassFlowRequest = this->PlantSourceMassFlowRateMax;
   10568             :             }
   10569             :         }
   10570             : 
   10571     3216015 :         if (WaterThermalTankSide == WaterHeaterSide::Source) { // temperature dependent controls for indirect heating/cooling
   10572     1100464 :             bool NeedsHeatOrCool = this->SourceHeatNeed(state, OutletTemp, DeadBandTemp, SetPointTemp_loc);
   10573     1100464 :             if (MassFlowRequest > 0.0) {
   10574     1071011 :                 if (NeedsHeatOrCool) {
   10575      230170 :                     FlowResult = MassFlowRequest;
   10576             :                 } else {
   10577      840841 :                     FlowResult = 0.0;
   10578             :                 }
   10579             :             } else {
   10580       29453 :                 FlowResult = 0.0;
   10581             :             }
   10582             :         } else { // end source side, begin use side
   10583     2115551 :             if (MassFlowRequest > 0.0) {
   10584     2115551 :                 FlowResult = MassFlowRequest;
   10585             :             } else {
   10586           0 :                 FlowResult = 0.0;
   10587             :             }
   10588             :         }
   10589     3216015 :         break;
   10590             :     }
   10591           0 :     default:
   10592           0 :         break;
   10593             :     }
   10594             : 
   10595     7721520 :     if (FlowResult < HVAC::VerySmallMassFlow) FlowResult = 0.0; // Catch underflow problems
   10596             : 
   10597     7721520 :     return FlowResult;
   10598             : }
   10599             : 
   10600         968 : void WaterThermalTankData::MinePlantStructForInfo(EnergyPlusData &state)
   10601             : {
   10602             : 
   10603             :     // SUBROUTINE INFORMATION:
   10604             :     //       AUTHOR         Brent Griffith
   10605             :     //       DATE WRITTEN   October 2007
   10606             :     //       MODIFIED       na
   10607             :     //       RE-ENGINEERED  na
   10608             : 
   10609             :     // PURPOSE OF THIS SUBROUTINE:
   10610             :     // get information from plant loop data structure
   10611             :     // check what we can learn from plant structure against user inputs
   10612             : 
   10613         968 :     bool ErrorsFound = false;
   10614             : 
   10615         968 :     if (allocated(state.dataPlnt->PlantLoop) && this->UseSidePlantLoc.loopNum > 0) {
   10616             : 
   10617             :         // check plant structure for useful data.
   10618             : 
   10619         895 :         int PlantLoopNum = this->UseSidePlantLoc.loopNum;
   10620         895 :         DataPlant::LoopSideLocation LoopSideNum = this->UseSidePlantLoc.loopSideNum;
   10621             : 
   10622         895 :         if ((this->UseDesignVolFlowRateWasAutoSized) && (this->UseSidePlantSizNum == 0)) {
   10623           0 :             ShowSevereError(state,
   10624           0 :                             format("Water heater = {} for autosizing Use side flow rate, did not find Sizing:Plant object {}",
   10625           0 :                                    this->Name,
   10626           0 :                                    state.dataPlnt->PlantLoop(PlantLoopNum).Name));
   10627           0 :             ErrorsFound = true;
   10628             :         }
   10629             :         // Is this wh Use side plumbed in series (default) or are there other branches in parallel?
   10630         895 :         if (state.dataPlnt->PlantLoop(PlantLoopNum).LoopSide(LoopSideNum).Splitter.Exists) {
   10631         895 :             if (any_eq(state.dataPlnt->PlantLoop(PlantLoopNum).LoopSide(LoopSideNum).Splitter.NodeNumOut,
   10632         895 :                        this->UseInletNode)) { // this wh is on the splitter
   10633         860 :                 if (state.dataPlnt->PlantLoop(PlantLoopNum).LoopSide(LoopSideNum).Splitter.TotalOutletNodes > 1) {
   10634         784 :                     this->UseSideSeries = false;
   10635             :                 }
   10636             :             }
   10637             :         }
   10638             :     }
   10639             : 
   10640         968 :     if (allocated(state.dataPlnt->PlantLoop) && this->SrcSidePlantLoc.loopNum > 0) {
   10641             :         // was user's input correct for plant loop name?
   10642         231 :         if ((this->SourceDesignVolFlowRateWasAutoSized) && (this->SourceSidePlantSizNum == 0) && (this->DesuperheaterNum == 0) &&
   10643           0 :             (this->HeatPumpNum == 0)) {
   10644           0 :             ShowSevereError(state,
   10645           0 :                             format("Water heater = {}for autosizing Source side flow rate, did not find Sizing:Plant object {}",
   10646           0 :                                    this->Name,
   10647           0 :                                    state.dataPlnt->PlantLoop(this->SrcSidePlantLoc.loopNum).Name));
   10648           0 :             ErrorsFound = true;
   10649             :         }
   10650             :         // Is this wh Source side plumbed in series (default) or are there other branches in parallel?
   10651         231 :         if (state.dataPlnt->PlantLoop(this->SrcSidePlantLoc.loopNum).LoopSide(this->SrcSidePlantLoc.loopSideNum).Splitter.Exists) {
   10652         231 :             if (any_eq(state.dataPlnt->PlantLoop(this->SrcSidePlantLoc.loopNum).LoopSide(this->SrcSidePlantLoc.loopSideNum).Splitter.NodeNumOut,
   10653         231 :                        this->SourceInletNode)) { // this wh is on the splitter
   10654         231 :                 if (state.dataPlnt->PlantLoop(this->SrcSidePlantLoc.loopNum).LoopSide(this->SrcSidePlantLoc.loopSideNum).Splitter.TotalOutletNodes >
   10655             :                     1) {
   10656          77 :                     this->SourceSideSeries = false;
   10657             :                 }
   10658             :             }
   10659             :         }
   10660             :     }
   10661             : 
   10662         968 :     if (ErrorsFound) {
   10663           0 :         ShowFatalError(state, "Preceding water heater input errors cause program termination");
   10664             :     }
   10665         968 : }
   10666             : 
   10667         766 : void WaterThermalTankData::SizeSupplySidePlantConnections(EnergyPlusData &state, const int loopNum)
   10668             : {
   10669             : 
   10670             :     // SUBROUTINE INFORMATION:
   10671             :     //       AUTHOR         Brent Griffith
   10672             :     //       DATE WRITTEN   October 2007
   10673             :     //       MODIFIED       na
   10674             :     //       RE-ENGINEERED  na
   10675             : 
   10676             :     // PURPOSE OF THIS SUBROUTINE:
   10677             :     // This subroutine is for sizing water heater plant connection flow rates
   10678             :     // on the supply that have not been specified in the input.
   10679             : 
   10680             :     // METHODOLOGY EMPLOYED:
   10681             :     // This routine is called later in the simulation than the sizing routine for the demand side
   10682             :     //  because the simulation needs to be further along before the needed data are available.
   10683             :     // For water heaters sides on Supply LoopSide, obtains hot water flow rate from the plant sizing array
   10684             :     //  (adapted approach from boiler sizing routines)
   10685             : 
   10686             :     static constexpr std::string_view RoutineName("SizeSupplySidePlantConnections");
   10687             : 
   10688         766 :     auto &PlantSizData = state.dataSize->PlantSizData;
   10689             : 
   10690         766 :     Real64 tmpUseDesignVolFlowRate = this->UseDesignVolFlowRate;
   10691         766 :     Real64 tmpSourceDesignVolFlowRate = this->SourceDesignVolFlowRate;
   10692             : 
   10693         766 :     if ((this->UseInletNode > 0) && (loopNum == this->UseSidePlantLoc.loopNum)) {
   10694         661 :         if (this->UseDesignVolFlowRateWasAutoSized) {
   10695         631 :             int PltSizNum = this->UseSidePlantSizNum;
   10696         631 :             if (PltSizNum > 0) { // we have a Plant Sizing Object
   10697         631 :                 if (this->UseSidePlantLoc.loopSideNum == DataPlant::LoopSideLocation::Supply) {
   10698         631 :                     if (PlantSizData(PltSizNum).DesVolFlowRate >= HVAC::SmallWaterVolFlow) {
   10699         508 :                         if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
   10700         139 :                             this->UseDesignVolFlowRate = PlantSizData(PltSizNum).DesVolFlowRate;
   10701             :                         } else {
   10702         369 :                             tmpUseDesignVolFlowRate = PlantSizData(PltSizNum).DesVolFlowRate;
   10703             :                         }
   10704             :                     } else {
   10705         123 :                         if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
   10706           0 :                             this->UseDesignVolFlowRate = 0.0;
   10707             :                         } else {
   10708         123 :                             tmpUseDesignVolFlowRate = 0.0;
   10709             :                         }
   10710             :                     }
   10711         631 :                     if (state.dataPlnt->PlantFinalSizesOkayToReport) {
   10712         123 :                         BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Use Side Design Flow Rate [m3/s]", this->UseDesignVolFlowRate);
   10713             :                     }
   10714         631 :                     if (state.dataPlnt->PlantFirstSizesOkayToReport) {
   10715           8 :                         BaseSizer::reportSizerOutput(
   10716             :                             state, this->Type, this->Name, "Initial Use Side Design Flow Rate [m3/s]", this->UseDesignVolFlowRate);
   10717             :                     }
   10718         631 :                     if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
   10719         139 :                         PlantUtilities::RegisterPlantCompDesignFlow(state, this->UseInletNode, this->UseDesignVolFlowRate);
   10720             :                     } else {
   10721         492 :                         PlantUtilities::RegisterPlantCompDesignFlow(state, this->UseInletNode, tmpUseDesignVolFlowRate);
   10722             :                     }
   10723             : 
   10724         631 :                     Real64 rho = FluidProperties::GetDensityGlycol(state,
   10725         631 :                                                                    state.dataPlnt->PlantLoop(this->UseSidePlantLoc.loopNum).FluidName,
   10726             :                                                                    Constant::InitConvTemp,
   10727         631 :                                                                    state.dataPlnt->PlantLoop(this->UseSidePlantLoc.loopNum).FluidIndex,
   10728             :                                                                    RoutineName);
   10729         631 :                     if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
   10730         139 :                         this->PlantUseMassFlowRateMax = this->UseDesignVolFlowRate * rho;
   10731             :                     } else {
   10732         492 :                         this->PlantUseMassFlowRateMax = tmpUseDesignVolFlowRate * rho;
   10733             :                     }
   10734             :                 }
   10735             :             } else {
   10736             :                 // do nothing
   10737             :             } // plant sizing object
   10738             :         } else {
   10739          30 :             PlantUtilities::RegisterPlantCompDesignFlow(state, this->UseInletNode, this->UseDesignVolFlowRate);
   10740             :             Real64 rho;
   10741          30 :             if (this->UseSidePlantLoc.loopNum > 0) {
   10742          30 :                 rho = FluidProperties::GetDensityGlycol(state,
   10743          30 :                                                         state.dataPlnt->PlantLoop(this->UseSidePlantLoc.loopNum).FluidName,
   10744             :                                                         Constant::InitConvTemp,
   10745          30 :                                                         state.dataPlnt->PlantLoop(this->UseSidePlantLoc.loopNum).FluidIndex,
   10746             :                                                         RoutineName);
   10747             :             } else {
   10748           0 :                 rho = FluidProperties::GetDensityGlycol(state, fluidNameWater, Constant::InitConvTemp, this->waterIndex, RoutineName);
   10749             :             }
   10750             : 
   10751          30 :             this->PlantUseMassFlowRateMax = this->UseDesignVolFlowRate * rho;
   10752             : 
   10753             :         } // autosizing needed.
   10754             :     }     // connected to plant
   10755             : 
   10756         766 :     if ((this->SourceInletNode > 0) && (loopNum == this->SrcSidePlantLoc.loopNum)) {
   10757         105 :         if (this->SourceDesignVolFlowRateWasAutoSized) {
   10758          55 :             int PltSizNum = this->SourceSidePlantSizNum;
   10759          55 :             if (PltSizNum > 0) {
   10760          55 :                 if (this->SrcSidePlantLoc.loopSideNum == DataPlant::LoopSideLocation::Supply) {
   10761          25 :                     if (PlantSizData(PltSizNum).DesVolFlowRate >= HVAC::SmallWaterVolFlow) {
   10762          18 :                         if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
   10763           5 :                             this->SourceDesignVolFlowRate = PlantSizData(PltSizNum).DesVolFlowRate;
   10764             :                         } else {
   10765          13 :                             tmpSourceDesignVolFlowRate = PlantSizData(PltSizNum).DesVolFlowRate;
   10766             :                         }
   10767             :                     } else {
   10768           7 :                         if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
   10769           0 :                             this->SourceDesignVolFlowRate = 0.0;
   10770             :                         } else {
   10771           7 :                             tmpSourceDesignVolFlowRate = 0.0;
   10772             :                         }
   10773             :                     }
   10774          25 :                     if (state.dataPlnt->PlantFinalSizesOkayToReport) {
   10775           5 :                         BaseSizer::reportSizerOutput(
   10776             :                             state, this->Type, this->Name, "Source Side Design Flow Rate [m3/s]", this->SourceDesignVolFlowRate);
   10777             :                     }
   10778          25 :                     if (state.dataPlnt->PlantFirstSizesOkayToReport) {
   10779           0 :                         BaseSizer::reportSizerOutput(
   10780             :                             state, this->Type, this->Name, "Initial Source Side Design Flow Rate [m3/s]", this->SourceDesignVolFlowRate);
   10781             :                     }
   10782          25 :                     if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
   10783           5 :                         PlantUtilities::RegisterPlantCompDesignFlow(state, this->SourceInletNode, this->SourceDesignVolFlowRate);
   10784             :                     } else {
   10785          20 :                         PlantUtilities::RegisterPlantCompDesignFlow(state, this->SourceInletNode, tmpSourceDesignVolFlowRate);
   10786             :                     }
   10787          25 :                     Real64 rho = FluidProperties::GetDensityGlycol(state,
   10788          25 :                                                                    state.dataPlnt->PlantLoop(this->SrcSidePlantLoc.loopNum).FluidName,
   10789             :                                                                    Constant::InitConvTemp,
   10790          25 :                                                                    state.dataPlnt->PlantLoop(this->SrcSidePlantLoc.loopNum).FluidIndex,
   10791             :                                                                    RoutineName);
   10792          25 :                     if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
   10793           5 :                         this->PlantSourceMassFlowRateMax = this->SourceDesignVolFlowRate * rho;
   10794             :                     } else {
   10795          20 :                         this->PlantSourceMassFlowRateMax = tmpSourceDesignVolFlowRate * rho;
   10796             :                     }
   10797             :                 } // plant loop allocation
   10798             :             } else {
   10799             :                 // do nothing
   10800             :             } // plant sizing object
   10801             :         } else {
   10802          50 :             if (this->SrcSidePlantLoc.loopSideNum == DataPlant::LoopSideLocation::Supply) {
   10803          45 :                 PlantUtilities::RegisterPlantCompDesignFlow(state, this->SourceInletNode, this->SourceDesignVolFlowRate);
   10804             :                 Real64 rho;
   10805          45 :                 if (this->SrcSidePlantLoc.loopNum > 0) {
   10806          45 :                     rho = FluidProperties::GetDensityGlycol(state,
   10807          45 :                                                             state.dataPlnt->PlantLoop(this->SrcSidePlantLoc.loopNum).FluidName,
   10808             :                                                             Constant::InitConvTemp,
   10809          45 :                                                             state.dataPlnt->PlantLoop(this->SrcSidePlantLoc.loopNum).FluidIndex,
   10810             :                                                             RoutineName);
   10811             :                 } else {
   10812           0 :                     rho = FluidProperties::GetDensityGlycol(state, fluidNameWater, Constant::InitConvTemp, this->waterIndex, RoutineName);
   10813             :                 }
   10814          45 :                 this->PlantSourceMassFlowRateMax = this->SourceDesignVolFlowRate * rho;
   10815             :             }
   10816             :         } // autosizing needed.
   10817             :     }     // connected to plant
   10818         766 : }
   10819             : 
   10820         766 : void WaterThermalTankData::SizeTankForDemandSide(EnergyPlusData &state)
   10821             : {
   10822             : 
   10823             :     // SUBROUTINE INFORMATION:
   10824             :     //       AUTHOR         Brent Griffith
   10825             :     //       DATE WRITTEN   February 2008
   10826             :     //       MODIFIED       na
   10827             :     //       RE-ENGINEERED  na
   10828             : 
   10829             :     // PURPOSE OF THIS SUBROUTINE:
   10830             :     // This subroutine is for sizing water heater tank volume and heater
   10831             :     //  as best we can at this point in simulation. (prior to demand side
   10832             :     //  sizing that needs volume).
   10833             : 
   10834             :     // METHODOLOGY EMPLOYED:
   10835             :     //  depending on the sizing design mode...
   10836             : 
   10837             :     // REFERENCES:
   10838             :     // BA benchmark report for residential design mode
   10839             : 
   10840             :     // SUBROUTINE PARAMETER DEFINITIONS:
   10841             :     static constexpr std::string_view RoutineName("SizeTankForDemandSide");
   10842         766 :     Real64 constexpr GalTocubicMeters(0.0037854);
   10843         766 :     Real64 constexpr kBtuPerHrToWatts(293.1);
   10844             : 
   10845         766 :     Real64 Tstart = 14.44;
   10846         766 :     Real64 Tfinish = 57.22;
   10847             : 
   10848         766 :     Real64 tmpTankVolume = this->Volume;
   10849         766 :     Real64 tmpMaxCapacity = this->MaxCapacity;
   10850             : 
   10851         766 :     switch (this->Sizing.DesignMode) {
   10852             : 
   10853         751 :     case SizingMode::Invalid:
   10854             :     case SizingMode::PeakDraw: {
   10855             : 
   10856         751 :         break;
   10857             :     }
   10858          15 :     case SizingMode::ResidentialMin: {
   10859             : 
   10860             :         // assume can propagate rules for gas to other fuels.
   10861          15 :         bool FuelTypeIsLikeGas = false;
   10862          15 :         switch (this->FuelType) {
   10863           0 :         case Constant::eFuel::NaturalGas:
   10864             :         case Constant::eFuel::Diesel:
   10865             :         case Constant::eFuel::Gasoline:
   10866             :         case Constant::eFuel::Coal:
   10867             :         case Constant::eFuel::FuelOilNo1:
   10868             :         case Constant::eFuel::FuelOilNo2:
   10869             :         case Constant::eFuel::Propane:
   10870             :         case Constant::eFuel::OtherFuel1:
   10871             :         case Constant::eFuel::OtherFuel2:
   10872             :         case Constant::eFuel::DistrictHeatingWater:
   10873             :         case Constant::eFuel::DistrictHeatingSteam:
   10874           0 :             FuelTypeIsLikeGas = true;
   10875           0 :             break;
   10876          15 :         default: // FuelTypeIsLikeGas stays false
   10877          15 :             break;
   10878             :         }
   10879             : 
   10880          15 :         if (this->Sizing.NumberOfBedrooms == 1) {
   10881           0 :             if (this->FuelType == Constant::eFuel::Electricity) {
   10882           0 :                 if (this->VolumeWasAutoSized) tmpTankVolume = 20.0 * GalTocubicMeters;
   10883           0 :                 if (this->MaxCapacityWasAutoSized) tmpMaxCapacity = 2.5 * 1000.0; // 2.5 kW
   10884           0 :             } else if (FuelTypeIsLikeGas) {
   10885           0 :                 if (this->VolumeWasAutoSized) tmpTankVolume = 20.0 * GalTocubicMeters;
   10886           0 :                 if (this->MaxCapacityWasAutoSized) tmpMaxCapacity = 27.0 * kBtuPerHrToWatts; // 27kBtu/hr
   10887             :             }
   10888             : 
   10889          15 :         } else if (this->Sizing.NumberOfBedrooms == 2) {
   10890           0 :             if (this->Sizing.NumberOfBathrooms <= 1.5) {
   10891           0 :                 if (this->FuelType == Constant::eFuel::Electricity) {
   10892           0 :                     if (this->VolumeWasAutoSized) tmpTankVolume = 30.0 * GalTocubicMeters;
   10893           0 :                     if (this->MaxCapacityWasAutoSized) tmpMaxCapacity = 3.5 * 1000.0; // 3.5 kW
   10894           0 :                 } else if (FuelTypeIsLikeGas) {
   10895           0 :                     if (this->VolumeWasAutoSized) tmpTankVolume = 30.0 * GalTocubicMeters;
   10896           0 :                     if (this->MaxCapacityWasAutoSized) tmpMaxCapacity = 36.0 * kBtuPerHrToWatts; // 36 kBtu/hr
   10897             :                 }
   10898           0 :             } else if ((this->Sizing.NumberOfBathrooms > 1.5) && (this->Sizing.NumberOfBathrooms < 3.0)) {
   10899           0 :                 if (this->FuelType == Constant::eFuel::Electricity) {
   10900           0 :                     if (this->VolumeWasAutoSized) tmpTankVolume = 40.0 * GalTocubicMeters;
   10901           0 :                     if (this->MaxCapacityWasAutoSized) tmpMaxCapacity = 4.5 * 1000.0; // 4.5 kW
   10902           0 :                 } else if (FuelTypeIsLikeGas) {
   10903           0 :                     if (this->VolumeWasAutoSized) tmpTankVolume = 30.0 * GalTocubicMeters;
   10904           0 :                     if (this->MaxCapacityWasAutoSized) tmpMaxCapacity = 36.0 * kBtuPerHrToWatts; // 36 kBtu/hr
   10905             :                 }
   10906           0 :             } else if (this->Sizing.NumberOfBathrooms >= 3.0) {
   10907           0 :                 if (this->FuelType == Constant::eFuel::Electricity) {
   10908           0 :                     if (this->VolumeWasAutoSized) tmpTankVolume = 50.0 * GalTocubicMeters;
   10909           0 :                     if (this->MaxCapacityWasAutoSized) tmpMaxCapacity = 5.5 * 1000.0; // 5.5 kW
   10910           0 :                 } else if (FuelTypeIsLikeGas) {
   10911           0 :                     if (this->VolumeWasAutoSized) tmpTankVolume = 40.0 * GalTocubicMeters;
   10912           0 :                     if (this->MaxCapacityWasAutoSized) tmpMaxCapacity = 36.0 * kBtuPerHrToWatts; // 36 kBtu/hr
   10913             :                 }
   10914             :             }
   10915          15 :         } else if (this->Sizing.NumberOfBedrooms == 3) {
   10916          15 :             if (this->Sizing.NumberOfBathrooms <= 1.5) {
   10917           0 :                 if (this->FuelType == Constant::eFuel::Electricity) {
   10918           0 :                     if (this->VolumeWasAutoSized) tmpTankVolume = 40.0 * GalTocubicMeters;
   10919           0 :                     if (this->MaxCapacityWasAutoSized) tmpMaxCapacity = 4.5 * 1000.0; // 4.5 kW
   10920           0 :                 } else if (FuelTypeIsLikeGas) {
   10921           0 :                     if (this->VolumeWasAutoSized) tmpTankVolume = 30.0 * GalTocubicMeters;
   10922           0 :                     if (this->MaxCapacityWasAutoSized) tmpMaxCapacity = 36.0 * kBtuPerHrToWatts; // 36 kBtu/hr
   10923             :                 }
   10924          15 :             } else if ((this->Sizing.NumberOfBathrooms > 1.5) && (this->Sizing.NumberOfBathrooms < 3.0)) {
   10925           0 :                 if (this->FuelType == Constant::eFuel::Electricity) {
   10926           0 :                     if (this->VolumeWasAutoSized) tmpTankVolume = 50.0 * GalTocubicMeters;
   10927           0 :                     if (this->MaxCapacityWasAutoSized) tmpMaxCapacity = 5.5 * 1000.0; // 5.5 kW
   10928           0 :                 } else if (FuelTypeIsLikeGas) {
   10929           0 :                     if (this->VolumeWasAutoSized) tmpTankVolume = 40.0 * GalTocubicMeters;
   10930           0 :                     if (this->MaxCapacityWasAutoSized) tmpMaxCapacity = 36.0 * kBtuPerHrToWatts; // 36 kBtu/hr
   10931             :                 }
   10932          15 :             } else if (this->Sizing.NumberOfBathrooms >= 3.0) {
   10933          15 :                 if (this->FuelType == Constant::eFuel::Electricity) {
   10934          15 :                     if (this->VolumeWasAutoSized) tmpTankVolume = 50.0 * GalTocubicMeters;
   10935          15 :                     if (this->MaxCapacityWasAutoSized) tmpMaxCapacity = 5.5 * 1000.0; // 5.5 kW
   10936           0 :                 } else if (FuelTypeIsLikeGas) {
   10937           0 :                     if (this->VolumeWasAutoSized) tmpTankVolume = 40.0 * GalTocubicMeters;
   10938           0 :                     if (this->MaxCapacityWasAutoSized) tmpMaxCapacity = 38.0 * kBtuPerHrToWatts; // 38 kBtu/hr
   10939             :                 }
   10940             :             }
   10941           0 :         } else if (this->Sizing.NumberOfBedrooms == 4) {
   10942           0 :             if (this->Sizing.NumberOfBathrooms <= 1.5) {
   10943           0 :                 if (this->FuelType == Constant::eFuel::Electricity) {
   10944           0 :                     if (this->VolumeWasAutoSized) tmpTankVolume = 50.0 * GalTocubicMeters;
   10945           0 :                     if (this->MaxCapacityWasAutoSized) tmpMaxCapacity = 5.5 * 1000.0; // 5.5 kW
   10946           0 :                 } else if (FuelTypeIsLikeGas) {
   10947           0 :                     if (this->VolumeWasAutoSized) tmpTankVolume = 40.0 * GalTocubicMeters;
   10948           0 :                     if (this->MaxCapacityWasAutoSized) tmpMaxCapacity = 36.0 * kBtuPerHrToWatts; // 36 kBtu/hr
   10949             :                 }
   10950           0 :             } else if ((this->Sizing.NumberOfBathrooms > 1.5) && (this->Sizing.NumberOfBathrooms < 3.0)) {
   10951           0 :                 if (this->FuelType == Constant::eFuel::Electricity) {
   10952           0 :                     if (this->VolumeWasAutoSized) tmpTankVolume = 50.0 * GalTocubicMeters;
   10953           0 :                     if (this->MaxCapacityWasAutoSized) tmpMaxCapacity = 5.5 * 1000.0; // 5.5 kW
   10954           0 :                 } else if (FuelTypeIsLikeGas) {
   10955           0 :                     if (this->VolumeWasAutoSized) tmpTankVolume = 40.0 * GalTocubicMeters;
   10956           0 :                     if (this->MaxCapacityWasAutoSized) tmpMaxCapacity = 38.0 * kBtuPerHrToWatts; // 38 kBtu/hr
   10957             :                 }
   10958           0 :             } else if (this->Sizing.NumberOfBathrooms >= 3.0) {
   10959           0 :                 if (this->FuelType == Constant::eFuel::Electricity) {
   10960           0 :                     if (this->VolumeWasAutoSized) tmpTankVolume = 66.0 * GalTocubicMeters;
   10961           0 :                     if (this->MaxCapacityWasAutoSized) tmpMaxCapacity = 5.5 * 1000.0; // 5.5 kW
   10962           0 :                 } else if (FuelTypeIsLikeGas) {
   10963           0 :                     if (this->VolumeWasAutoSized) tmpTankVolume = 50.0 * GalTocubicMeters;
   10964           0 :                     if (this->MaxCapacityWasAutoSized) tmpMaxCapacity = 38.0 * kBtuPerHrToWatts; // 38 kBtu/hr
   10965             :                 }
   10966             :             }
   10967           0 :         } else if (this->Sizing.NumberOfBedrooms == 5) {
   10968           0 :             if (this->FuelType == Constant::eFuel::Electricity) {
   10969           0 :                 if (this->VolumeWasAutoSized) tmpTankVolume = 66.0 * GalTocubicMeters;
   10970           0 :                 if (this->MaxCapacityWasAutoSized) tmpMaxCapacity = 5.5 * 1000.0; // 5.5 kW
   10971           0 :             } else if (FuelTypeIsLikeGas) {
   10972           0 :                 if (this->VolumeWasAutoSized) tmpTankVolume = 50.0 * GalTocubicMeters;
   10973           0 :                 if (this->MaxCapacityWasAutoSized) tmpMaxCapacity = 47.0 * kBtuPerHrToWatts; // 47 kBtu/hr
   10974             :             }
   10975           0 :         } else if (this->Sizing.NumberOfBedrooms >= 6) {
   10976           0 :             if (this->FuelType == Constant::eFuel::Electricity) {
   10977           0 :                 if (this->VolumeWasAutoSized) tmpTankVolume = 66.0 * GalTocubicMeters;
   10978           0 :                 if (this->MaxCapacityWasAutoSized) tmpMaxCapacity = 5.5 * 1000.0; // 5.5 kW
   10979           0 :             } else if (FuelTypeIsLikeGas) {
   10980           0 :                 if (this->VolumeWasAutoSized) tmpTankVolume = 50.0 * GalTocubicMeters;
   10981           0 :                 if (this->MaxCapacityWasAutoSized) tmpMaxCapacity = 50.0 * kBtuPerHrToWatts; // 50 kBtu/hr
   10982             :             }
   10983             :         }
   10984             : 
   10985          15 :         if (this->VolumeWasAutoSized && state.dataPlnt->PlantFirstSizesOkayToFinalize) {
   10986           0 :             this->Volume = tmpTankVolume;
   10987           0 :             if (state.dataPlnt->PlantFinalSizesOkayToReport) {
   10988           0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Tank Volume [m3]", this->Volume);
   10989             :             }
   10990           0 :             if (state.dataPlnt->PlantFirstSizesOkayToReport) {
   10991           0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Initial Tank Volume [m3]", this->Volume);
   10992             :             }
   10993             :         }
   10994          15 :         if (this->MaxCapacityWasAutoSized && state.dataPlnt->PlantFirstSizesOkayToFinalize) {
   10995           3 :             this->MaxCapacity = tmpMaxCapacity;
   10996           3 :             if (state.dataPlnt->PlantFinalSizesOkayToReport) {
   10997           3 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Maximum Heater Capacity [W]", this->MaxCapacity);
   10998             :             }
   10999           3 :             if (state.dataPlnt->PlantFirstSizesOkayToReport) {
   11000           0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Initial Maximum Heater Capacity [W]", this->MaxCapacity);
   11001             :             }
   11002             :         }
   11003          15 :         break;
   11004             :     }
   11005           0 :     case SizingMode::PerPerson: {
   11006             :         // how to get number of people?
   11007             : 
   11008             :         // MJW TODO: this won't compile now: Real64 SumPeopleAllZones = sum(state.dataHeatBal->Zone, &DataHeatBalance::ZoneData::TotOccupants);
   11009           0 :         Real64 SumPeopleAllZones = 0.0;
   11010           0 :         for (auto &thisZone : state.dataHeatBal->Zone) {
   11011           0 :             SumPeopleAllZones += thisZone.TotOccupants;
   11012           0 :         }
   11013           0 :         if (this->VolumeWasAutoSized) tmpTankVolume = this->Sizing.TankCapacityPerPerson * SumPeopleAllZones;
   11014             : 
   11015           0 :         if (this->MaxCapacityWasAutoSized) {
   11016             :             Real64 rho;
   11017             :             Real64 Cp;
   11018           0 :             if (this->UseSidePlantLoc.loopNum > 0) {
   11019           0 :                 rho = FluidProperties::GetDensityGlycol(state,
   11020           0 :                                                         state.dataPlnt->PlantLoop(this->UseSidePlantLoc.loopNum).FluidName,
   11021           0 :                                                         ((Tfinish + Tstart) / 2.0),
   11022           0 :                                                         state.dataPlnt->PlantLoop(this->UseSidePlantLoc.loopNum).FluidIndex,
   11023             :                                                         RoutineName);
   11024           0 :                 Cp = FluidProperties::GetSpecificHeatGlycol(state,
   11025           0 :                                                             state.dataPlnt->PlantLoop(this->UseSidePlantLoc.loopNum).FluidName,
   11026           0 :                                                             ((Tfinish + Tstart) / 2.0),
   11027           0 :                                                             state.dataPlnt->PlantLoop(this->UseSidePlantLoc.loopNum).FluidIndex,
   11028             :                                                             RoutineName);
   11029             :             } else {
   11030           0 :                 rho = FluidProperties::GetDensityGlycol(state, fluidNameWater, ((Tfinish + Tstart) / 2.0), this->waterIndex, RoutineName);
   11031           0 :                 Cp = FluidProperties::GetSpecificHeatGlycol(state, fluidNameWater, ((Tfinish + Tstart) / 2.0), this->waterIndex, RoutineName);
   11032             :             }
   11033             : 
   11034           0 :             tmpMaxCapacity = SumPeopleAllZones * this->Sizing.RecoveryCapacityPerPerson * (Tfinish - Tstart) * (1.0 / Constant::SecInHour) * rho *
   11035             :                              Cp; // m3/hr/person | delta T  in K | 1 hr/ 3600 s | kg/m3 | J/Kg/k
   11036             :         }
   11037             : 
   11038           0 :         if (this->VolumeWasAutoSized && state.dataPlnt->PlantFirstSizesOkayToFinalize) {
   11039           0 :             this->Volume = tmpTankVolume;
   11040           0 :             if (state.dataPlnt->PlantFinalSizesOkayToReport) {
   11041           0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Tank Volume [m3]", this->Volume);
   11042             :             }
   11043           0 :             if (state.dataPlnt->PlantFirstSizesOkayToReport) {
   11044           0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Initial Tank Volume [m3]", this->Volume);
   11045             :             }
   11046             :         }
   11047           0 :         if (this->MaxCapacityWasAutoSized && state.dataPlnt->PlantFirstSizesOkayToFinalize) {
   11048           0 :             this->MaxCapacity = tmpMaxCapacity;
   11049           0 :             if (state.dataPlnt->PlantFinalSizesOkayToReport) {
   11050           0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Maximum Heater Capacity [W]", this->MaxCapacity);
   11051             :             }
   11052           0 :             if (state.dataPlnt->PlantFirstSizesOkayToReport) {
   11053           0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Initial Maximum Heater Capacity [W]", this->MaxCapacity);
   11054             :             }
   11055             :         }
   11056           0 :         break;
   11057             :     }
   11058           0 :     case SizingMode::PerFloorArea: {
   11059             : 
   11060             :         // MJW TODO: this won't compile now: Real64 SumFloorAreaAllZones = sum(state.dataHeatBal->Zone, &DataHeatBalance::ZoneData::FloorArea);
   11061           0 :         Real64 SumFloorAreaAllZones = 0.0;
   11062           0 :         for (auto &thisZone : state.dataHeatBal->Zone) {
   11063           0 :             SumFloorAreaAllZones += thisZone.FloorArea;
   11064           0 :         }
   11065           0 :         if (this->VolumeWasAutoSized) tmpTankVolume = this->Sizing.TankCapacityPerArea * SumFloorAreaAllZones;
   11066           0 :         if (this->MaxCapacityWasAutoSized) {
   11067             :             Real64 rho;
   11068             :             Real64 Cp;
   11069           0 :             if (this->UseSidePlantLoc.loopNum > 0) {
   11070           0 :                 rho = FluidProperties::GetDensityGlycol(state,
   11071           0 :                                                         state.dataPlnt->PlantLoop(this->UseSidePlantLoc.loopNum).FluidName,
   11072           0 :                                                         ((Tfinish + Tstart) / 2.0),
   11073           0 :                                                         state.dataPlnt->PlantLoop(this->UseSidePlantLoc.loopNum).FluidIndex,
   11074             :                                                         RoutineName);
   11075           0 :                 Cp = FluidProperties::GetSpecificHeatGlycol(state,
   11076           0 :                                                             state.dataPlnt->PlantLoop(this->UseSidePlantLoc.loopNum).FluidName,
   11077           0 :                                                             ((Tfinish + Tstart) / 2.0),
   11078           0 :                                                             state.dataPlnt->PlantLoop(this->UseSidePlantLoc.loopNum).FluidIndex,
   11079             :                                                             RoutineName);
   11080             :             } else {
   11081           0 :                 rho = FluidProperties::GetDensityGlycol(state, fluidNameWater, ((Tfinish + Tstart) / 2.0), this->waterIndex, RoutineName);
   11082           0 :                 Cp = FluidProperties::GetSpecificHeatGlycol(state, fluidNameWater, ((Tfinish + Tstart) / 2.0), this->waterIndex, RoutineName);
   11083             :             }
   11084           0 :             tmpMaxCapacity = SumFloorAreaAllZones * this->Sizing.RecoveryCapacityPerArea * (Tfinish - Tstart) * (1.0 / Constant::SecInHour) * rho *
   11085             :                              Cp; // m2 | m3/hr/m2 | delta T  in K | 1 hr/ 3600 s | kg/m3 | J/Kg/k
   11086             :         }
   11087           0 :         if (this->VolumeWasAutoSized && state.dataPlnt->PlantFirstSizesOkayToFinalize) {
   11088           0 :             this->Volume = tmpTankVolume;
   11089           0 :             if (state.dataPlnt->PlantFinalSizesOkayToReport) {
   11090           0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Tank Volume [m3]", this->Volume);
   11091             :             }
   11092           0 :             if (state.dataPlnt->PlantFirstSizesOkayToReport) {
   11093           0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Initial Tank Volume [m3]", this->Volume);
   11094             :             }
   11095             :         }
   11096           0 :         if (this->MaxCapacityWasAutoSized && state.dataPlnt->PlantFirstSizesOkayToFinalize) {
   11097           0 :             this->MaxCapacity = tmpMaxCapacity;
   11098           0 :             if (state.dataPlnt->PlantFinalSizesOkayToReport) {
   11099           0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Maximum Heater Capacity [W]", this->MaxCapacity);
   11100             :             }
   11101           0 :             if (state.dataPlnt->PlantFirstSizesOkayToReport) {
   11102           0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Initial Maximum Heater Capacity [W]", this->MaxCapacity);
   11103             :             }
   11104             :         }
   11105           0 :         break;
   11106             :     }
   11107           0 :     case SizingMode::PerUnit: {
   11108             : 
   11109           0 :         if (this->VolumeWasAutoSized) tmpTankVolume = this->Sizing.TankCapacityPerUnit * this->Sizing.NumberOfUnits;
   11110             : 
   11111           0 :         if (this->MaxCapacityWasAutoSized) {
   11112             :             Real64 rho;
   11113             :             Real64 Cp;
   11114           0 :             if (this->UseSidePlantLoc.loopNum > 0) {
   11115           0 :                 rho = FluidProperties::GetDensityGlycol(state,
   11116           0 :                                                         state.dataPlnt->PlantLoop(this->UseSidePlantLoc.loopNum).FluidName,
   11117           0 :                                                         ((Tfinish + Tstart) / 2.0),
   11118           0 :                                                         state.dataPlnt->PlantLoop(this->UseSidePlantLoc.loopNum).FluidIndex,
   11119             :                                                         RoutineName);
   11120           0 :                 Cp = FluidProperties::GetSpecificHeatGlycol(state,
   11121           0 :                                                             state.dataPlnt->PlantLoop(this->UseSidePlantLoc.loopNum).FluidName,
   11122           0 :                                                             ((Tfinish + Tstart) / 2.0),
   11123           0 :                                                             state.dataPlnt->PlantLoop(this->UseSidePlantLoc.loopNum).FluidIndex,
   11124             :                                                             RoutineName);
   11125             :             } else {
   11126           0 :                 rho = FluidProperties::GetDensityGlycol(state, fluidNameWater, ((Tfinish + Tstart) / 2.0), this->waterIndex, RoutineName);
   11127           0 :                 Cp = FluidProperties::GetSpecificHeatGlycol(state, fluidNameWater, ((Tfinish + Tstart) / 2.0), this->waterIndex, RoutineName);
   11128             :             }
   11129           0 :             tmpMaxCapacity = this->Sizing.NumberOfUnits * this->Sizing.RecoveryCapacityPerUnit * (Tfinish - Tstart) * (1.0 / Constant::SecInHour) *
   11130             :                              rho * Cp; // m3/hr/ea | delta T  in K | 1 hr/ 3600 s | kg/m3 | J/Kg/k
   11131             :         }
   11132             : 
   11133           0 :         if (this->VolumeWasAutoSized && state.dataPlnt->PlantFirstSizesOkayToFinalize) {
   11134           0 :             this->Volume = tmpTankVolume;
   11135           0 :             if (state.dataPlnt->PlantFinalSizesOkayToReport) {
   11136           0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Tank Volume [m3]", this->Volume);
   11137             :             }
   11138           0 :             if (state.dataPlnt->PlantFirstSizesOkayToReport) {
   11139           0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Initial Tank Volume [m3]", this->Volume);
   11140             :             }
   11141             :         }
   11142           0 :         if (this->MaxCapacityWasAutoSized && state.dataPlnt->PlantFirstSizesOkayToFinalize) {
   11143           0 :             this->MaxCapacity = tmpMaxCapacity;
   11144           0 :             if (state.dataPlnt->PlantFinalSizesOkayToReport) {
   11145           0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Maximum Heater Capacity [W]", this->MaxCapacity);
   11146             :             }
   11147           0 :             if (state.dataPlnt->PlantFirstSizesOkayToReport) {
   11148           0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Initial Maximum Heater Capacity [W]", this->MaxCapacity);
   11149             :             }
   11150             :         }
   11151           0 :         break;
   11152             :     }
   11153           0 :     case SizingMode::PerSolarColArea: {
   11154           0 :         break;
   11155             :     }
   11156           0 :     default:
   11157           0 :         break;
   11158             :     }
   11159             : 
   11160         766 :     if (this->MaxCapacityWasAutoSized) this->setBackupElementCapacity(state);
   11161             : 
   11162             :     // if stratified, might set height.
   11163         766 :     if ((this->VolumeWasAutoSized) && (this->WaterThermalTankType == DataPlant::PlantEquipmentType::WtrHeaterStratified) &&
   11164           0 :         state.dataPlnt->PlantFirstSizesOkayToFinalize) { // might set height
   11165           0 :         if ((this->HeightWasAutoSized) && (!this->VolumeWasAutoSized)) {
   11166           0 :             this->Height = std::pow((4.0 * this->Volume * pow_2(this->Sizing.HeightAspectRatio)) / Constant::Pi, 0.3333333333333333);
   11167           0 :             if (state.dataPlnt->PlantFinalSizesOkayToReport) {
   11168           0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Tank Height [m]", this->Height);
   11169             :             }
   11170           0 :             if (state.dataPlnt->PlantFirstSizesOkayToReport) {
   11171           0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Initial Tank Height [m]", this->Height);
   11172             :             }
   11173             :             // check if Constant::AutoCalculate() Use outlet and source inlet are still set to autosize by earlier
   11174           0 :             if (this->UseOutletHeightWasAutoSized) {
   11175           0 :                 this->UseOutletHeight = this->Height;
   11176             :             }
   11177           0 :             if (this->SourceInletHeightWasAutoSized) {
   11178           0 :                 this->SourceInletHeight = this->Height;
   11179             :             }
   11180             :         }
   11181             :     }
   11182         766 : }
   11183             : 
   11184         766 : void WaterThermalTankData::SizeTankForSupplySide(EnergyPlusData &state)
   11185             : {
   11186             : 
   11187             :     // SUBROUTINE INFORMATION:
   11188             :     //       AUTHOR         Brent Griffith
   11189             :     //       DATE WRITTEN   February 2008
   11190             :     //       MODIFIED       na
   11191             :     //       RE-ENGINEERED  na
   11192             : 
   11193             :     // PURPOSE OF THIS SUBROUTINE:
   11194             :     // This subroutine is for sizing water heater tank volume and heater
   11195             :     //   at a later point in the simulation when more of the plant is ready.
   11196             : 
   11197             :     // METHODOLOGY EMPLOYED:
   11198             :     //  depending on the sizing design mode...
   11199             : 
   11200             :     // REFERENCES:
   11201             :     // BA benchmark report for residential design mode
   11202             : 
   11203             :     static constexpr std::string_view RoutineName("SizeTankForSupplySide");
   11204             : 
   11205         766 :     Real64 tmpTankVolume = this->Volume;
   11206         766 :     Real64 tmpMaxCapacity = this->MaxCapacity;
   11207             : 
   11208         766 :     if (this->Sizing.DesignMode == SizingMode::PeakDraw) {
   11209          20 :         if (this->VolumeWasAutoSized)
   11210          20 :             tmpTankVolume = this->Sizing.TankDrawTime * this->UseDesignVolFlowRate * Constant::SecInHour; // hours | m3/s | (3600 s/1 hour)
   11211          20 :         if (this->VolumeWasAutoSized && state.dataPlnt->PlantFirstSizesOkayToFinalize) {
   11212           4 :             this->Volume = tmpTankVolume;
   11213           4 :             if (state.dataPlnt->PlantFinalSizesOkayToReport) {
   11214           4 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Tank Volume [m3]", this->Volume);
   11215             :             }
   11216           4 :             if (state.dataPlnt->PlantFirstSizesOkayToReport) {
   11217           0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Initial Tank Volume [m3]", this->Volume);
   11218             :             }
   11219             :         }
   11220          20 :         if (this->MaxCapacityWasAutoSized) {
   11221           0 :             if (this->Sizing.RecoveryTime > 0.0) {
   11222           0 :                 Real64 rho = 0.0;
   11223           0 :                 Real64 Cp = 0.0;
   11224           0 :                 constexpr Real64 Tstart = 14.44;
   11225           0 :                 constexpr Real64 Tfinish = 57.22;
   11226             : 
   11227           0 :                 if (this->SrcSidePlantLoc.loopNum > 0) {
   11228           0 :                     rho = FluidProperties::GetDensityGlycol(state,
   11229           0 :                                                             state.dataPlnt->PlantLoop(this->SrcSidePlantLoc.loopNum).FluidName,
   11230             :                                                             ((Tfinish + Tstart) / 2.0),
   11231           0 :                                                             state.dataPlnt->PlantLoop(this->SrcSidePlantLoc.loopNum).FluidIndex,
   11232             :                                                             RoutineName);
   11233           0 :                     Cp = FluidProperties::GetSpecificHeatGlycol(state,
   11234           0 :                                                                 state.dataPlnt->PlantLoop(this->SrcSidePlantLoc.loopNum).FluidName,
   11235             :                                                                 ((Tfinish + Tstart) / 2.0),
   11236           0 :                                                                 state.dataPlnt->PlantLoop(this->SrcSidePlantLoc.loopNum).FluidIndex,
   11237             :                                                                 RoutineName);
   11238             :                 } else {
   11239           0 :                     rho = FluidProperties::GetDensityGlycol(state, fluidNameWater, ((Tfinish + Tstart) / 2.0), this->waterIndex, RoutineName);
   11240           0 :                     Cp = FluidProperties::GetSpecificHeatGlycol(state, fluidNameWater, ((Tfinish + Tstart) / 2.0), this->waterIndex, RoutineName);
   11241             :                 }
   11242           0 :                 tmpMaxCapacity = (this->Volume * rho * Cp * (Tfinish - Tstart)) /
   11243           0 :                                  (this->Sizing.RecoveryTime * Constant::SecInHour); // m3 | kg/m3 | J/Kg/K | K | seconds
   11244             :             } else {
   11245           0 :                 ShowFatalError(
   11246           0 :                     state, format("{}: Tank=\"{}\", requested sizing for max capacity but entered Recovery Time is zero.", RoutineName, this->Name));
   11247             :             }
   11248             :         }
   11249             : 
   11250          20 :         if (this->MaxCapacityWasAutoSized && state.dataPlnt->PlantFirstSizesOkayToFinalize) {
   11251           0 :             this->MaxCapacity = tmpMaxCapacity;
   11252           0 :             if (state.dataPlnt->PlantFinalSizesOkayToReport) {
   11253           0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Maximum Heater Capacity [W]", this->MaxCapacity);
   11254             :             }
   11255           0 :             if (state.dataPlnt->PlantFirstSizesOkayToReport) {
   11256           0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Initial Maximum Heater Capacity [W]", this->MaxCapacity);
   11257             :             }
   11258             :         }
   11259         746 :     } else if (this->Sizing.DesignMode == SizingMode::PerSolarColArea) {
   11260             : 
   11261           0 :         this->Sizing.TotalSolarCollectorArea = 0.0;
   11262             : 
   11263           0 :         for (int CollectorNum = 1; CollectorNum <= state.dataSolarCollectors->NumOfCollectors; ++CollectorNum) {
   11264           0 :             auto const &collector = state.dataSolarCollectors->Collector(CollectorNum);
   11265           0 :             this->Sizing.TotalSolarCollectorArea += state.dataSurface->Surface(collector.Surface).Area;
   11266             :         }
   11267             : 
   11268           0 :         for (int CollectorNum = 1; CollectorNum <= state.dataPhotovoltaicThermalCollector->NumPVT; ++CollectorNum) {
   11269           0 :             auto const &collector = state.dataPhotovoltaicThermalCollector->PVT(CollectorNum);
   11270           0 :             this->Sizing.TotalSolarCollectorArea += collector.AreaCol;
   11271             :         }
   11272             : 
   11273           0 :         if (this->VolumeWasAutoSized) {
   11274           0 :             if (this->Sizing.TotalSolarCollectorArea > 0) {
   11275           0 :                 tmpTankVolume = this->Sizing.TotalSolarCollectorArea * this->Sizing.TankCapacityPerCollectorArea;
   11276             :             } else {
   11277           0 :                 ShowFatalError(state,
   11278           0 :                                format("{}: Tank=\"{}\", requested sizing for volume with PerSolarCollectorArea but total found "
   11279             :                                       "area of Collectors is zero.",
   11280             :                                       RoutineName,
   11281           0 :                                       this->Name));
   11282             :             }
   11283             :         }
   11284           0 :         if (this->MaxCapacityWasAutoSized) {
   11285           0 :             tmpMaxCapacity = 0.0;
   11286             :         }
   11287           0 :         if (this->VolumeWasAutoSized && state.dataPlnt->PlantFirstSizesOkayToFinalize) {
   11288           0 :             this->Volume = tmpTankVolume;
   11289           0 :             if (state.dataPlnt->PlantFinalSizesOkayToReport) {
   11290           0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Tank Volume [m3]", this->Volume);
   11291             :             }
   11292           0 :             if (state.dataPlnt->PlantFirstSizesOkayToReport) {
   11293           0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Initial Tank Volume [m3]", this->Volume);
   11294             :             }
   11295             :         }
   11296           0 :         if (this->MaxCapacityWasAutoSized && state.dataPlnt->PlantFirstSizesOkayToFinalize) {
   11297           0 :             this->MaxCapacity = tmpMaxCapacity;
   11298           0 :             if (state.dataPlnt->PlantFinalSizesOkayToReport) {
   11299           0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Maximum Heater Capacity [W]", this->MaxCapacity);
   11300             :             }
   11301           0 :             if (state.dataPlnt->PlantFirstSizesOkayToReport) {
   11302           0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Initial Maximum Heater Capacity [W]", this->MaxCapacity);
   11303             :             }
   11304             :         }
   11305             :     }
   11306             : 
   11307         766 :     if (this->MaxCapacityWasAutoSized) {
   11308          15 :         this->setBackupElementCapacity(state);
   11309             :     }
   11310             : 
   11311         766 :     if ((this->VolumeWasAutoSized) && (this->WaterThermalTankType == DataPlant::PlantEquipmentType::WtrHeaterStratified) &&
   11312           0 :         state.dataPlnt->PlantFirstSizesOkayToFinalize) { // might set height
   11313           0 :         if ((this->HeightWasAutoSized) && (!this->VolumeWasAutoSized)) {
   11314           0 :             this->Height = std::pow((4.0 * this->Volume * pow_2(this->Sizing.HeightAspectRatio)) / Constant::Pi, 0.3333333333333333);
   11315           0 :             if (state.dataPlnt->PlantFinalSizesOkayToReport) {
   11316           0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Tank Height [m]", this->Height);
   11317             :             }
   11318           0 :             if (state.dataPlnt->PlantFirstSizesOkayToReport) {
   11319           0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Initial Tank Height [m]", this->Height);
   11320             :             }
   11321             :         }
   11322             :     }
   11323         766 : }
   11324             : 
   11325         766 : void WaterThermalTankData::SizeDemandSidePlantConnections(EnergyPlusData &state)
   11326             : {
   11327             : 
   11328             :     // SUBROUTINE INFORMATION:
   11329             :     //       AUTHOR         Brent Griffith
   11330             :     //       DATE WRITTEN   October 2007
   11331             :     //       MODIFIED       na
   11332             :     //       RE-ENGINEERED  na
   11333             : 
   11334             :     // PURPOSE OF THIS SUBROUTINE:
   11335             :     // This subroutine is for sizing water heater plant connection flow rates
   11336             :     // on the demand side that have not been specified in the input.
   11337             : 
   11338             :     // METHODOLOGY EMPLOYED:
   11339             :     // For water heater sides on the Demand side, hot water flow rates are modeled entirely from user input data
   11340             :     // because the plant loop is not yet set up nor is plant sizing info populated.
   11341             :     // sizing is done by calculating an initial
   11342             :     //  recovery rate that if continued would reheat tank in user specified amount of time.
   11343             :     //  initial and final tank temperatures are 14.44 and reheat to 57.22 (values from CalcStandardRatings routine)
   11344             : 
   11345             :     static constexpr std::string_view RoutineName("SizeDemandSidePlantConnections");
   11346             : 
   11347         766 :     auto &PlantSizData = state.dataSize->PlantSizData;
   11348             : 
   11349         766 :     Real64 tankRecoverhours = this->SizingRecoveryTime;
   11350         766 :     bool ErrorsFound = false;
   11351         766 :     Real64 tmpUseDesignVolFlowRate = this->UseDesignVolFlowRate;
   11352         766 :     Real64 tmpSourceDesignVolFlowRate = this->SourceDesignVolFlowRate;
   11353             : 
   11354             :     Real64 Tstart;
   11355             :     Real64 Tfinish;
   11356         766 :     if (!this->IsChilledWaterTank) {
   11357         716 :         Tstart = 14.44;
   11358         716 :         Tfinish = 57.22;
   11359             :     } else {
   11360          50 :         Tstart = 14.44;
   11361          50 :         Tfinish = 9.0;
   11362             :     }
   11363             : 
   11364             :     // determine tank volume to use for sizing.
   11365         766 :     Real64 TankVolume = this->Volume;
   11366         766 :     if (this->VolumeWasAutoSized) {
   11367          20 :         TankVolume = this->Sizing.NominalVolForSizingDemandSideFlow;
   11368             :     }
   11369             : 
   11370         766 :     if (this->UseInletNode > 0) {
   11371         766 :         if (this->UseDesignVolFlowRateWasAutoSized) {
   11372         706 :             int PltSizNum = this->UseSidePlantSizNum;
   11373         706 :             if (PltSizNum > 0) { // we have a Plant Sizing Object
   11374         706 :                 if (this->UseSidePlantLoc.loopSideNum == DataPlant::LoopSideLocation::Demand) {
   11375             :                     // probably shouldn't come here as Use side is unlikley to be on demand side (?)
   11376             :                     // but going to treat component with symetry so if connections are reversed it'll still work
   11377             :                     // choose a flow rate that will allow the entire volume of the tank to go from 14.44 to 57.22 C
   11378             :                     // in user specified hours.
   11379             :                     //  using the plant inlet design temp for sizing.
   11380           0 :                     Real64 Tpdesign = PlantSizData(PltSizNum).ExitTemp;
   11381           0 :                     Real64 eff = this->UseEffectiveness;
   11382           0 :                     if ((Tpdesign >= 58.0) && (!this->IsChilledWaterTank)) {
   11383           0 :                         if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
   11384           0 :                             this->UseDesignVolFlowRate = -1.0 * (TankVolume / (tankRecoverhours * Constant::SecInHour * eff)) *
   11385           0 :                                                          std::log((Tpdesign - Tfinish) / (Tpdesign - Tstart));
   11386             :                         } else {
   11387           0 :                             tmpUseDesignVolFlowRate = -1.0 * (TankVolume / (tankRecoverhours * Constant::SecInHour * eff)) *
   11388           0 :                                                       std::log((Tpdesign - Tfinish) / (Tpdesign - Tstart));
   11389             :                         }
   11390           0 :                     } else if ((Tpdesign <= 8.0) && (this->IsChilledWaterTank)) {
   11391           0 :                         if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
   11392           0 :                             this->UseDesignVolFlowRate = -1.0 * (TankVolume / (tankRecoverhours * Constant::SecInHour * eff)) *
   11393           0 :                                                          std::log((Tpdesign - Tfinish) / (Tpdesign - Tstart));
   11394             :                         } else {
   11395           0 :                             tmpUseDesignVolFlowRate = -1.0 * (TankVolume / (tankRecoverhours * Constant::SecInHour * eff)) *
   11396           0 :                                                       std::log((Tpdesign - Tfinish) / (Tpdesign - Tstart));
   11397             :                         }
   11398             :                     } else {
   11399           0 :                         if (!this->IsChilledWaterTank) {
   11400             :                             // plant sizing object design temperature is set too low throw warning.
   11401           0 :                             ShowSevereError(state,
   11402             :                                             "Autosizing of Use side water heater design flow rate requires Sizing:Plant object to have an exit "
   11403             :                                             "temperature >= 58C");
   11404           0 :                             ShowContinueError(state, format("Occurs for water heater object={}", this->Name));
   11405             :                         } else {
   11406             :                             // plant sizing object design temperature is set too hi throw warning.
   11407           0 :                             ShowSevereError(state,
   11408             :                                             "Autosizing of Use side chilled water tank design flow rate requires Sizing:Plant object to have an "
   11409             :                                             "exit temperature <= 8C");
   11410           0 :                             ShowContinueError(state, format("Occurs for chilled water storage tank object={}", this->Name));
   11411             :                         }
   11412           0 :                         ErrorsFound = true;
   11413             :                     }
   11414           0 :                     if (state.dataPlnt->PlantFinalSizesOkayToReport) {
   11415           0 :                         BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Use Side Design Flow Rate [m3/s]", this->UseDesignVolFlowRate);
   11416             :                     }
   11417           0 :                     if (state.dataPlnt->PlantFirstSizesOkayToReport) {
   11418           0 :                         BaseSizer::reportSizerOutput(
   11419             :                             state, this->Type, this->Name, "Initial Use Side Design Flow Rate [m3/s]", this->UseDesignVolFlowRate);
   11420             :                     }
   11421           0 :                     if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
   11422           0 :                         PlantUtilities::RegisterPlantCompDesignFlow(state, this->UseInletNode, this->UseDesignVolFlowRate);
   11423             :                     } else {
   11424           0 :                         PlantUtilities::RegisterPlantCompDesignFlow(state, this->UseInletNode, tmpUseDesignVolFlowRate);
   11425             :                     }
   11426           0 :                     Real64 rho = FluidProperties::GetDensityGlycol(state,
   11427           0 :                                                                    state.dataPlnt->PlantLoop(this->UseSidePlantLoc.loopNum).FluidName,
   11428             :                                                                    Constant::InitConvTemp,
   11429           0 :                                                                    state.dataPlnt->PlantLoop(this->UseSidePlantLoc.loopNum).FluidIndex,
   11430             :                                                                    RoutineName);
   11431           0 :                     if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
   11432           0 :                         this->PlantUseMassFlowRateMax = this->UseDesignVolFlowRate * rho;
   11433             :                     } else {
   11434           0 :                         this->PlantUseMassFlowRateMax = tmpUseDesignVolFlowRate * rho;
   11435             :                     }
   11436             :                 } // Demand side
   11437             :             } else {
   11438             :                 // do nothing
   11439             :             } // plant sizing object
   11440             : 
   11441             :         } else {
   11442             :             // not autosized - report flow to RegisterPlantCompDesignFlow for supply side component sizing
   11443          60 :             PlantUtilities::RegisterPlantCompDesignFlow(state, this->UseInletNode, this->UseDesignVolFlowRate);
   11444             :             Real64 rho;
   11445          60 :             if (this->UseSidePlantLoc.loopNum > 0) {
   11446          60 :                 rho = FluidProperties::GetDensityGlycol(state,
   11447          60 :                                                         state.dataPlnt->PlantLoop(this->UseSidePlantLoc.loopNum).FluidName,
   11448             :                                                         Constant::InitConvTemp,
   11449          60 :                                                         state.dataPlnt->PlantLoop(this->UseSidePlantLoc.loopNum).FluidIndex,
   11450             :                                                         RoutineName);
   11451             :             } else {
   11452           0 :                 rho = FluidProperties::GetDensityGlycol(state, fluidNameWater, Constant::InitConvTemp, this->waterIndex, RoutineName);
   11453             :             }
   11454          60 :             this->PlantUseMassFlowRateMax = this->UseDesignVolFlowRate * rho;
   11455             :         } // autosizing needed.
   11456             :     }     // connected to plant
   11457             : 
   11458         766 :     if (this->SourceInletNode > 0) {
   11459         260 :         if (this->SourceDesignVolFlowRateWasAutoSized) {
   11460         125 :             int PltSizNum = this->SourceSidePlantSizNum;
   11461         125 :             if (PltSizNum > 0) {
   11462         110 :                 if (this->SrcSidePlantLoc.loopSideNum == DataPlant::LoopSideLocation::Demand) {
   11463             :                     //  choose a flow rate that will allow the entire volume of the tank to go from 14.44 to 57.22 C
   11464             :                     // in user specified hours.
   11465             :                     //  using the plant inlet design temp for sizing.
   11466          60 :                     Real64 Tpdesign = PlantSizData(PltSizNum).ExitTemp;
   11467          60 :                     Real64 eff = this->SourceEffectiveness;
   11468          60 :                     if ((Tpdesign >= 58.0) && (!this->IsChilledWaterTank)) {
   11469             : 
   11470          30 :                         if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
   11471           6 :                             this->SourceDesignVolFlowRate = -1.0 * (TankVolume / (tankRecoverhours * Constant::SecInHour * eff)) *
   11472           6 :                                                             std::log((Tpdesign - Tfinish) / (Tpdesign - Tstart));
   11473             :                         } else {
   11474          24 :                             tmpSourceDesignVolFlowRate = -1.0 * (TankVolume / (tankRecoverhours * Constant::SecInHour * eff)) *
   11475          24 :                                                          std::log((Tpdesign - Tfinish) / (Tpdesign - Tstart));
   11476             :                         }
   11477          30 :                     } else if ((Tpdesign <= 8.0) && (this->IsChilledWaterTank)) {
   11478          30 :                         if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
   11479           6 :                             this->SourceDesignVolFlowRate = -1.0 * (TankVolume / (tankRecoverhours * Constant::SecInHour * eff)) *
   11480           6 :                                                             std::log((Tpdesign - Tfinish) / (Tpdesign - Tstart));
   11481             :                         } else {
   11482          24 :                             tmpSourceDesignVolFlowRate = -1.0 * (TankVolume / (tankRecoverhours * Constant::SecInHour * eff)) *
   11483          24 :                                                          std::log((Tpdesign - Tfinish) / (Tpdesign - Tstart));
   11484             :                         }
   11485             :                     } else {
   11486           0 :                         if (!this->IsChilledWaterTank) {
   11487             :                             // plant sizing object design temperature is set too low throw warning.
   11488           0 :                             ShowSevereError(state,
   11489             :                                             "Autosizing of Source side water heater design flow rate requires Sizing:Plant object to have an "
   11490             :                                             "exit temperature >= 58C");
   11491           0 :                             ShowContinueError(state, format("Occurs for WaterHeater:Mixed object={}", this->Name));
   11492             :                         } else {
   11493             :                             // plant sizing object design temperature is set too hi throw warning.
   11494           0 :                             ShowSevereError(state,
   11495             :                                             "Autosizing of Source side chilled water tank design flow rate requires Sizing:Plant object to have "
   11496             :                                             "an exit temperature <= 8C");
   11497           0 :                             ShowContinueError(state, format("Occurs for chilled water storage tank object={}", this->Name));
   11498             :                         }
   11499           0 :                         ErrorsFound = true;
   11500             :                     }
   11501          60 :                     if (state.dataPlnt->PlantFinalSizesOkayToReport) {
   11502          12 :                         BaseSizer::reportSizerOutput(
   11503             :                             state, this->Type, this->Name, "Source Side Design Flow Rate [m3/s]", this->SourceDesignVolFlowRate);
   11504             :                     }
   11505          60 :                     if (state.dataPlnt->PlantFirstSizesOkayToReport) {
   11506           0 :                         BaseSizer::reportSizerOutput(
   11507             :                             state, this->Type, this->Name, "Initial Source Side Design Flow Rate [m3/s]", this->SourceDesignVolFlowRate);
   11508             :                     }
   11509          60 :                     if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
   11510          12 :                         PlantUtilities::RegisterPlantCompDesignFlow(state, this->SourceInletNode, this->SourceDesignVolFlowRate);
   11511             :                     } else {
   11512          48 :                         PlantUtilities::RegisterPlantCompDesignFlow(state, this->SourceInletNode, tmpSourceDesignVolFlowRate);
   11513             :                     }
   11514          60 :                     Real64 rho = FluidProperties::GetDensityGlycol(state,
   11515          60 :                                                                    state.dataPlnt->PlantLoop(this->SrcSidePlantLoc.loopNum).FluidName,
   11516             :                                                                    Constant::InitConvTemp,
   11517          60 :                                                                    state.dataPlnt->PlantLoop(this->SrcSidePlantLoc.loopNum).FluidIndex,
   11518             :                                                                    RoutineName);
   11519          60 :                     if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
   11520          12 :                         this->PlantSourceMassFlowRateMax = this->SourceDesignVolFlowRate * rho;
   11521             :                     } else {
   11522          48 :                         this->PlantSourceMassFlowRateMax = tmpSourceDesignVolFlowRate * rho;
   11523             :                     }
   11524             :                 } // demand side
   11525             :             } else {
   11526             :                 // do nothing
   11527             :             } // plant sizing object
   11528             : 
   11529             :         } else {
   11530             :             // not autosized - report flow to RegisterPlantCompDesignFlow for supply side component sizing
   11531         135 :             PlantUtilities::RegisterPlantCompDesignFlow(state, this->SourceInletNode, this->SourceDesignVolFlowRate);
   11532             :             Real64 rho;
   11533         135 :             if (this->SrcSidePlantLoc.loopNum > 0) {
   11534         100 :                 rho = FluidProperties::GetDensityGlycol(state,
   11535         100 :                                                         state.dataPlnt->PlantLoop(this->SrcSidePlantLoc.loopNum).FluidName,
   11536             :                                                         Constant::InitConvTemp,
   11537         100 :                                                         state.dataPlnt->PlantLoop(this->SrcSidePlantLoc.loopNum).FluidIndex,
   11538             :                                                         RoutineName);
   11539             :             } else {
   11540          35 :                 rho = FluidProperties::GetDensityGlycol(state, fluidNameWater, Constant::InitConvTemp, this->waterIndex, RoutineName);
   11541             :             }
   11542         135 :             this->PlantSourceMassFlowRateMax = this->SourceDesignVolFlowRate * rho;
   11543             :         } // autosizing needed.
   11544             :     }     // connected to plant
   11545             : 
   11546         766 :     if (ErrorsFound) {
   11547           0 :         ShowFatalError(state, "Preceding sizing errors cause program termination");
   11548             :     }
   11549         766 : }
   11550             : 
   11551          49 : void WaterThermalTankData::SizeStandAloneWaterHeater(EnergyPlusData &state)
   11552             : {
   11553             : 
   11554             :     // SUBROUTINE INFORMATION:
   11555             :     //       AUTHOR         B. Griffith
   11556             :     //       DATE WRITTEN   October 2013
   11557             :     //       MODIFIED       na
   11558             :     //       RE-ENGINEERED  na
   11559             : 
   11560             :     // PURPOSE OF THIS SUBROUTINE:
   11561             :     // allow autosizing of tank volume and heat capacity for stand alone tanks
   11562             : 
   11563             :     // METHODOLOGY EMPLOYED:
   11564             :     // same as for plant connected water heaters, only draws are scheduled.
   11565             : 
   11566             :     // SUBROUTINE PARAMETER DEFINITIONS:
   11567          49 :     Real64 constexpr GalTocubicMeters(0.0037854);
   11568          49 :     Real64 constexpr kBtuPerHrToWatts(293.1);
   11569             :     static constexpr std::string_view RoutineName("SizeStandAloneWaterHeater");
   11570             : 
   11571          49 :     Real64 Tstart = 14.44;
   11572          49 :     Real64 Tfinish = 57.22;
   11573          49 :     Real64 tmpTankVolume = this->Volume;
   11574          49 :     Real64 tmpMaxCapacity = this->MaxCapacity;
   11575             : 
   11576          49 :     if (this->VolumeWasAutoSized || this->MaxCapacityWasAutoSized) {
   11577             : 
   11578           0 :         switch (this->Sizing.DesignMode) {
   11579             : 
   11580           0 :         case SizingMode::PeakDraw: {
   11581             :             // get draw rate from maximum in schedule
   11582           0 :             Real64 rho = FluidProperties::GetDensityGlycol(state, fluidNameWater, Constant::InitConvTemp, this->waterIndex, RoutineName);
   11583           0 :             Real64 DrawDesignVolFlowRate = ScheduleManager::GetScheduleMaxValue(state, this->FlowRateSchedule) * this->MassFlowRateMax / rho;
   11584             : 
   11585           0 :             if (this->VolumeWasAutoSized) {
   11586           0 :                 tmpTankVolume = this->Sizing.TankDrawTime * DrawDesignVolFlowRate * Constant::SecInHour; // hours | m3/s | (3600 s/1 hour)
   11587           0 :                 this->Volume = tmpTankVolume;
   11588           0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Tank Volume [m3]", this->Volume);
   11589             :             }
   11590           0 :             if (this->MaxCapacityWasAutoSized) {
   11591           0 :                 if (this->Sizing.RecoveryTime > 0.0) {
   11592           0 :                     rho = FluidProperties::GetDensityGlycol(state, fluidNameWater, ((Tfinish + Tstart) / 2.0), this->waterIndex, RoutineName);
   11593             :                     Real64 Cp =
   11594           0 :                         FluidProperties::GetSpecificHeatGlycol(state, fluidNameWater, ((Tfinish + Tstart) / 2.0), this->waterIndex, RoutineName);
   11595             : 
   11596           0 :                     tmpMaxCapacity = (this->Volume * rho * Cp * (Tfinish - Tstart)) /
   11597           0 :                                      (this->Sizing.RecoveryTime * Constant::SecInHour); // m3 | kg/m3 | J/Kg/K | K | seconds
   11598             :                 } else {
   11599           0 :                     ShowFatalError(
   11600             :                         state,
   11601           0 :                         format("{}: Tank=\"{}\", requested sizing for max capacity but entered Recovery Time is zero.", RoutineName, this->Name));
   11602             :                 }
   11603           0 :                 this->MaxCapacity = tmpMaxCapacity;
   11604           0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Maximum Heater Capacity [W]", this->MaxCapacity);
   11605             :             }
   11606             : 
   11607           0 :             break;
   11608             :         }
   11609           0 :         case SizingMode::ResidentialMin: {
   11610             :             // assume can propagate rules for gas to other fuels.
   11611           0 :             bool FuelTypeIsLikeGas = false;
   11612           0 :             switch (this->FuelType) {
   11613           0 :             case Constant::eFuel::NaturalGas:
   11614             :             case Constant::eFuel::Diesel:
   11615             :             case Constant::eFuel::Gasoline:
   11616             :             case Constant::eFuel::Coal:
   11617             :             case Constant::eFuel::FuelOilNo1:
   11618             :             case Constant::eFuel::FuelOilNo2:
   11619             :             case Constant::eFuel::Propane:
   11620             :             case Constant::eFuel::OtherFuel1:
   11621             :             case Constant::eFuel::OtherFuel2:
   11622             :             case Constant::eFuel::DistrictHeatingWater:
   11623             :             case Constant::eFuel::DistrictHeatingSteam:
   11624           0 :                 FuelTypeIsLikeGas = true;
   11625           0 :                 break;
   11626           0 :             default: // FuelTypeIsLikeGas stays false
   11627           0 :                 break;
   11628             :             }
   11629             : 
   11630           0 :             if (this->Sizing.NumberOfBedrooms == 1) {
   11631           0 :                 if (this->FuelType == Constant::eFuel::Electricity) {
   11632           0 :                     if (this->VolumeWasAutoSized) tmpTankVolume = 20.0 * GalTocubicMeters;
   11633           0 :                     if (this->MaxCapacityWasAutoSized) tmpMaxCapacity = 2.5 * 1000.0; // 2.5 kW
   11634           0 :                 } else if (FuelTypeIsLikeGas) {
   11635           0 :                     if (this->VolumeWasAutoSized) tmpTankVolume = 20.0 * GalTocubicMeters;
   11636           0 :                     if (this->MaxCapacityWasAutoSized) tmpMaxCapacity = 27.0 * kBtuPerHrToWatts; // 27kBtu/hr
   11637             :                 }
   11638             : 
   11639           0 :             } else if (this->Sizing.NumberOfBedrooms == 2) {
   11640           0 :                 if (this->Sizing.NumberOfBathrooms <= 1.5) {
   11641           0 :                     if (this->FuelType == Constant::eFuel::Electricity) {
   11642           0 :                         if (this->VolumeWasAutoSized) tmpTankVolume = 30.0 * GalTocubicMeters;
   11643           0 :                         if (this->MaxCapacityWasAutoSized) tmpMaxCapacity = 3.5 * 1000.0; // 3.5 kW
   11644           0 :                     } else if (FuelTypeIsLikeGas) {
   11645           0 :                         if (this->VolumeWasAutoSized) tmpTankVolume = 30.0 * GalTocubicMeters;
   11646           0 :                         if (this->MaxCapacityWasAutoSized) tmpMaxCapacity = 36.0 * kBtuPerHrToWatts; // 36 kBtu/hr
   11647             :                     }
   11648           0 :                 } else if ((this->Sizing.NumberOfBathrooms > 1.5) && (this->Sizing.NumberOfBathrooms < 3.0)) {
   11649           0 :                     if (this->FuelType == Constant::eFuel::Electricity) {
   11650           0 :                         if (this->VolumeWasAutoSized) tmpTankVolume = 40.0 * GalTocubicMeters;
   11651           0 :                         if (this->MaxCapacityWasAutoSized) tmpMaxCapacity = 4.5 * 1000.0; // 4.5 kW
   11652           0 :                     } else if (FuelTypeIsLikeGas) {
   11653           0 :                         if (this->VolumeWasAutoSized) tmpTankVolume = 30.0 * GalTocubicMeters;
   11654           0 :                         if (this->MaxCapacityWasAutoSized) tmpMaxCapacity = 36.0 * kBtuPerHrToWatts; // 36 kBtu/hr
   11655             :                     }
   11656           0 :                 } else if (this->Sizing.NumberOfBathrooms >= 3.0) {
   11657           0 :                     if (this->FuelType == Constant::eFuel::Electricity) {
   11658           0 :                         if (this->VolumeWasAutoSized) tmpTankVolume = 50.0 * GalTocubicMeters;
   11659           0 :                         if (this->MaxCapacityWasAutoSized) tmpMaxCapacity = 5.5 * 1000.0; // 5.5 kW
   11660           0 :                     } else if (FuelTypeIsLikeGas) {
   11661           0 :                         if (this->VolumeWasAutoSized) tmpTankVolume = 40.0 * GalTocubicMeters;
   11662           0 :                         if (this->MaxCapacityWasAutoSized) tmpMaxCapacity = 36.0 * kBtuPerHrToWatts; // 36 kBtu/hr
   11663             :                     }
   11664             :                 }
   11665           0 :             } else if (this->Sizing.NumberOfBedrooms == 3) {
   11666           0 :                 if (this->Sizing.NumberOfBathrooms <= 1.5) {
   11667           0 :                     if (this->FuelType == Constant::eFuel::Electricity) {
   11668           0 :                         if (this->VolumeWasAutoSized) tmpTankVolume = 40.0 * GalTocubicMeters;
   11669           0 :                         if (this->MaxCapacityWasAutoSized) tmpMaxCapacity = 4.5 * 1000.0; // 4.5 kW
   11670           0 :                     } else if (FuelTypeIsLikeGas) {
   11671           0 :                         if (this->VolumeWasAutoSized) tmpTankVolume = 30.0 * GalTocubicMeters;
   11672           0 :                         if (this->MaxCapacityWasAutoSized) tmpMaxCapacity = 36.0 * kBtuPerHrToWatts; // 36 kBtu/hr
   11673             :                     }
   11674           0 :                 } else if ((this->Sizing.NumberOfBathrooms > 1.5) && (this->Sizing.NumberOfBathrooms < 3.0)) {
   11675           0 :                     if (this->FuelType == Constant::eFuel::Electricity) {
   11676           0 :                         if (this->VolumeWasAutoSized) tmpTankVolume = 50.0 * GalTocubicMeters;
   11677           0 :                         if (this->MaxCapacityWasAutoSized) tmpMaxCapacity = 5.5 * 1000.0; // 5.5 kW
   11678           0 :                     } else if (FuelTypeIsLikeGas) {
   11679           0 :                         if (this->VolumeWasAutoSized) tmpTankVolume = 40.0 * GalTocubicMeters;
   11680           0 :                         if (this->MaxCapacityWasAutoSized) tmpMaxCapacity = 36.0 * kBtuPerHrToWatts; // 36 kBtu/hr
   11681             :                     }
   11682           0 :                 } else if (this->Sizing.NumberOfBathrooms >= 3.0) {
   11683           0 :                     if (this->FuelType == Constant::eFuel::Electricity) {
   11684           0 :                         if (this->VolumeWasAutoSized) tmpTankVolume = 50.0 * GalTocubicMeters;
   11685           0 :                         if (this->MaxCapacityWasAutoSized) tmpMaxCapacity = 5.5 * 1000.0; // 5.5 kW
   11686           0 :                     } else if (FuelTypeIsLikeGas) {
   11687           0 :                         if (this->VolumeWasAutoSized) tmpTankVolume = 40.0 * GalTocubicMeters;
   11688           0 :                         if (this->MaxCapacityWasAutoSized) tmpMaxCapacity = 38.0 * kBtuPerHrToWatts; // 38 kBtu/hr
   11689             :                     }
   11690             :                 }
   11691           0 :             } else if (this->Sizing.NumberOfBedrooms == 4) {
   11692           0 :                 if (this->Sizing.NumberOfBathrooms <= 1.5) {
   11693           0 :                     if (this->FuelType == Constant::eFuel::Electricity) {
   11694           0 :                         if (this->VolumeWasAutoSized) tmpTankVolume = 50.0 * GalTocubicMeters;
   11695           0 :                         if (this->MaxCapacityWasAutoSized) tmpMaxCapacity = 5.5 * 1000.0; // 5.5 kW
   11696           0 :                     } else if (FuelTypeIsLikeGas) {
   11697           0 :                         if (this->VolumeWasAutoSized) tmpTankVolume = 40.0 * GalTocubicMeters;
   11698           0 :                         if (this->MaxCapacityWasAutoSized) tmpMaxCapacity = 36.0 * kBtuPerHrToWatts; // 36 kBtu/hr
   11699             :                     }
   11700           0 :                 } else if ((this->Sizing.NumberOfBathrooms > 1.5) && (this->Sizing.NumberOfBathrooms < 3.0)) {
   11701           0 :                     if (this->FuelType == Constant::eFuel::Electricity) {
   11702           0 :                         if (this->VolumeWasAutoSized) tmpTankVolume = 50.0 * GalTocubicMeters;
   11703           0 :                         if (this->MaxCapacityWasAutoSized) tmpMaxCapacity = 5.5 * 1000.0; // 5.5 kW
   11704           0 :                     } else if (FuelTypeIsLikeGas) {
   11705           0 :                         if (this->VolumeWasAutoSized) tmpTankVolume = 40.0 * GalTocubicMeters;
   11706           0 :                         if (this->MaxCapacityWasAutoSized) tmpMaxCapacity = 38.0 * kBtuPerHrToWatts; // 38 kBtu/hr
   11707             :                     }
   11708           0 :                 } else if (this->Sizing.NumberOfBathrooms >= 3.0) {
   11709           0 :                     if (this->FuelType == Constant::eFuel::Electricity) {
   11710           0 :                         if (this->VolumeWasAutoSized) tmpTankVolume = 66.0 * GalTocubicMeters;
   11711           0 :                         if (this->MaxCapacityWasAutoSized) tmpMaxCapacity = 5.5 * 1000.0; // 5.5 kW
   11712           0 :                     } else if (FuelTypeIsLikeGas) {
   11713           0 :                         if (this->VolumeWasAutoSized) tmpTankVolume = 50.0 * GalTocubicMeters;
   11714           0 :                         if (this->MaxCapacityWasAutoSized) tmpMaxCapacity = 38.0 * kBtuPerHrToWatts; // 38 kBtu/hr
   11715             :                     }
   11716             :                 }
   11717           0 :             } else if (this->Sizing.NumberOfBedrooms == 5) {
   11718           0 :                 if (this->FuelType == Constant::eFuel::Electricity) {
   11719           0 :                     if (this->VolumeWasAutoSized) tmpTankVolume = 66.0 * GalTocubicMeters;
   11720           0 :                     if (this->MaxCapacityWasAutoSized) tmpMaxCapacity = 5.5 * 1000.0; // 5.5 kW
   11721           0 :                 } else if (FuelTypeIsLikeGas) {
   11722           0 :                     if (this->VolumeWasAutoSized) tmpTankVolume = 50.0 * GalTocubicMeters;
   11723           0 :                     if (this->MaxCapacityWasAutoSized) tmpMaxCapacity = 47.0 * kBtuPerHrToWatts; // 47 kBtu/hr
   11724             :                 }
   11725           0 :             } else if (this->Sizing.NumberOfBedrooms >= 6) {
   11726           0 :                 if (this->FuelType == Constant::eFuel::Electricity) {
   11727           0 :                     if (this->VolumeWasAutoSized) tmpTankVolume = 66.0 * GalTocubicMeters;
   11728           0 :                     if (this->MaxCapacityWasAutoSized) tmpMaxCapacity = 5.5 * 1000.0; // 5.5 kW
   11729           0 :                 } else if (FuelTypeIsLikeGas) {
   11730           0 :                     if (this->VolumeWasAutoSized) tmpTankVolume = 50.0 * GalTocubicMeters;
   11731           0 :                     if (this->MaxCapacityWasAutoSized) tmpMaxCapacity = 50.0 * kBtuPerHrToWatts; // 50 kBtu/hr
   11732             :                 }
   11733             :             }
   11734           0 :             if (this->VolumeWasAutoSized) {
   11735           0 :                 this->Volume = tmpTankVolume;
   11736           0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Tank Volume [m3]", this->Volume);
   11737             :             }
   11738           0 :             if (this->MaxCapacityWasAutoSized) {
   11739           0 :                 this->MaxCapacity = tmpMaxCapacity;
   11740           0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Maximum Heater Capacity [W]", this->MaxCapacity);
   11741             :             }
   11742             : 
   11743           0 :             break;
   11744             :         }
   11745           0 :         case SizingMode::PerPerson: {
   11746             :             // how to get number of people?
   11747             : 
   11748             :             // MJW TODO: this won't compile now: Real64 SumPeopleAllZones = sum(state.dataHeatBal->Zone, &DataHeatBalance::ZoneData::TotOccupants);
   11749           0 :             Real64 SumPeopleAllZones = 0.0;
   11750           0 :             for (auto &thisZone : state.dataHeatBal->Zone) {
   11751           0 :                 SumPeopleAllZones += thisZone.TotOccupants;
   11752           0 :             }
   11753           0 :             if (this->VolumeWasAutoSized) {
   11754           0 :                 tmpTankVolume = this->Sizing.TankCapacityPerPerson * SumPeopleAllZones;
   11755             :             }
   11756           0 :             if (this->MaxCapacityWasAutoSized) {
   11757           0 :                 Real64 rho = FluidProperties::GetDensityGlycol(state, fluidNameWater, ((Tfinish + Tstart) / 2.0), this->waterIndex, RoutineName);
   11758           0 :                 Real64 Cp = FluidProperties::GetSpecificHeatGlycol(state, fluidNameWater, ((Tfinish + Tstart) / 2.0), this->waterIndex, RoutineName);
   11759           0 :                 tmpMaxCapacity = SumPeopleAllZones * this->Sizing.RecoveryCapacityPerPerson * (Tfinish - Tstart) * (1.0 / Constant::SecInHour) * rho *
   11760             :                                  Cp; // m3/hr/person | delta T  in K | 1 hr/ 3600 s | kg/m3 | J/Kg/k
   11761             :             }
   11762             : 
   11763           0 :             if (this->VolumeWasAutoSized) {
   11764           0 :                 this->Volume = tmpTankVolume;
   11765           0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Tank Volume [m3]", this->Volume);
   11766             :             }
   11767           0 :             if (this->MaxCapacityWasAutoSized) {
   11768           0 :                 this->MaxCapacity = tmpMaxCapacity;
   11769           0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Maximum Heater Capacity [W]", this->MaxCapacity);
   11770             :             }
   11771             : 
   11772           0 :             break;
   11773             :         }
   11774           0 :         case SizingMode::PerFloorArea: {
   11775             : 
   11776             :             // MJW TODO: this won't compile now: Real64 SumFloorAreaAllZones = sum(state.dataHeatBal->Zone, &DataHeatBalance::ZoneData::FloorArea);
   11777           0 :             Real64 SumFloorAreaAllZones = 0.0;
   11778           0 :             for (auto &thisZone : state.dataHeatBal->Zone) {
   11779           0 :                 SumFloorAreaAllZones += thisZone.FloorArea;
   11780           0 :             }
   11781           0 :             if (this->VolumeWasAutoSized) {
   11782           0 :                 tmpTankVolume = this->Sizing.TankCapacityPerArea * SumFloorAreaAllZones;
   11783             :             }
   11784             : 
   11785           0 :             if (this->MaxCapacityWasAutoSized) {
   11786           0 :                 Real64 rho = FluidProperties::GetDensityGlycol(state, fluidNameWater, ((Tfinish + Tstart) / 2.0), this->waterIndex, RoutineName);
   11787           0 :                 Real64 Cp = FluidProperties::GetSpecificHeatGlycol(state, fluidNameWater, ((Tfinish + Tstart) / 2.0), this->waterIndex, RoutineName);
   11788           0 :                 tmpMaxCapacity = SumFloorAreaAllZones * this->Sizing.RecoveryCapacityPerArea * (Tfinish - Tstart) * (1.0 / Constant::SecInHour) *
   11789             :                                  rho * Cp; // m2 | m3/hr/m2 | delta T  in K | 1 hr/ 3600 s | kg/m3 | J/Kg/k
   11790             :             }
   11791           0 :             if (this->VolumeWasAutoSized) {
   11792           0 :                 this->Volume = tmpTankVolume;
   11793           0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Tank Volume [m3]", this->Volume);
   11794             :             }
   11795           0 :             if (this->MaxCapacityWasAutoSized) {
   11796           0 :                 this->MaxCapacity = tmpMaxCapacity;
   11797           0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Maximum Heater Capacity [W]", this->MaxCapacity);
   11798             :             }
   11799           0 :             break;
   11800             :         }
   11801           0 :         case SizingMode::PerUnit: {
   11802             : 
   11803           0 :             if (this->VolumeWasAutoSized) tmpTankVolume = this->Sizing.TankCapacityPerUnit * this->Sizing.NumberOfUnits;
   11804             : 
   11805           0 :             if (this->MaxCapacityWasAutoSized) {
   11806           0 :                 Real64 rho = FluidProperties::GetDensityGlycol(state, fluidNameWater, ((Tfinish + Tstart) / 2.0), this->waterIndex, RoutineName);
   11807           0 :                 Real64 Cp = FluidProperties::GetSpecificHeatGlycol(state, fluidNameWater, ((Tfinish + Tstart) / 2.0), this->waterIndex, RoutineName);
   11808           0 :                 tmpMaxCapacity = this->Sizing.NumberOfUnits * this->Sizing.RecoveryCapacityPerUnit * (Tfinish - Tstart) *
   11809           0 :                                  (1.0 / Constant::SecInHour) * rho * Cp; // m3/hr/ea | delta T  in K | 1 hr/ 3600 s | kg/m3 | J/Kg/k
   11810             :             }
   11811             : 
   11812           0 :             if (this->VolumeWasAutoSized) {
   11813           0 :                 this->Volume = tmpTankVolume;
   11814           0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Tank Volume [m3]", this->Volume);
   11815             :             }
   11816           0 :             if (this->MaxCapacityWasAutoSized) {
   11817           0 :                 this->MaxCapacity = tmpMaxCapacity;
   11818           0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Maximum Heater Capacity [W]", this->MaxCapacity);
   11819             :             }
   11820           0 :             break;
   11821             :         }
   11822           0 :         case SizingMode::PerSolarColArea: {
   11823             : 
   11824           0 :             this->Sizing.TotalSolarCollectorArea = 0.0;
   11825             : 
   11826           0 :             for (int CollectorNum = 1; CollectorNum <= state.dataSolarCollectors->NumOfCollectors; ++CollectorNum) {
   11827           0 :                 auto const &collector = state.dataSolarCollectors->Collector(CollectorNum);
   11828           0 :                 this->Sizing.TotalSolarCollectorArea += state.dataSurface->Surface(collector.Surface).Area;
   11829             :             }
   11830             : 
   11831           0 :             for (int CollectorNum = 1; CollectorNum <= state.dataPhotovoltaicThermalCollector->NumPVT; ++CollectorNum) {
   11832           0 :                 auto const &collector = state.dataPhotovoltaicThermalCollector->PVT(CollectorNum);
   11833           0 :                 this->Sizing.TotalSolarCollectorArea += collector.AreaCol;
   11834             :             }
   11835             : 
   11836           0 :             if (this->VolumeWasAutoSized) {
   11837           0 :                 if (this->Sizing.TotalSolarCollectorArea > 0) {
   11838           0 :                     tmpTankVolume = this->Sizing.TotalSolarCollectorArea * this->Sizing.TankCapacityPerCollectorArea;
   11839             :                 } else {
   11840           0 :                     ShowFatalError(state,
   11841           0 :                                    format("{}: Tank=\"{}\", requested sizing for volume with PerSolarCollectorArea but total found "
   11842             :                                           "area of Collectors is zero.",
   11843             :                                           RoutineName,
   11844           0 :                                           this->Name));
   11845             :                 }
   11846             :             }
   11847           0 :             if (this->MaxCapacityWasAutoSized) {
   11848           0 :                 tmpMaxCapacity = 0.0;
   11849             :             }
   11850             : 
   11851           0 :             if (this->VolumeWasAutoSized) {
   11852           0 :                 this->Volume = tmpTankVolume;
   11853           0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Tank Volume [m3]", this->Volume);
   11854             :             }
   11855           0 :             if (this->MaxCapacityWasAutoSized) {
   11856           0 :                 this->MaxCapacity = tmpMaxCapacity;
   11857           0 :                 BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Maximum Heater Capacity [W]", this->MaxCapacity);
   11858             :             }
   11859           0 :             break;
   11860             :         }
   11861           0 :         default:
   11862           0 :             if (this->MaxCapacityWasAutoSized) {
   11863           0 :                 this->setBackupElementCapacity(state);
   11864             :             }
   11865           0 :             break;
   11866             :         }
   11867             :     }
   11868          49 : }
   11869             : 
   11870     6283865 : void WaterThermalTankData::UpdateWaterThermalTank(EnergyPlusData &state)
   11871             : {
   11872             : 
   11873             :     // SUBROUTINE INFORMATION:
   11874             :     //       AUTHOR         Brandon Anderson
   11875             :     //       DATE WRITTEN   May 2000
   11876             :     //       MODIFIED       na
   11877             :     //                      Nov 2011, BAN; removed the use and source heat rate re-calculation for stratified tank
   11878             :     //                                     for energy conservation verification.
   11879             :     //       RE-ENGINEERED  Feb 2004, PGE
   11880             : 
   11881             :     // PURPOSE OF THIS SUBROUTINE:
   11882             :     // Updates the node variables with local variables.
   11883             : 
   11884     6283865 :     if (this->UseInletNode > 0 && this->UseOutletNode > 0) {
   11885     5863219 :         state.dataLoopNodes->Node(UseOutletNode) = state.dataLoopNodes->Node(this->UseInletNode); // this could wipe out setpoints on outlet node
   11886             : 
   11887     5863219 :         state.dataLoopNodes->Node(this->UseOutletNode).Temp = this->UseOutletTemp;
   11888             :     }
   11889             : 
   11890     6283865 :     if (this->SourceInletNode > 0 && this->SourceOutletNode > 0) {
   11891     1858870 :         state.dataLoopNodes->Node(this->SourceOutletNode) = state.dataLoopNodes->Node(this->SourceInletNode);
   11892             : 
   11893     1858870 :         state.dataLoopNodes->Node(this->SourceOutletNode).Temp = this->SourceOutletTemp;
   11894             :     }
   11895     6283865 : }
   11896             : 
   11897     6283865 : void WaterThermalTankData::ReportWaterThermalTank(EnergyPlusData &state)
   11898             : {
   11899             : 
   11900             :     // SUBROUTINE INFORMATION:
   11901             :     //       AUTHOR         Brandon Anderson
   11902             :     //       DATE WRITTEN   May 2000
   11903             :     //       MODIFIED       na
   11904             :     //       RE-ENGINEERED  Feb 2004, PGE
   11905             : 
   11906     6283865 :     Real64 SecInTimeStep = state.dataHVACGlobal->TimeStepSysSec;
   11907             : 
   11908     6283865 :     this->UnmetEnergy = this->UnmetRate * SecInTimeStep;
   11909     6283865 :     this->LossEnergy = this->LossRate * SecInTimeStep;
   11910     6283865 :     this->FlueLossEnergy = this->FlueLossRate * SecInTimeStep;
   11911     6283865 :     this->UseEnergy = this->UseRate * SecInTimeStep;
   11912     6283865 :     this->TotalDemandEnergy = this->TotalDemandRate * SecInTimeStep;
   11913     6283865 :     this->SourceEnergy = this->SourceRate * SecInTimeStep;
   11914     6283865 :     this->HeaterEnergy = this->HeaterRate * SecInTimeStep;
   11915     6283865 :     this->HeaterEnergy1 = this->HeaterRate1 * SecInTimeStep;
   11916     6283865 :     this->HeaterEnergy2 = this->HeaterRate2 * SecInTimeStep;
   11917     6283865 :     this->FuelEnergy = this->FuelRate * SecInTimeStep;
   11918     6283865 :     this->VentEnergy = this->VentRate * SecInTimeStep;
   11919     6283865 :     this->OffCycParaFuelEnergy = this->OffCycParaFuelRate * SecInTimeStep;
   11920     6283865 :     this->OffCycParaEnergyToTank = this->OffCycParaRateToTank * SecInTimeStep;
   11921     6283865 :     this->OnCycParaFuelEnergy = this->OnCycParaFuelRate * SecInTimeStep;
   11922     6283865 :     this->OnCycParaEnergyToTank = this->OnCycParaRateToTank * SecInTimeStep;
   11923     6283865 :     this->NetHeatTransferEnergy = this->NetHeatTransferRate * SecInTimeStep;
   11924     6283865 :     this->VolumeConsumed = this->VolFlowRate * SecInTimeStep;
   11925     6283865 : }
   11926             : 
   11927         341 : void WaterThermalTankData::CalcStandardRatings(EnergyPlusData &state)
   11928             : {
   11929             : 
   11930             :     // SUBROUTINE INFORMATION:
   11931             :     //       AUTHOR         Peter Graham Ellis
   11932             :     //       DATE WRITTEN   January 2005
   11933             :     //       MODIFIED       R. Raustad, July 2005 - added HPWH to ratings procedure
   11934             :     //       RE-ENGINEERED  na
   11935             : 
   11936             :     // PURPOSE OF THIS SUBROUTINE:
   11937             :     // Calculates the water heater standard ratings, such as Energy Factor and Recovery Efficiency.  Results are written
   11938             :     // to the EIO file.  Standard ratings are not calculated for storage-only tanks, i.e., MaxCapacity = 0, nor for Integrated Heat Pumps
   11939             : 
   11940             :     // METHODOLOGY EMPLOYED:
   11941             :     // Water heater inputs are set to the specified test conditions. For HPWHs, the heating capacity and COP are assumed
   11942             :     // to be the primary element in the water heater and are used during the rating procedure.  CalcWaterThermalTankMixed
   11943             :     // is iteratively called in a self-contained, 24 hour simulation of the standard test procedure.
   11944             : 
   11945             :     // REFERENCES:
   11946             :     // Title 10, Code of Federal Regulations, Part 430- Energy Conservation Program for Consumer Products, Appendix E to
   11947             :     // Subpart B- Uniform Test Procedure for Measuring the Energy Consumption of Water Heaters, January 1, 2004.
   11948             : 
   11949         341 :     if (this->AlreadyRated) { // bail we already did this one
   11950         150 :         return;
   11951             :     }
   11952             : 
   11953             :     bool FirstTimeFlag; // used during HPWH rating procedure
   11954         191 :     bool bIsVSCoil = false;
   11955             :     Real64 RecoveryEfficiency;
   11956             :     Real64 EnergyFactor;
   11957         191 :     Real64 RatedDXCoilTotalCapacity = 0.0;
   11958         191 :     if (this->MaxCapacity > 0.0 || this->HeatPumpNum > 0) {
   11959             :         // Set test conditions
   11960         186 :         this->AmbientTemp = 19.7222;   // 67.5 F
   11961         186 :         this->UseInletTemp = 14.4444;  // 58 F
   11962         186 :         this->SetPointTemp = 57.2222;  // 135 F
   11963         186 :         this->SetPointTemp2 = 57.2222; // 135 F
   11964         186 :         this->TankTemp = 57.2222;      // Initialize tank temperature
   11965         186 :         if (this->Nodes > 0)
   11966         144 :             for (auto &e : this->Node)
   11967         128 :                 e.Temp = 57.2222;
   11968             : 
   11969         186 :         Real64 TotalDrawMass = 0.243402 * Psychrometrics::RhoH2O(Constant::InitConvTemp); // 64.3 gal * rho
   11970         186 :         Real64 DrawMass = TotalDrawMass / 6.0;                                            // 6 equal draws
   11971         186 :         Real64 SecInTimeStep = state.dataHVACGlobal->TimeStepSysSec;
   11972         186 :         Real64 DrawMassFlowRate = DrawMass / SecInTimeStep;
   11973         186 :         Real64 FuelEnergy_loc = 0.0;
   11974         186 :         FirstTimeFlag = true;
   11975             : 
   11976         186 :         int TimeStepPerHour = int(1.0 / state.dataHVACGlobal->TimeStepSys);
   11977             :         // Simulate 24 hour test
   11978       23274 :         for (int Step = 1; Step <= TimeStepPerHour * 24; ++Step) {
   11979             : 
   11980       23088 :             if (Step == 1 || Step == (1 + TimeStepPerHour) || Step == (1 + TimeStepPerHour * 2) || Step == (1 + TimeStepPerHour * 3) ||
   11981       22344 :                 Step == (1 + TimeStepPerHour * 4) || Step == (1 + TimeStepPerHour * 5)) { // Hour 1 | Hour 2 | Hour 3 | Hour 4 | Hour 5 | Hour 6
   11982             : 
   11983        1116 :                 this->UseMassFlowRate = DrawMassFlowRate;
   11984             :             } else {
   11985       21972 :                 this->UseMassFlowRate = 0.0;
   11986             :             }
   11987             : 
   11988       23088 :             this->SavedTankTemp = this->TankTemp;
   11989       23088 :             this->SavedMode = this->Mode;
   11990       23088 :             if (this->Nodes > 0) {
   11991       33552 :                 for (auto &e : this->Node)
   11992       30336 :                     e.SavedTemp = e.Temp;
   11993        3216 :                 this->SavedHeaterOn1 = this->HeaterOn1;
   11994        3216 :                 this->SavedHeaterOn2 = this->HeaterOn2;
   11995             :             }
   11996             : 
   11997       23088 :             if (this->HeatPumpNum == 0) {
   11998             : 
   11999       19296 :                 if (this->WaterThermalTankType == DataPlant::PlantEquipmentType::WtrHeaterMixed) {
   12000       18672 :                     this->CalcWaterThermalTankMixed(state);
   12001             : 
   12002         624 :                 } else if (this->WaterThermalTankType == DataPlant::PlantEquipmentType::WtrHeaterStratified) {
   12003         624 :                     this->CalcWaterThermalTankStratified(state);
   12004             :                 }
   12005             : 
   12006             :             } else {
   12007             : 
   12008        3792 :                 int HPNum = this->HeatPumpNum;  // Convenience variable
   12009        3792 :                 Real64 AmbientHumRat = 0.00717; // Humidity ratio at 67.5 F / 50% RH
   12010             : 
   12011             :                 //       set the heat pump air- and water-side mass flow rate
   12012        3792 :                 Real64 MdotWater = state.dataWaterThermalTanks->HPWaterHeater(HPNum).OperatingWaterFlowRate * Psychrometrics::RhoH2O(this->TankTemp);
   12013        3792 :                 Real64 mdotAir = state.dataWaterThermalTanks->HPWaterHeater(HPNum).OperatingAirMassFlowRate;
   12014             : 
   12015             :                 // ?? why is HPWH condenser inlet node temp reset inside the for loop? shouldn't it chnage with the tank temp throughout these
   12016             :                 // iterations?
   12017        3792 :                 if (state.dataWaterThermalTanks->HPWaterHeater(HPNum).HPWHType == DataPlant::PlantEquipmentType::HeatPumpWtrHeaterPumped) {
   12018             :                     // set the condenser inlet node mass flow rate and temperature
   12019        2064 :                     state.dataLoopNodes->Node(state.dataWaterThermalTanks->HPWaterHeater(HPNum).CondWaterInletNode).MassFlowRate = MdotWater;
   12020        2064 :                     state.dataLoopNodes->Node(state.dataWaterThermalTanks->HPWaterHeater(HPNum).CondWaterInletNode).Temp = this->TankTemp;
   12021             :                 }
   12022             : 
   12023             :                 //       initialize temperatures for HPWH DX Coil heating capacity and COP curves
   12024        3792 :                 state.dataHVACGlobal->HPWHInletDBTemp = this->AmbientTemp;
   12025        7584 :                 state.dataHVACGlobal->HPWHInletWBTemp =
   12026        3792 :                     Psychrometrics::PsyTwbFnTdbWPb(state, state.dataHVACGlobal->HPWHInletDBTemp, AmbientHumRat, state.dataEnvrn->OutBaroPress);
   12027             : 
   12028             :                 //       set up full air flow on DX coil inlet node
   12029        3792 :                 if (state.dataWaterThermalTanks->HPWaterHeater(HPNum).InletAirMixerNode > 0) {
   12030         288 :                     state.dataLoopNodes->Node(state.dataWaterThermalTanks->HPWaterHeater(HPNum).InletAirMixerNode).MassFlowRate = mdotAir;
   12031         288 :                     state.dataLoopNodes->Node(state.dataWaterThermalTanks->HPWaterHeater(HPNum).InletAirMixerNode).MassFlowRateMaxAvail = mdotAir;
   12032         288 :                     state.dataLoopNodes->Node(state.dataWaterThermalTanks->HPWaterHeater(HPNum).InletAirMixerNode).Temp = this->AmbientTemp;
   12033         288 :                     state.dataLoopNodes->Node(state.dataWaterThermalTanks->HPWaterHeater(HPNum).InletAirMixerNode).HumRat = AmbientHumRat;
   12034         288 :                     state.dataLoopNodes->Node(state.dataWaterThermalTanks->HPWaterHeater(HPNum).InletAirMixerNode).Enthalpy =
   12035         288 :                         Psychrometrics::PsyHFnTdbW(this->AmbientTemp, AmbientHumRat);
   12036             :                 } else {
   12037        3504 :                     if (state.dataWaterThermalTanks->HPWaterHeater(HPNum).OutsideAirNode == 0) {
   12038        1056 :                         state.dataLoopNodes->Node(state.dataWaterThermalTanks->HPWaterHeater(HPNum).HeatPumpAirInletNode).MassFlowRate = mdotAir;
   12039        1056 :                         state.dataLoopNodes->Node(state.dataWaterThermalTanks->HPWaterHeater(HPNum).HeatPumpAirInletNode).MassFlowRateMaxAvail =
   12040             :                             mdotAir;
   12041        1056 :                         state.dataLoopNodes->Node(state.dataWaterThermalTanks->HPWaterHeater(HPNum).HeatPumpAirInletNode).Temp = this->AmbientTemp;
   12042        1056 :                         state.dataLoopNodes->Node(state.dataWaterThermalTanks->HPWaterHeater(HPNum).HeatPumpAirInletNode).HumRat = AmbientHumRat;
   12043        1056 :                         state.dataLoopNodes->Node(state.dataWaterThermalTanks->HPWaterHeater(HPNum).HeatPumpAirInletNode).Enthalpy =
   12044        1056 :                             Psychrometrics::PsyHFnTdbW(this->AmbientTemp, AmbientHumRat);
   12045             :                     } else {
   12046        2448 :                         state.dataLoopNodes->Node(state.dataWaterThermalTanks->HPWaterHeater(HPNum).OutsideAirNode).MassFlowRate = mdotAir;
   12047        2448 :                         state.dataLoopNodes->Node(state.dataWaterThermalTanks->HPWaterHeater(HPNum).OutsideAirNode).MassFlowRateMaxAvail = mdotAir;
   12048        2448 :                         state.dataLoopNodes->Node(state.dataWaterThermalTanks->HPWaterHeater(HPNum).OutsideAirNode).Temp = this->AmbientTemp;
   12049        2448 :                         state.dataLoopNodes->Node(state.dataWaterThermalTanks->HPWaterHeater(HPNum).OutsideAirNode).HumRat = AmbientHumRat;
   12050        2448 :                         state.dataLoopNodes->Node(state.dataWaterThermalTanks->HPWaterHeater(HPNum).OutsideAirNode).Enthalpy =
   12051        2448 :                             Psychrometrics::PsyHFnTdbW(this->AmbientTemp, AmbientHumRat);
   12052             :                     }
   12053             :                 }
   12054             : 
   12055        3792 :                 state.dataHVACGlobal->HPWHCrankcaseDBTemp = this->AmbientTemp;
   12056             : 
   12057        3792 :                 if (Util::SameString(state.dataWaterThermalTanks->HPWaterHeater(HPNum).DXCoilType,
   12058        6960 :                                      "Coil:WaterHeating:AirToWaterHeatPump:VariableSpeed") ||
   12059        3168 :                     (state.dataWaterThermalTanks->HPWaterHeater(HPNum).bIsIHP)) {
   12060         768 :                     bIsVSCoil = true;
   12061         768 :                     std::string VSCoilName = state.dataWaterThermalTanks->HPWaterHeater(HPNum).DXCoilName;
   12062         768 :                     int VSCoilNum = state.dataWaterThermalTanks->HPWaterHeater(HPNum).DXCoilNum;
   12063         768 :                     if (state.dataWaterThermalTanks->HPWaterHeater(HPNum).bIsIHP) {
   12064         144 :                         VSCoilNum =
   12065         144 :                             state.dataIntegratedHP->IntegratedHeatPumps(state.dataWaterThermalTanks->HPWaterHeater(HPNum).DXCoilNum).SCWHCoilIndex;
   12066             :                         VSCoilName =
   12067         144 :                             state.dataIntegratedHP->IntegratedHeatPumps(state.dataWaterThermalTanks->HPWaterHeater(HPNum).DXCoilNum).SCWHCoilName;
   12068             :                     }
   12069             : 
   12070         768 :                     Real64 RhoWater = Psychrometrics::RhoH2O(this->TankTemp);
   12071         768 :                     auto &HPWH = state.dataWaterThermalTanks->HPWaterHeater(HPNum);
   12072         768 :                     this->SetVSHPWHFlowRates(
   12073             :                         state,
   12074             :                         HPWH,
   12075         768 :                         state.dataVariableSpeedCoils->VarSpeedCoil(state.dataWaterThermalTanks->HPWaterHeater(HPNum).DXCoilNum).NormSpedLevel,
   12076             :                         1.0,
   12077             :                         RhoWater,
   12078             :                         MdotWater,
   12079             :                         true);
   12080             :                     //       simulate the HPWH coil/fan to find heating capacity
   12081         768 :                     if (state.dataWaterThermalTanks->HPWaterHeater(HPNum).fanPlace == HVAC::FanPlace::BlowThru) {
   12082             :                         //   simulate fan and DX coil twice
   12083         576 :                         state.dataFans->fans(state.dataWaterThermalTanks->HPWaterHeater(HPNum).FanNum)->simulate(state, true, _, _);
   12084             : 
   12085         576 :                         VariableSpeedCoils::SimVariableSpeedCoils(
   12086             :                             state,
   12087             :                             VSCoilName,
   12088             :                             VSCoilNum,
   12089             :                             HVAC::FanOp::Cycling,
   12090             :                             HVAC::CompressorOp::On,
   12091             :                             1.0,
   12092         576 :                             state.dataVariableSpeedCoils->VarSpeedCoil(state.dataWaterThermalTanks->HPWaterHeater(HPNum).DXCoilNum).NormSpedLevel,
   12093             :                             1.0,
   12094             :                             0.0,
   12095             :                             0.0,
   12096             :                             1.0);
   12097             : 
   12098         576 :                         state.dataFans->fans(state.dataWaterThermalTanks->HPWaterHeater(HPNum).FanNum)->simulate(state, true, _, _);
   12099             : 
   12100         576 :                         VariableSpeedCoils::SimVariableSpeedCoils(
   12101             :                             state,
   12102             :                             VSCoilName,
   12103             :                             VSCoilNum,
   12104             :                             HVAC::FanOp::Cycling,
   12105             :                             HVAC::CompressorOp::On,
   12106             :                             1.0,
   12107         576 :                             state.dataVariableSpeedCoils->VarSpeedCoil(state.dataWaterThermalTanks->HPWaterHeater(HPNum).DXCoilNum).NormSpedLevel,
   12108             :                             1.0,
   12109             :                             0.0,
   12110             :                             0.0,
   12111             :                             1.0);
   12112             :                     } else {
   12113             :                         //   simulate DX coil and fan twice to pass fan power (FanElecPower) to DX coil
   12114         192 :                         VariableSpeedCoils::SimVariableSpeedCoils(
   12115             :                             state,
   12116             :                             VSCoilName,
   12117             :                             VSCoilNum,
   12118             :                             HVAC::FanOp::Cycling,
   12119             :                             HVAC::CompressorOp::On,
   12120             :                             1.0,
   12121         192 :                             state.dataVariableSpeedCoils->VarSpeedCoil(state.dataWaterThermalTanks->HPWaterHeater(HPNum).DXCoilNum).NormSpedLevel,
   12122             :                             1.0,
   12123             :                             0.0,
   12124             :                             0.0,
   12125             :                             1.0);
   12126             : 
   12127         192 :                         state.dataFans->fans(state.dataWaterThermalTanks->HPWaterHeater(HPNum).FanNum)->simulate(state, true, _, _);
   12128             : 
   12129         192 :                         VariableSpeedCoils::SimVariableSpeedCoils(
   12130             :                             state,
   12131             :                             VSCoilName,
   12132             :                             VSCoilNum,
   12133             :                             HVAC::FanOp::Cycling,
   12134             :                             HVAC::CompressorOp::On,
   12135             :                             1.0,
   12136         192 :                             state.dataVariableSpeedCoils->VarSpeedCoil(state.dataWaterThermalTanks->HPWaterHeater(HPNum).DXCoilNum).NormSpedLevel,
   12137             :                             1.0,
   12138             :                             0.0,
   12139             :                             0.0,
   12140             :                             1.0);
   12141             : 
   12142         192 :                         state.dataFans->fans(state.dataWaterThermalTanks->HPWaterHeater(HPNum).FanNum)->simulate(state, true, _, _);
   12143             :                     }
   12144             : 
   12145         768 :                     this->MaxCapacity = state.dataVariableSpeedCoils->VSHPWHHeatingCapacity;
   12146         768 :                     this->MinCapacity = state.dataVariableSpeedCoils->VSHPWHHeatingCapacity;
   12147         768 :                     this->Efficiency = state.dataVariableSpeedCoils->VSHPWHHeatingCOP;
   12148         768 :                 } else {
   12149        3024 :                     bIsVSCoil = false;
   12150             :                     //       simulate the HPWH coil/fan to find heating capacity
   12151        3024 :                     if (state.dataWaterThermalTanks->HPWaterHeater(HPNum).fanPlace == HVAC::FanPlace::BlowThru) {
   12152         720 :                         if (FirstTimeFlag) { // first time DXCoils::DXCoil is called, it's sized at the RatedCondenserWaterInlet temp, size and
   12153             :                                              // reset water inlet temp. If already sized, no harm.
   12154           7 :                             state.dataFans->fans(state.dataWaterThermalTanks->HPWaterHeater(HPNum).FanNum)->simulate(state, true, _, _);
   12155             : 
   12156          21 :                             DXCoils::SimDXCoil(state,
   12157           7 :                                                state.dataWaterThermalTanks->HPWaterHeater(HPNum).DXCoilName,
   12158             :                                                HVAC::CompressorOp::On,
   12159             :                                                true,
   12160           7 :                                                state.dataWaterThermalTanks->HPWaterHeater(HPNum).DXCoilNum,
   12161             :                                                HVAC::FanOp::Cycling,
   12162          14 :                                                1.0);
   12163           7 :                             state.dataLoopNodes->Node(state.dataWaterThermalTanks->HPWaterHeater(HPNum).CondWaterInletNode).Temp = this->TankTemp;
   12164             :                         }
   12165             :                         // ?? should only need to call twice if PLR<1 since this might affect OnOffFanPartLoadFraction which impacts fan energy.
   12166             :                         // PLR=1 here.
   12167         720 :                         state.dataFans->fans(state.dataWaterThermalTanks->HPWaterHeater(HPNum).FanNum)->simulate(state, true, _, _);
   12168             : 
   12169        2160 :                         DXCoils::SimDXCoil(state,
   12170         720 :                                            state.dataWaterThermalTanks->HPWaterHeater(HPNum).DXCoilName,
   12171             :                                            HVAC::CompressorOp::On,
   12172             :                                            true,
   12173         720 :                                            state.dataWaterThermalTanks->HPWaterHeater(HPNum).DXCoilNum,
   12174             :                                            HVAC::FanOp::Cycling,
   12175        1440 :                                            1.0);
   12176             : 
   12177         720 :                         state.dataFans->fans(state.dataWaterThermalTanks->HPWaterHeater(HPNum).FanNum)->simulate(state, true, _, _);
   12178             : 
   12179        2160 :                         DXCoils::SimDXCoil(state,
   12180         720 :                                            state.dataWaterThermalTanks->HPWaterHeater(HPNum).DXCoilName,
   12181             :                                            HVAC::CompressorOp::On,
   12182             :                                            true,
   12183         720 :                                            state.dataWaterThermalTanks->HPWaterHeater(HPNum).DXCoilNum,
   12184             :                                            HVAC::FanOp::Cycling,
   12185        1440 :                                            1.0);
   12186             :                     } else {
   12187        2304 :                         if (FirstTimeFlag) { // first time DXCoils::DXCoil is called, it's sized at the RatedCondenserWaterInlet temp, size and
   12188             :                                              // reset water inlet temp. If already sized, no harm.
   12189          27 :                             DXCoils::SimDXCoil(state,
   12190           9 :                                                state.dataWaterThermalTanks->HPWaterHeater(HPNum).DXCoilName,
   12191             :                                                HVAC::CompressorOp::On,
   12192             :                                                true,
   12193           9 :                                                state.dataWaterThermalTanks->HPWaterHeater(HPNum).DXCoilNum,
   12194             :                                                HVAC::FanOp::Cycling,
   12195          18 :                                                1.0);
   12196           9 :                             state.dataLoopNodes->Node(state.dataWaterThermalTanks->HPWaterHeater(HPNum).CondWaterInletNode).Temp = this->TankTemp;
   12197             :                         }
   12198             :                         // ?? should only need to call twice if PLR<1 since this might affect OnOffFanPartLoadFraction which impacts fan energy.
   12199             :                         // PLR=1 here.
   12200        6912 :                         DXCoils::SimDXCoil(state,
   12201        2304 :                                            state.dataWaterThermalTanks->HPWaterHeater(HPNum).DXCoilName,
   12202             :                                            HVAC::CompressorOp::On,
   12203             :                                            true,
   12204        2304 :                                            state.dataWaterThermalTanks->HPWaterHeater(HPNum).DXCoilNum,
   12205             :                                            HVAC::FanOp::Cycling,
   12206        4608 :                                            1.0);
   12207             : 
   12208        2304 :                         state.dataFans->fans(state.dataWaterThermalTanks->HPWaterHeater(HPNum).FanNum)->simulate(state, true, _, _);
   12209             : 
   12210        6912 :                         DXCoils::SimDXCoil(state,
   12211        2304 :                                            state.dataWaterThermalTanks->HPWaterHeater(HPNum).DXCoilName,
   12212             :                                            HVAC::CompressorOp::On,
   12213             :                                            true,
   12214        2304 :                                            state.dataWaterThermalTanks->HPWaterHeater(HPNum).DXCoilNum,
   12215             :                                            HVAC::FanOp::Cycling,
   12216        4608 :                                            1.0);
   12217             : 
   12218        2304 :                         state.dataFans->fans(state.dataWaterThermalTanks->HPWaterHeater(HPNum).FanNum)->simulate(state, true, _, _);
   12219             :                     }
   12220             : 
   12221        3024 :                     this->MaxCapacity = state.dataDXCoils->HPWHHeatingCapacity;
   12222        3024 :                     this->MinCapacity = state.dataDXCoils->HPWHHeatingCapacity;
   12223        3024 :                     this->Efficiency = state.dataDXCoils->HPWHHeatingCOP;
   12224             :                 }
   12225             : 
   12226        3792 :                 if (FirstTimeFlag) {
   12227          23 :                     RatedDXCoilTotalCapacity = state.dataHVACGlobal->DXCoilTotalCapacity;
   12228          23 :                     FirstTimeFlag = false;
   12229             :                 }
   12230             : 
   12231             :                 //       Switch the HPWH info with the tank info and call CalcWaterThermalTankMixed to get Standard Rating
   12232             :                 //       (backup element is assumed to be disabled during the rating procedure)
   12233        3792 :                 this->SourceMassFlowRate = 0.0;
   12234        3792 :                 this->OnCycParaLoad = state.dataWaterThermalTanks->HPWaterHeater(HPNum).OnCycParaLoad;
   12235        3792 :                 this->OffCycParaLoad = state.dataWaterThermalTanks->HPWaterHeater(HPNum).OffCycParaLoad;
   12236        3792 :                 this->OffCycParaFracToTank = 0.0;
   12237        3792 :                 this->OnCycParaFracToTank = 0.0;
   12238        3792 :                 this->PLFCurve = state.dataWaterThermalTanks->HPWaterHeater(HPNum).DXCoilPLFFPLR;
   12239             : 
   12240        3792 :                 if (this->WaterThermalTankType == DataPlant::PlantEquipmentType::WtrHeaterMixed) {
   12241        1200 :                     if (this->Efficiency > 0.0) this->CalcWaterThermalTankMixed(state);
   12242             : 
   12243        2592 :                 } else if (this->WaterThermalTankType == DataPlant::PlantEquipmentType::WtrHeaterStratified) {
   12244        2592 :                     if (this->Efficiency > 0.0) this->CalcWaterThermalTankStratified(state);
   12245             :                 }
   12246             : 
   12247             :                 //       reset the water heater data to original values
   12248        3792 :                 this->MaxCapacity = state.dataWaterThermalTanks->HPWaterHeater(HPNum).BackupElementCapacity;
   12249        3792 :                 this->MinCapacity = state.dataWaterThermalTanks->HPWaterHeater(HPNum).BackupElementCapacity;
   12250        3792 :                 this->Efficiency = state.dataWaterThermalTanks->HPWaterHeater(HPNum).BackupElementEfficiency;
   12251        3792 :                 this->OnCycParaLoad = state.dataWaterThermalTanks->HPWaterHeater(HPNum).WHOnCycParaLoad;
   12252        3792 :                 this->OffCycParaLoad = state.dataWaterThermalTanks->HPWaterHeater(HPNum).WHOffCycParaLoad;
   12253        3792 :                 this->OnCycParaFracToTank = state.dataWaterThermalTanks->HPWaterHeater(HPNum).WHOnCycParaFracToTank;
   12254        3792 :                 this->OffCycParaFracToTank = state.dataWaterThermalTanks->HPWaterHeater(HPNum).WHOffCycParaFracToTank;
   12255        3792 :                 this->PLFCurve = state.dataWaterThermalTanks->HPWaterHeater(HPNum).WHPLFCurve;
   12256             :             }
   12257             : 
   12258       23088 :             FuelEnergy_loc += (this->FuelRate + this->OffCycParaFuelRate + this->OnCycParaFuelRate) * SecInTimeStep;
   12259             : 
   12260             :         } // Step
   12261             : 
   12262         186 :         if (this->FirstRecoveryDone && this->FirstRecoveryFuel > 0.0) {
   12263             :             // Calculate Recovery Efficiency based on energy used to recover from the first draw
   12264             :             // FirstRecoveryFuel is recorded inside the CalcWaterThermalTank subroutine
   12265         168 :             RecoveryEfficiency = DrawMass * Psychrometrics::CPHW(57.2222) * (57.2222 - 14.4444) / this->FirstRecoveryFuel;
   12266             : 
   12267             :             // Calculate Energy Factor based on total energy (including parasitics) used over entire test
   12268         168 :             EnergyFactor = TotalDrawMass * Psychrometrics::CPHW(57.2222) * (57.2222 - 14.4444) / FuelEnergy_loc;
   12269             : 
   12270             :         } else {
   12271          18 :             RecoveryEfficiency = 0.0;
   12272          18 :             EnergyFactor = 0.0;
   12273             :             // If this a regular tank, or an HPWH that's not an Integrated one
   12274          18 :             if ((this->HeatPumpNum == 0) || !state.dataWaterThermalTanks->HPWaterHeater(this->HeatPumpNum).bIsIHP) {
   12275          34 :                 ShowWarningError(
   12276             :                     state,
   12277          34 :                     format("Water heater = {}:  Recovery Efficiency and Energy Factor could not be calculated during the test for standard ratings",
   12278          17 :                            this->Name));
   12279          17 :                 ShowContinueError(state, "Setpoint was never recovered and/or heater never turned on");
   12280             :             }
   12281             :         }
   12282             : 
   12283         186 :     } else {
   12284             : 
   12285             :         // Storage-only tank
   12286           5 :         RecoveryEfficiency = 0.0;
   12287           5 :         EnergyFactor = 0.0;
   12288             : 
   12289             :     } // WaterThermalTank(WaterThermalTankNum)%MaxCapacity > 0.0
   12290             : 
   12291             :     // create predefined report
   12292             :     // Store values for the input verification and summary report
   12293         191 :     std::string equipName;
   12294         191 :     if (this->HeatPumpNum == 0) {
   12295         168 :         equipName = this->Name;
   12296         168 :         OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchSWHType, equipName, this->Type);
   12297         168 :         OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchSWHVol, equipName, this->Volume);
   12298         168 :         OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchSWHHeatIn, equipName, this->MaxCapacity);
   12299         168 :         OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchSWHThEff, equipName, this->Efficiency);
   12300         168 :         OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchSWHRecEff, equipName, RecoveryEfficiency);
   12301         168 :         OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchSWHEnFac, equipName, EnergyFactor);
   12302             :     } else {
   12303          23 :         equipName = state.dataWaterThermalTanks->HPWaterHeater(this->HeatPumpNum).Name;
   12304          46 :         OutputReportPredefined::PreDefTableEntry(
   12305          46 :             state, state.dataOutRptPredefined->pdchSWHType, equipName, state.dataWaterThermalTanks->HPWaterHeater(this->HeatPumpNum).Type);
   12306          23 :         OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchSWHVol, equipName, this->Volume);
   12307          23 :         if (bIsVSCoil) {
   12308          21 :             OutputReportPredefined::PreDefTableEntry(
   12309          14 :                 state, state.dataOutRptPredefined->pdchSWHHeatIn, equipName, state.dataVariableSpeedCoils->VSHPWHHeatingCapacity);
   12310             :         } else {
   12311          48 :             OutputReportPredefined::PreDefTableEntry(
   12312          32 :                 state, state.dataOutRptPredefined->pdchSWHHeatIn, equipName, state.dataDXCoils->HPWHHeatingCapacity);
   12313             :         }
   12314          23 :         OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchSWHThEff, equipName, this->Efficiency);
   12315          23 :         OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchSWHRecEff, equipName, RecoveryEfficiency);
   12316          23 :         OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchSWHEnFac, equipName, EnergyFactor);
   12317             :     }
   12318             : 
   12319             :     // Write test results
   12320         191 :     if (this->HeatPumpNum == 0) {
   12321             :         Real64 MaxCapacity_loc;
   12322         168 :         if (this->WaterThermalTankType == DataPlant::PlantEquipmentType::WtrHeaterStratified) {
   12323           5 :             if (this->StratifiedControlMode == PriorityControlMode::MasterSlave) {
   12324           5 :                 MaxCapacity_loc = max(this->MaxCapacity, this->MaxCapacity2);
   12325             :             } else { // PrioritySimultaneous
   12326           0 :                 MaxCapacity_loc = this->MaxCapacity + this->MaxCapacity2;
   12327             :             }
   12328             :         } else { // WaterHeaterMixed
   12329         163 :             MaxCapacity_loc = this->MaxCapacity;
   12330             :         }
   12331             : 
   12332             :         static constexpr std::string_view Format_720("Water Heater Information,{},{},{:.4T},{:.1T},{:.3T},{:.4T}\n");
   12333         168 :         print(state.files.eio, Format_720, this->Type, this->Name, this->Volume, MaxCapacity_loc, RecoveryEfficiency, EnergyFactor);
   12334             :     } else {
   12335             :         static constexpr std::string_view Format_721("Heat Pump Water Heater Information,{},{},{:.4T},{:.1T},{:.3T},{:.4T},{:.0T}\n");
   12336          23 :         print(state.files.eio,
   12337             :               Format_721,
   12338          23 :               state.dataWaterThermalTanks->HPWaterHeater(this->HeatPumpNum).Type,
   12339          23 :               state.dataWaterThermalTanks->HPWaterHeater(this->HeatPumpNum).Name,
   12340          23 :               this->Volume,
   12341          23 :               state.dataDXCoils->HPWHHeatingCapacity,
   12342             :               RecoveryEfficiency,
   12343             :               EnergyFactor,
   12344             :               RatedDXCoilTotalCapacity);
   12345             :     }
   12346             : 
   12347         191 :     this->AlreadyRated = true;
   12348         191 : }
   12349             : 
   12350          10 : void WaterThermalTankData::ReportCWTankInits(EnergyPlusData &state)
   12351             : {
   12352             : 
   12353             :     // SUBROUTINE INFORMATION:
   12354             :     //       AUTHOR         B. Griffith
   12355             :     //       DATE WRITTEN   March 2009
   12356             :     //       MODIFIED       na
   12357             :     //       RE-ENGINEERED  na
   12358             : 
   12359             :     // PURPOSE OF THIS SUBROUTINE:
   12360             :     // send chilled water tank info to EIO
   12361             : 
   12362          10 :     if (this->myOneTimeInitFlag) {
   12363           0 :         this->setupOutputVars(state);
   12364           0 :         this->myOneTimeInitFlag = false;
   12365             :     }
   12366             : 
   12367          10 :     if (this->AlreadyReported) { // bail we already did this one
   12368           4 :         return;
   12369             :     }
   12370             : 
   12371             :     static constexpr std::string_view Format_728("Chilled Water Tank Information,{},{},{:.4T},{:.4T},{:.4T}\n");
   12372           6 :     print(state.files.eio, Format_728, this->Type, this->Name, this->Volume, this->UseDesignVolFlowRate, this->SourceDesignVolFlowRate);
   12373             : 
   12374           6 :     this->AlreadyReported = true;
   12375             : }
   12376             : 
   12377      800828 : Real64 WaterThermalTankData::FindStratifiedTankSensedTemp(EnergyPlusData &state, bool UseAverage)
   12378             : {
   12379             : 
   12380             :     // FUNCTION INFORMATION:
   12381             :     //       AUTHOR         B. Griffith
   12382             :     //       DATE WRITTEN   March 2012
   12383             :     //       MODIFIED       na
   12384             :     //       RE-ENGINEERED  Noel Merket, April 2015
   12385             : 
   12386             :     // PURPOSE OF THIS FUNCTION:
   12387             :     // find tank temperature depending on how sensed
   12388             : 
   12389             :     // FUNCTION LOCAL VARIABLE DECLARATIONS:
   12390      800828 :     HeatPumpWaterHeaterData const &HPWH = state.dataWaterThermalTanks->HPWaterHeater(this->HeatPumpNum);
   12391             :     Real64 ControlSensor1Temp;
   12392             :     Real64 ControlSensor2Temp;
   12393             : 
   12394      800828 :     if (UseAverage) {
   12395      199442 :         ControlSensor1Temp = this->Node(HPWH.ControlSensor1Node).TempAvg;
   12396      199442 :         ControlSensor2Temp = this->Node(HPWH.ControlSensor2Node).TempAvg;
   12397             :     } else {
   12398      601386 :         ControlSensor1Temp = this->Node(HPWH.ControlSensor1Node).Temp;
   12399      601386 :         ControlSensor2Temp = this->Node(HPWH.ControlSensor2Node).Temp;
   12400             :     }
   12401             : 
   12402      800828 :     Real64 SensedTemp = ControlSensor1Temp * HPWH.ControlSensor1Weight + ControlSensor2Temp * HPWH.ControlSensor2Weight;
   12403             : 
   12404      800828 :     return SensedTemp;
   12405             : }
   12406             : 
   12407     6523006 : Real64 WaterThermalTankData::getDeadBandTemp()
   12408             : {
   12409     6523006 :     if (this->IsChilledWaterTank) {
   12410      397780 :         return (this->SetPointTemp + this->DeadBandDeltaTemp);
   12411             :     } else {
   12412     6125226 :         return (this->SetPointTemp - this->DeadBandDeltaTemp);
   12413             :     }
   12414             : }
   12415     5835179 : void WaterThermalTankData::oneTimeInit(EnergyPlusData &state)
   12416             : {
   12417     5835179 :     if (this->myOneTimeInitFlag) {
   12418         174 :         this->setupOutputVars(state);
   12419         174 :         this->myOneTimeInitFlag = false;
   12420             :     }
   12421     5835179 : }
   12422             : 
   12423          30 : void WaterThermalTankData::setBackupElementCapacity(EnergyPlusData &state)
   12424             : {
   12425             :     // Fix for #9001: The BackupElementCapacity was not being reset from the autosize value (-99999) which resulted in
   12426             :     // negative electric consumption.  Using a test for any negative numbers here instead of just -99999 for safety.
   12427             :     // Only reset the backup element capacity if a problem has been occured.
   12428          30 :     if (this->HeatPumpNum > 0) {
   12429          20 :         if (state.dataWaterThermalTanks->HPWaterHeater(this->HeatPumpNum).HPWHType == DataPlant::PlantEquipmentType::HeatPumpWtrHeaterWrapped) return;
   12430           0 :         if (state.dataWaterThermalTanks->HPWaterHeater(this->HeatPumpNum).BackupElementCapacity < 0.0) {
   12431           0 :             state.dataWaterThermalTanks->HPWaterHeater(this->HeatPumpNum).BackupElementCapacity = this->MaxCapacity;
   12432             :         }
   12433          10 :     } else if (this->DesuperheaterNum > 0) {
   12434           0 :         if (state.dataWaterThermalTanks->WaterHeaterDesuperheater(this->DesuperheaterNum).BackupElementCapacity < 0.0) {
   12435           0 :             state.dataWaterThermalTanks->WaterHeaterDesuperheater(this->DesuperheaterNum).BackupElementCapacity = this->MaxCapacity;
   12436             :         }
   12437             :     }
   12438             : }
   12439             : 
   12440          16 : bool GetHeatPumpWaterHeaterNodeNumber(EnergyPlusData &state, int const NodeNumber)
   12441             : {
   12442             :     // PURPOSE OF THIS FUNCTION:
   12443             :     // Check if a node is used by a heat pump water heater
   12444             :     // and can be excluded from an airflow network.
   12445             : 
   12446             :     // Return value
   12447             :     bool HeatPumpWaterHeaterNodeException;
   12448             : 
   12449             :     int HeatPumpWaterHeaterIndex;
   12450             : 
   12451          16 :     if (state.dataWaterThermalTanks->getWaterThermalTankInputFlag) {
   12452           0 :         GetWaterThermalTankInput(state);
   12453           0 :         state.dataWaterThermalTanks->getWaterThermalTankInputFlag = false;
   12454             :     }
   12455             : 
   12456          16 :     HeatPumpWaterHeaterNodeException = false;
   12457             : 
   12458          26 :     for (HeatPumpWaterHeaterIndex = 1; HeatPumpWaterHeaterIndex <= state.dataWaterThermalTanks->numHeatPumpWaterHeater; ++HeatPumpWaterHeaterIndex) {
   12459             : 
   12460             :         // Get heat pump water heater data
   12461          16 :         HeatPumpWaterHeaterData &HPWH = state.dataWaterThermalTanks->HPWaterHeater(HeatPumpWaterHeaterIndex);
   12462             : 
   12463             :         // "Zone and outdoor air" configuration is expected break the conservation of mass
   12464          16 :         if (HPWH.InletAirConfiguration != WTTAmbientTemp::ZoneAndOA) {
   12465             : 
   12466             :             // Air outlet node
   12467          16 :             if (NodeNumber == HPWH.HeatPumpAirOutletNode) {
   12468           2 :                 HeatPumpWaterHeaterNodeException = true;
   12469           2 :                 break;
   12470             :             }
   12471             : 
   12472             :             // Air inlet node
   12473          14 :             if (NodeNumber == HPWH.HeatPumpAirInletNode) {
   12474           2 :                 HeatPumpWaterHeaterNodeException = true;
   12475           2 :                 break;
   12476             :             }
   12477             : 
   12478             :             // Get fan inlet node index
   12479          12 :             int FanInletNodeIndex = state.dataFans->fans(HPWH.FanNum)->inletNodeNum;
   12480             : 
   12481             :             // Fan inlet node
   12482          12 :             if (NodeNumber == FanInletNodeIndex) {
   12483           2 :                 HeatPumpWaterHeaterNodeException = true;
   12484           2 :                 break;
   12485             :             }
   12486             : 
   12487             :             // Fan outlet node
   12488          10 :             if (NodeNumber == HPWH.FanOutletNode) {
   12489           0 :                 HeatPumpWaterHeaterNodeException = true;
   12490           0 :                 break;
   12491             :             }
   12492             : 
   12493             :             // Outside air node
   12494          10 :             if (NodeNumber == HPWH.OutsideAirNode) {
   12495           0 :                 HeatPumpWaterHeaterNodeException = true;
   12496           0 :                 break;
   12497             :             }
   12498             : 
   12499             :             // Exhaust air node
   12500          10 :             if (NodeNumber == HPWH.ExhaustAirNode) {
   12501           0 :                 HeatPumpWaterHeaterNodeException = true;
   12502           0 :                 break;
   12503             :             }
   12504             :         }
   12505             :     }
   12506             : 
   12507          16 :     return HeatPumpWaterHeaterNodeException;
   12508             : }
   12509             : 
   12510           0 : int getHeatPumpWaterHeaterIndex(EnergyPlusData &state, std::string_view CompName)
   12511             : {
   12512           0 :     if (state.dataWaterThermalTanks->getWaterThermalTankInputFlag) {
   12513           0 :         GetWaterThermalTankInput(state);
   12514           0 :         state.dataWaterThermalTanks->getWaterThermalTankInputFlag = false;
   12515             :     }
   12516             : 
   12517           0 :     for (int HPNum = 1; HPNum <= state.dataWaterThermalTanks->numHeatPumpWaterHeater; ++HPNum) {
   12518           0 :         if (Util::SameString(state.dataWaterThermalTanks->HPWaterHeater(HPNum).Name, CompName)) {
   12519           0 :             return HPNum;
   12520             :         }
   12521             :     }
   12522             : 
   12523           0 :     return 0;
   12524             : }
   12525             : 
   12526             : } // namespace EnergyPlus::WaterThermalTanks

Generated by: LCOV version 1.14