LCOV - code coverage report
Current view: top level - EnergyPlus - UnitHeater.cc (source / functions) Hit Total Coverage
Test: lcov.output.filtered Lines: 583 1042 56.0 %
Date: 2023-01-17 19:17:23 Functions: 9 10 90.0 %

          Line data    Source code
       1             : // EnergyPlus, Copyright (c) 1996-2023, 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             : // C++ Headers
      49             : #include <cmath>
      50             : 
      51             : // ObjexxFCL Headers
      52             : #include <ObjexxFCL/Array.functions.hh>
      53             : #include <ObjexxFCL/Fmath.hh>
      54             : 
      55             : // EnergyPlus Headers
      56             : #include <EnergyPlus/Autosizing/HeatingAirFlowSizing.hh>
      57             : #include <EnergyPlus/Autosizing/HeatingCapacitySizing.hh>
      58             : #include <EnergyPlus/BranchNodeConnections.hh>
      59             : #include <EnergyPlus/Data/EnergyPlusData.hh>
      60             : #include <EnergyPlus/DataEnvironment.hh>
      61             : #include <EnergyPlus/DataHVACGlobals.hh>
      62             : #include <EnergyPlus/DataHeatBalance.hh>
      63             : #include <EnergyPlus/DataLoopNode.hh>
      64             : #include <EnergyPlus/DataSizing.hh>
      65             : #include <EnergyPlus/DataZoneEnergyDemands.hh>
      66             : #include <EnergyPlus/DataZoneEquipment.hh>
      67             : #include <EnergyPlus/Fans.hh>
      68             : #include <EnergyPlus/FluidProperties.hh>
      69             : #include <EnergyPlus/General.hh>
      70             : #include <EnergyPlus/GeneralRoutines.hh>
      71             : #include <EnergyPlus/HVACFan.hh>
      72             : #include <EnergyPlus/HeatingCoils.hh>
      73             : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
      74             : #include <EnergyPlus/NodeInputManager.hh>
      75             : #include <EnergyPlus/OutputProcessor.hh>
      76             : #include <EnergyPlus/PlantUtilities.hh>
      77             : #include <EnergyPlus/Psychrometrics.hh>
      78             : #include <EnergyPlus/ReportCoilSelection.hh>
      79             : #include <EnergyPlus/ScheduleManager.hh>
      80             : #include <EnergyPlus/SteamCoils.hh>
      81             : #include <EnergyPlus/UnitHeater.hh>
      82             : #include <EnergyPlus/UtilityRoutines.hh>
      83             : #include <EnergyPlus/WaterCoils.hh>
      84             : 
      85             : namespace EnergyPlus {
      86             : 
      87             : namespace UnitHeater {
      88             : 
      89             :     // Module containing the routines dealing with the Unit Heater
      90             : 
      91             :     // MODULE INFORMATION:
      92             :     //       AUTHOR         Rick Strand
      93             :     //       DATE WRITTEN   May 2000
      94             :     //       MODIFIED       Brent Griffith, Sept 2010, plant upgrades, fluid properties
      95             :     //       MODIFIED       Bereket Nigusse, FSEC, October 2013, Added cycling fan operating mode
      96             :     //       RE-ENGINEERED  na
      97             : 
      98             :     // PURPOSE OF THIS MODULE:
      99             :     // To simulate unit heaters.  It is assumed that unit heaters are zone equipment
     100             :     // without any connection to outside air other than through a separately defined
     101             :     // air loop.
     102             : 
     103             :     // METHODOLOGY EMPLOYED:
     104             :     // Units are modeled as a collection of a fan and a heating coil.  The fan
     105             :     // can either be a continuously running fan or an on-off fan which turns on
     106             :     // only when there is actually a heating load.  This fan control works together
     107             :     // with the unit operation schedule to determine what the unit heater actually
     108             :     // does at a given point in time.
     109             : 
     110             :     // REFERENCES:
     111             :     // ASHRAE Systems and Equipment Handbook (SI), 1996. pp. 31.3-31.8
     112             :     // Rick Strand's unit heater module which was based upon Fred Buhl's fan coil
     113             :     // module (FanCoilUnits.cc)
     114             : 
     115             :     // Using/Aliasing
     116             :     using namespace DataLoopNode;
     117             :     using DataHVACGlobals::cFanTypes;
     118             :     using DataHVACGlobals::ContFanCycCoil;
     119             :     using DataHVACGlobals::CycFanCycCoil;
     120             :     using DataHVACGlobals::SmallAirVolFlow;
     121             :     using DataHVACGlobals::SmallLoad;
     122             :     using DataHVACGlobals::SmallMassFlow;
     123             :     using namespace ScheduleManager;
     124             :     using Psychrometrics::PsyCpAirFnW;
     125             :     using Psychrometrics::PsyHFnTdbW;
     126             :     using Psychrometrics::PsyRhoAirFnPbTdbW;
     127             :     using namespace FluidProperties;
     128             : 
     129             :     static constexpr std::string_view fluidNameSteam("STEAM");
     130             : 
     131      638739 :     void SimUnitHeater(EnergyPlusData &state,
     132             :                        std::string_view CompName,     // name of the fan coil unit
     133             :                        int const ZoneNum,             // number of zone being served
     134             :                        bool const FirstHVACIteration, // TRUE if 1st HVAC simulation of system timestep
     135             :                        Real64 &PowerMet,              // Sensible power supplied (W)
     136             :                        Real64 &LatOutputProvided,     // Latent add/removal supplied by window AC (kg/s), dehumid = negative
     137             :                        int &CompIndex)
     138             :     {
     139             : 
     140             :         // SUBROUTINE INFORMATION:
     141             :         //       AUTHOR         Rick Strand
     142             :         //       DATE WRITTEN   May 2000
     143             :         //       MODIFIED       Don Shirey, Aug 2009 (LatOutputProvided)
     144             :         //       RE-ENGINEERED  na
     145             : 
     146             :         // PURPOSE OF THIS SUBROUTINE:
     147             :         // This is the main driver subroutine for the Unit Heater simulation.
     148             : 
     149             :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     150             :         int UnitHeatNum; // index of unit heater being simulated
     151             : 
     152      638739 :         if (state.dataUnitHeaters->GetUnitHeaterInputFlag) {
     153          14 :             GetUnitHeaterInput(state);
     154          14 :             state.dataUnitHeaters->GetUnitHeaterInputFlag = false;
     155             :         }
     156             : 
     157             :         // Find the correct Unit Heater Equipment
     158      638739 :         if (CompIndex == 0) {
     159          63 :             UnitHeatNum = UtilityRoutines::FindItemInList(CompName, state.dataUnitHeaters->UnitHeat);
     160          63 :             if (UnitHeatNum == 0) {
     161           0 :                 ShowFatalError(state, "SimUnitHeater: Unit not found=" + std::string{CompName});
     162             :             }
     163          63 :             CompIndex = UnitHeatNum;
     164             :         } else {
     165      638676 :             UnitHeatNum = CompIndex;
     166      638676 :             if (UnitHeatNum > state.dataUnitHeaters->NumOfUnitHeats || UnitHeatNum < 1) {
     167           0 :                 ShowFatalError(state,
     168           0 :                                format("SimUnitHeater:  Invalid CompIndex passed={}, Number of Units={}, Entered Unit name={}",
     169             :                                       UnitHeatNum,
     170           0 :                                       state.dataUnitHeaters->NumOfUnitHeats,
     171           0 :                                       CompName));
     172             :             }
     173      638676 :             if (state.dataUnitHeaters->CheckEquipName(UnitHeatNum)) {
     174          63 :                 if (CompName != state.dataUnitHeaters->UnitHeat(UnitHeatNum).Name) {
     175           0 :                     ShowFatalError(state,
     176           0 :                                    format("SimUnitHeater: Invalid CompIndex passed={}, Unit name={}, stored Unit Name for that index={}",
     177             :                                           UnitHeatNum,
     178             :                                           CompName,
     179           0 :                                           state.dataUnitHeaters->UnitHeat(UnitHeatNum).Name));
     180             :                 }
     181          63 :                 state.dataUnitHeaters->CheckEquipName(UnitHeatNum) = false;
     182             :             }
     183             :         }
     184             : 
     185      638739 :         state.dataSize->ZoneEqUnitHeater = true;
     186             : 
     187      638739 :         InitUnitHeater(state, UnitHeatNum, ZoneNum, FirstHVACIteration);
     188             : 
     189      638739 :         state.dataSize->ZoneHeatingOnlyFan = true;
     190             : 
     191      638739 :         CalcUnitHeater(state, UnitHeatNum, ZoneNum, FirstHVACIteration, PowerMet, LatOutputProvided);
     192             : 
     193      638739 :         state.dataSize->ZoneHeatingOnlyFan = false;
     194             : 
     195             :         //  CALL UpdateUnitHeater
     196             : 
     197      638739 :         ReportUnitHeater(state, UnitHeatNum);
     198             : 
     199      638739 :         state.dataSize->ZoneEqUnitHeater = false;
     200      638739 :     }
     201             : 
     202          14 :     void GetUnitHeaterInput(EnergyPlusData &state)
     203             :     {
     204             : 
     205             :         // SUBROUTINE INFORMATION:
     206             :         //       AUTHOR         Rick Strand
     207             :         //       DATE WRITTEN   May 2000
     208             :         //       MODIFIED       Chandan Sharma, FSEC, March 2011: Added ZoneHVAC sys avail manager
     209             :         //                      Bereket Nigusse, FSEC, April 2011: eliminated input node names
     210             :         //                                                         & added fan object type
     211             :         //       RE-ENGINEERED  na
     212             : 
     213             :         // PURPOSE OF THIS SUBROUTINE:
     214             :         // Obtain the user input data for all of the unit heaters in the input file.
     215             : 
     216             :         // METHODOLOGY EMPLOYED:
     217             :         // Standard EnergyPlus methodology.
     218             : 
     219             :         // REFERENCES:
     220             :         // Fred Buhl's fan coil module (FanCoilUnits.cc)
     221             : 
     222             :         // Using/Aliasing
     223             :         using BranchNodeConnections::SetUpCompSets;
     224             :         using DataHVACGlobals::FanType_SimpleConstVolume;
     225             :         using DataHVACGlobals::FanType_SimpleOnOff;
     226             :         using DataHVACGlobals::FanType_SimpleVAV;
     227             : 
     228             :         using DataSizing::AutoSize;
     229             :         using Fans::GetFanAvailSchPtr;
     230             :         using Fans::GetFanIndex;
     231             :         using Fans::GetFanOutletNode;
     232             :         using Fans::GetFanType;
     233             :         using Fans::GetFanVolFlow;
     234             :         using NodeInputManager::GetOnlySingleNode;
     235             :         using SteamCoils::GetCoilSteamInletNode;
     236             :         using SteamCoils::GetSteamCoilIndex;
     237             :         using WaterCoils::GetCoilWaterInletNode;
     238             : 
     239             :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     240          14 :         bool ErrorsFound(false);                                               // Set to true if errors in input, fatal at end of routine
     241             :         int IOStatus;                                                          // Used in GetObjectItem
     242             :         bool IsNotOK;                                                          // TRUE if there was a problem with a list name
     243          14 :         bool errFlag(false);                                                   // interim error flag
     244             :         int NumAlphas;                                                         // Number of Alphas for each GetObjectItem call
     245             :         int NumNumbers;                                                        // Number of Numbers for each GetObjectItem call
     246             :         int NumFields;                                                         // Total number of fields in object
     247             :         int UnitHeatNum;                                                       // Item to be "gotten"
     248             :         static constexpr std::string_view RoutineName("GetUnitHeaterInput: "); // include trailing blank space
     249             :         Real64 FanVolFlow;                                                     // Fan volumetric flow rate
     250          28 :         std::string CurrentModuleObject;
     251          28 :         Array1D_string Alphas;         // Alpha items for object
     252          28 :         Array1D<Real64> Numbers;       // Numeric items for object
     253          28 :         Array1D_string cAlphaFields;   // Alpha field names
     254          28 :         Array1D_string cNumericFields; // Numeric field names
     255          28 :         Array1D_bool lAlphaBlanks;     // Logical array, alpha field input BLANK = .TRUE.
     256          28 :         Array1D_bool lNumericBlanks;   // Logical array, numeric field input BLANK = .TRUE.
     257             :         int CtrlZone;                  // index to loop counter
     258             :         int NodeNum;                   // index to loop counter
     259             :         bool ZoneNodeNotFound;         // used in error checking
     260             : 
     261             :         // Figure out how many unit heaters there are in the input file
     262          14 :         CurrentModuleObject = state.dataUnitHeaters->cMO_UnitHeater;
     263          14 :         state.dataUnitHeaters->NumOfUnitHeats = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject);
     264          14 :         state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, CurrentModuleObject, NumFields, NumAlphas, NumNumbers);
     265             : 
     266          14 :         Alphas.allocate(NumAlphas);
     267          14 :         Numbers.dimension(NumNumbers, 0.0);
     268          14 :         cAlphaFields.allocate(NumAlphas);
     269          14 :         cNumericFields.allocate(NumNumbers);
     270          14 :         lAlphaBlanks.dimension(NumAlphas, true);
     271          14 :         lNumericBlanks.dimension(NumNumbers, true);
     272             : 
     273             :         // Allocate the local derived type and do one-time initializations for all parts of it
     274          14 :         if (state.dataUnitHeaters->NumOfUnitHeats > 0) {
     275          14 :             state.dataUnitHeaters->UnitHeat.allocate(state.dataUnitHeaters->NumOfUnitHeats);
     276          14 :             state.dataUnitHeaters->CheckEquipName.allocate(state.dataUnitHeaters->NumOfUnitHeats);
     277          14 :             state.dataUnitHeaters->UnitHeatNumericFields.allocate(state.dataUnitHeaters->NumOfUnitHeats);
     278             :         }
     279          14 :         state.dataUnitHeaters->CheckEquipName = true;
     280             : 
     281          77 :         for (UnitHeatNum = 1; UnitHeatNum <= state.dataUnitHeaters->NumOfUnitHeats;
     282             :              ++UnitHeatNum) { // Begin looping over all of the unit heaters found in the input file...
     283             : 
     284          63 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
     285             :                                                                      CurrentModuleObject,
     286             :                                                                      UnitHeatNum,
     287             :                                                                      Alphas,
     288             :                                                                      NumAlphas,
     289             :                                                                      Numbers,
     290             :                                                                      NumNumbers,
     291             :                                                                      IOStatus,
     292             :                                                                      lNumericBlanks,
     293             :                                                                      lAlphaBlanks,
     294             :                                                                      cAlphaFields,
     295             :                                                                      cNumericFields);
     296             : 
     297          63 :             state.dataUnitHeaters->UnitHeatNumericFields(UnitHeatNum).FieldNames.allocate(NumNumbers);
     298          63 :             state.dataUnitHeaters->UnitHeatNumericFields(UnitHeatNum).FieldNames = "";
     299          63 :             state.dataUnitHeaters->UnitHeatNumericFields(UnitHeatNum).FieldNames = cNumericFields;
     300          63 :             UtilityRoutines::IsNameEmpty(state, Alphas(1), CurrentModuleObject, ErrorsFound);
     301             : 
     302          63 :             state.dataUnitHeaters->UnitHeat(UnitHeatNum).Name = Alphas(1);
     303          63 :             state.dataUnitHeaters->UnitHeat(UnitHeatNum).SchedName = Alphas(2);
     304          63 :             if (lAlphaBlanks(2)) {
     305           0 :                 state.dataUnitHeaters->UnitHeat(UnitHeatNum).SchedPtr = DataGlobalConstants::ScheduleAlwaysOn;
     306             :             } else {
     307          63 :                 state.dataUnitHeaters->UnitHeat(UnitHeatNum).SchedPtr = GetScheduleIndex(state, Alphas(2)); // convert schedule name to pointer
     308          63 :                 if (state.dataUnitHeaters->UnitHeat(UnitHeatNum).SchedPtr == 0) {
     309           0 :                     ShowSevereError(state,
     310           0 :                                     std::string{RoutineName} + CurrentModuleObject + ": invalid " + cAlphaFields(2) + " entered =" + Alphas(2) +
     311           0 :                                         " for " + cAlphaFields(1) + '=' + Alphas(1));
     312           0 :                     ErrorsFound = true;
     313             :                 }
     314             :             }
     315             : 
     316             :             // Main air nodes (except outside air node):
     317          63 :             state.dataUnitHeaters->UnitHeat(UnitHeatNum).AirInNode = GetOnlySingleNode(state,
     318          63 :                                                                                        Alphas(3),
     319             :                                                                                        ErrorsFound,
     320             :                                                                                        DataLoopNode::ConnectionObjectType::ZoneHVACUnitHeater,
     321          63 :                                                                                        Alphas(1),
     322             :                                                                                        DataLoopNode::NodeFluidType::Air,
     323             :                                                                                        DataLoopNode::ConnectionType::Inlet,
     324             :                                                                                        NodeInputManager::CompFluidStream::Primary,
     325          63 :                                                                                        ObjectIsParent);
     326             : 
     327          63 :             state.dataUnitHeaters->UnitHeat(UnitHeatNum).AirOutNode = GetOnlySingleNode(state,
     328          63 :                                                                                         Alphas(4),
     329             :                                                                                         ErrorsFound,
     330             :                                                                                         DataLoopNode::ConnectionObjectType::ZoneHVACUnitHeater,
     331          63 :                                                                                         Alphas(1),
     332             :                                                                                         DataLoopNode::NodeFluidType::Air,
     333             :                                                                                         DataLoopNode::ConnectionType::Outlet,
     334             :                                                                                         NodeInputManager::CompFluidStream::Primary,
     335          63 :                                                                                         ObjectIsParent);
     336             : 
     337             :             // Fan information:
     338          63 :             state.dataUnitHeaters->UnitHeat(UnitHeatNum).FanType = Alphas(5);
     339          63 :             state.dataUnitHeaters->UnitHeat(UnitHeatNum).FanName = Alphas(6);
     340          63 :             state.dataUnitHeaters->UnitHeat(UnitHeatNum).MaxAirVolFlow = Numbers(1);
     341             : 
     342          63 :             errFlag = false;
     343         126 :             ValidateComponent(state,
     344          63 :                               state.dataUnitHeaters->UnitHeat(UnitHeatNum).FanType,
     345          63 :                               state.dataUnitHeaters->UnitHeat(UnitHeatNum).FanName,
     346             :                               errFlag,
     347             :                               CurrentModuleObject);
     348          63 :             if (errFlag) {
     349           0 :                 ShowContinueError(state, "specified in " + CurrentModuleObject + " = \"" + state.dataUnitHeaters->UnitHeat(UnitHeatNum).Name + "\".");
     350           0 :                 ErrorsFound = true;
     351             :             } else {
     352          63 :                 if (!UtilityRoutines::SameString(state.dataUnitHeaters->UnitHeat(UnitHeatNum).FanType, "Fan:SystemModel")) {
     353         180 :                     GetFanType(state,
     354          60 :                                state.dataUnitHeaters->UnitHeat(UnitHeatNum).FanName,
     355          60 :                                state.dataUnitHeaters->UnitHeat(UnitHeatNum).FanType_Num,
     356             :                                errFlag,
     357             :                                CurrentModuleObject,
     358          60 :                                state.dataUnitHeaters->UnitHeat(UnitHeatNum).Name);
     359             : 
     360             :                     {
     361          60 :                         switch (state.dataUnitHeaters->UnitHeat(UnitHeatNum).FanType_Num) {
     362          60 :                         case FanType_SimpleConstVolume:
     363             :                         case FanType_SimpleVAV:
     364             :                         case FanType_SimpleOnOff:
     365             :                             // Get fan outlet node
     366          60 :                             state.dataUnitHeaters->UnitHeat(UnitHeatNum).FanOutletNode =
     367         120 :                                 GetFanOutletNode(state,
     368          60 :                                                  state.dataUnitHeaters->UnitHeat(UnitHeatNum).FanType,
     369          60 :                                                  state.dataUnitHeaters->UnitHeat(UnitHeatNum).FanName,
     370             :                                                  errFlag);
     371          60 :                             if (errFlag) {
     372           0 :                                 ShowContinueError(state,
     373           0 :                                                   "specified in " + CurrentModuleObject + " = \"" +
     374           0 :                                                       state.dataUnitHeaters->UnitHeat(UnitHeatNum).Name + "\".");
     375           0 :                                 ErrorsFound = true;
     376             :                             }
     377          60 :                             break;
     378           0 :                         default:
     379           0 :                             ShowSevereError(state, std::string{RoutineName} + CurrentModuleObject + " = \"" + Alphas(1) + "\"");
     380           0 :                             ShowContinueError(state, "Fan Type must be Fan:ConstantVolume or Fan:VariableVolume");
     381           0 :                             ErrorsFound = true;
     382             :                         }
     383             :                     }
     384         180 :                     GetFanIndex(state,
     385          60 :                                 state.dataUnitHeaters->UnitHeat(UnitHeatNum).FanName,
     386          60 :                                 state.dataUnitHeaters->UnitHeat(UnitHeatNum).Fan_Index,
     387             :                                 errFlag,
     388             :                                 CurrentModuleObject);
     389          60 :                     if (errFlag) {
     390           0 :                         ErrorsFound = true;
     391             :                     } else {
     392          60 :                         GetFanVolFlow(state, state.dataUnitHeaters->UnitHeat(UnitHeatNum).Fan_Index, FanVolFlow);
     393             : 
     394          70 :                         if (FanVolFlow != AutoSize && state.dataUnitHeaters->UnitHeat(UnitHeatNum).MaxAirVolFlow != AutoSize &&
     395          10 :                             FanVolFlow < state.dataUnitHeaters->UnitHeat(UnitHeatNum).MaxAirVolFlow) {
     396           0 :                             ShowSevereError(state, "Specified in " + CurrentModuleObject + " = " + state.dataUnitHeaters->UnitHeat(UnitHeatNum).Name);
     397           0 :                             ShowContinueError(
     398             :                                 state,
     399           0 :                                 format(
     400             :                                     "...air flow rate ({:.7T}) in fan object {} is less than the unit heater maximum supply air flow rate ({:.7T}).",
     401             :                                     FanVolFlow,
     402           0 :                                     state.dataUnitHeaters->UnitHeat(UnitHeatNum).FanName,
     403           0 :                                     state.dataUnitHeaters->UnitHeat(UnitHeatNum).MaxAirVolFlow));
     404           0 :                             ShowContinueError(state,
     405             :                                               "...the fan flow rate must be greater than or equal to the unit heater maximum supply air flow rate.");
     406           0 :                             ErrorsFound = true;
     407          60 :                         } else if (FanVolFlow == AutoSize && state.dataUnitHeaters->UnitHeat(UnitHeatNum).MaxAirVolFlow != AutoSize) {
     408           0 :                             ShowWarningError(state,
     409           0 :                                              "Specified in " + CurrentModuleObject + " = " + state.dataUnitHeaters->UnitHeat(UnitHeatNum).Name);
     410           0 :                             ShowContinueError(state, "...the fan flow rate is autosized while the unit heater flow rate is not.");
     411           0 :                             ShowContinueError(state, "...this can lead to unexpected results where the fan flow rate is less than required.");
     412          60 :                         } else if (FanVolFlow != AutoSize && state.dataUnitHeaters->UnitHeat(UnitHeatNum).MaxAirVolFlow == AutoSize) {
     413           0 :                             ShowWarningError(state,
     414           0 :                                              "Specified in " + CurrentModuleObject + " = " + state.dataUnitHeaters->UnitHeat(UnitHeatNum).Name);
     415           0 :                             ShowContinueError(state, "...the unit heater flow rate is autosized while the fan flow rate is not.");
     416           0 :                             ShowContinueError(state, "...this can lead to unexpected results where the fan flow rate is less than required.");
     417             :                         }
     418          60 :                         state.dataUnitHeaters->UnitHeat(UnitHeatNum).FanAvailSchedPtr =
     419         120 :                             GetFanAvailSchPtr(state,
     420          60 :                                               state.dataUnitHeaters->UnitHeat(UnitHeatNum).FanType,
     421          60 :                                               state.dataUnitHeaters->UnitHeat(UnitHeatNum).FanName,
     422             :                                               errFlag);
     423             :                     }
     424           3 :                 } else if (UtilityRoutines::SameString(state.dataUnitHeaters->UnitHeat(UnitHeatNum).FanType, "Fan:SystemModel")) {
     425           3 :                     state.dataUnitHeaters->UnitHeat(UnitHeatNum).FanType_Num = DataHVACGlobals::FanType_SystemModelObject;
     426           6 :                     state.dataHVACFan->fanObjs.emplace_back(
     427           6 :                         new HVACFan::FanSystem(state, state.dataUnitHeaters->UnitHeat(UnitHeatNum).FanName)); // call constructor
     428           3 :                     state.dataUnitHeaters->UnitHeat(UnitHeatNum).Fan_Index =
     429           3 :                         HVACFan::getFanObjectVectorIndex(state, state.dataUnitHeaters->UnitHeat(UnitHeatNum).FanName); // zero-based
     430           3 :                     state.dataUnitHeaters->UnitHeat(UnitHeatNum).FanOutletNode =
     431           3 :                         state.dataHVACFan->fanObjs[state.dataUnitHeaters->UnitHeat(UnitHeatNum).Fan_Index]->outletNodeNum;
     432           3 :                     FanVolFlow = state.dataHVACFan->fanObjs[state.dataUnitHeaters->UnitHeat(UnitHeatNum).Fan_Index]->designAirVolFlowRate;
     433           3 :                     if (FanVolFlow != AutoSize && state.dataUnitHeaters->UnitHeat(UnitHeatNum).MaxAirVolFlow != AutoSize &&
     434           0 :                         FanVolFlow < state.dataUnitHeaters->UnitHeat(UnitHeatNum).MaxAirVolFlow) {
     435           0 :                         ShowSevereError(state, "Specified in " + CurrentModuleObject + " = " + state.dataUnitHeaters->UnitHeat(UnitHeatNum).Name);
     436           0 :                         ShowContinueError(
     437             :                             state,
     438           0 :                             format("...air flow rate ({:.7T}) in fan object {} is less than the unit heater maximum supply air flow rate ({:.7T}).",
     439             :                                    FanVolFlow,
     440           0 :                                    state.dataUnitHeaters->UnitHeat(UnitHeatNum).FanName,
     441           0 :                                    state.dataUnitHeaters->UnitHeat(UnitHeatNum).MaxAirVolFlow));
     442           0 :                         ShowContinueError(state,
     443             :                                           "...the fan flow rate must be greater than or equal to the unit heater maximum supply air flow rate.");
     444           0 :                         ErrorsFound = true;
     445           3 :                     } else if (FanVolFlow == AutoSize && state.dataUnitHeaters->UnitHeat(UnitHeatNum).MaxAirVolFlow != AutoSize) {
     446           0 :                         ShowWarningError(state, "Specified in " + CurrentModuleObject + " = " + state.dataUnitHeaters->UnitHeat(UnitHeatNum).Name);
     447           0 :                         ShowContinueError(state, "...the fan flow rate is autosized while the unit heater flow rate is not.");
     448           0 :                         ShowContinueError(state, "...this can lead to unexpected results where the fan flow rate is less than required.");
     449           3 :                     } else if (FanVolFlow != AutoSize && state.dataUnitHeaters->UnitHeat(UnitHeatNum).MaxAirVolFlow == AutoSize) {
     450           0 :                         ShowWarningError(state, "Specified in " + CurrentModuleObject + " = " + state.dataUnitHeaters->UnitHeat(UnitHeatNum).Name);
     451           0 :                         ShowContinueError(state, "...the unit heater flow rate is autosized while the fan flow rate is not.");
     452           0 :                         ShowContinueError(state, "...this can lead to unexpected results where the fan flow rate is less than required.");
     453             :                     }
     454             : 
     455           3 :                     state.dataUnitHeaters->UnitHeat(UnitHeatNum).FanAvailSchedPtr =
     456           3 :                         state.dataHVACFan->fanObjs[state.dataUnitHeaters->UnitHeat(UnitHeatNum).Fan_Index]->availSchedIndex;
     457             :                 }
     458             :             }
     459             : 
     460             :             // Heating coil information:
     461             :             {
     462          63 :                 state.dataUnitHeaters->UnitHeat(UnitHeatNum).Type =
     463         126 :                     static_cast<HCoilType>(getEnumerationValue(HCoilTypeNamesUC, UtilityRoutines::MakeUPPERCase(Alphas(7))));
     464          63 :                 switch (state.dataUnitHeaters->UnitHeat(UnitHeatNum).Type) {
     465           6 :                 case HCoilType::WaterHeatingCoil:
     466           6 :                     state.dataUnitHeaters->UnitHeat(UnitHeatNum).HeatingCoilType = DataPlant::PlantEquipmentType::CoilWaterSimpleHeating;
     467           6 :                     break;
     468           0 :                 case HCoilType::SteamCoil:
     469           0 :                     state.dataUnitHeaters->UnitHeat(UnitHeatNum).HeatingCoilType = DataPlant::PlantEquipmentType::CoilSteamAirHeating;
     470           0 :                     break;
     471          57 :                 case HCoilType::Electric:
     472             :                 case HCoilType::Gas:
     473          57 :                     break;
     474           0 :                 default: {
     475           0 :                     ShowSevereError(state, "Illegal " + cAlphaFields(7) + " = " + Alphas(7));
     476           0 :                     ShowContinueError(state, "Occurs in " + CurrentModuleObject + '=' + state.dataUnitHeaters->UnitHeat(UnitHeatNum).Name);
     477           0 :                     ErrorsFound = true;
     478           0 :                     errFlag = true;
     479             :                 }
     480             :                 }
     481             :             }
     482          63 :             if (!errFlag) {
     483          63 :                 state.dataUnitHeaters->UnitHeat(UnitHeatNum).HCoilTypeCh = Alphas(7);
     484          63 :                 state.dataUnitHeaters->UnitHeat(UnitHeatNum).HCoilName = Alphas(8);
     485          63 :                 ValidateComponent(state, Alphas(7), state.dataUnitHeaters->UnitHeat(UnitHeatNum).HCoilName, IsNotOK, CurrentModuleObject);
     486          63 :                 if (IsNotOK) {
     487           0 :                     ShowContinueError(state,
     488           0 :                                       "specified in " + CurrentModuleObject + " = \"" + state.dataUnitHeaters->UnitHeat(UnitHeatNum).Name + "\"");
     489           0 :                     ErrorsFound = true;
     490             :                 } else {
     491             :                     // The heating coil control node is necessary for hot water and steam coils, but not necessary for an
     492             :                     // electric or gas coil.
     493         120 :                     if (state.dataUnitHeaters->UnitHeat(UnitHeatNum).Type == HCoilType::WaterHeatingCoil ||
     494          57 :                         state.dataUnitHeaters->UnitHeat(UnitHeatNum).Type == HCoilType::SteamCoil) {
     495             :                         // mine the hot water or steam node from the coil object
     496           6 :                         errFlag = false;
     497           6 :                         if (state.dataUnitHeaters->UnitHeat(UnitHeatNum).Type == HCoilType::WaterHeatingCoil) {
     498           6 :                             state.dataUnitHeaters->UnitHeat(UnitHeatNum).HotControlNode =
     499          12 :                                 GetCoilWaterInletNode(state, "Coil:Heating:Water", state.dataUnitHeaters->UnitHeat(UnitHeatNum).HCoilName, errFlag);
     500             :                         } else { // its a steam coil
     501           0 :                             state.dataUnitHeaters->UnitHeat(UnitHeatNum).HCoil_Index =
     502           0 :                                 GetSteamCoilIndex(state, "COIL:HEATING:STEAM", state.dataUnitHeaters->UnitHeat(UnitHeatNum).HCoilName, errFlag);
     503           0 :                             state.dataUnitHeaters->UnitHeat(UnitHeatNum).HotControlNode =
     504           0 :                                 GetCoilSteamInletNode(state,
     505           0 :                                                       state.dataUnitHeaters->UnitHeat(UnitHeatNum).HCoil_Index,
     506           0 :                                                       state.dataUnitHeaters->UnitHeat(UnitHeatNum).HCoilName,
     507             :                                                       errFlag);
     508             :                         }
     509             :                         // Other error checks should trap before it gets to this point in the code, but including just in case.
     510           6 :                         if (errFlag) {
     511           0 :                             ShowContinueError(state,
     512           0 :                                               "that was specified in " + CurrentModuleObject + " = \"" +
     513           0 :                                                   state.dataUnitHeaters->UnitHeat(UnitHeatNum).Name + "\"");
     514           0 :                             ErrorsFound = true;
     515             :                         }
     516             :                     }
     517             :                 }
     518             :             }
     519             : 
     520          63 :             state.dataUnitHeaters->UnitHeat(UnitHeatNum).FanSchedPtr = GetScheduleIndex(state, Alphas(9));
     521             :             // Default to cycling fan when fan operating mode schedule is not present
     522          63 :             if (!lAlphaBlanks(9) && state.dataUnitHeaters->UnitHeat(UnitHeatNum).FanSchedPtr == 0) {
     523           0 :                 ShowSevereError(state,
     524           0 :                                 CurrentModuleObject + " \"" + state.dataUnitHeaters->UnitHeat(UnitHeatNum).Name + "\" " + cAlphaFields(9) +
     525           0 :                                     " not found: " + Alphas(9));
     526           0 :                 ErrorsFound = true;
     527          63 :             } else if (lAlphaBlanks(9)) {
     528         120 :                 if (state.dataUnitHeaters->UnitHeat(UnitHeatNum).FanType_Num == FanType_SimpleOnOff ||
     529          60 :                     state.dataUnitHeaters->UnitHeat(UnitHeatNum).FanType_Num == DataHVACGlobals::FanType_SystemModelObject) {
     530           0 :                     state.dataUnitHeaters->UnitHeat(UnitHeatNum).OpMode = CycFanCycCoil;
     531             :                 } else {
     532          60 :                     state.dataUnitHeaters->UnitHeat(UnitHeatNum).OpMode = ContFanCycCoil;
     533             :                 }
     534             :             }
     535             : 
     536             :             // Check fan's schedule for cycling fan operation if constant volume fan is used
     537          66 :             if (state.dataUnitHeaters->UnitHeat(UnitHeatNum).FanSchedPtr > 0 &&
     538           3 :                 state.dataUnitHeaters->UnitHeat(UnitHeatNum).FanType_Num == FanType_SimpleConstVolume) {
     539           0 :                 if (!CheckScheduleValueMinMax(state, state.dataUnitHeaters->UnitHeat(UnitHeatNum).FanSchedPtr, ">", 0.0, "<=", 1.0)) {
     540           0 :                     ShowSevereError(state, CurrentModuleObject + " = " + Alphas(1));
     541           0 :                     ShowContinueError(state, "For " + cAlphaFields(5) + " = " + Alphas(5));
     542           0 :                     ShowContinueError(state, "Fan operating mode must be continuous (fan operating mode schedule values > 0).");
     543           0 :                     ShowContinueError(state, "Error found in " + cAlphaFields(9) + " = " + Alphas(9));
     544           0 :                     ShowContinueError(state, "...schedule values must be (>0., <=1.)");
     545           0 :                     ErrorsFound = true;
     546             :                 }
     547             :             }
     548             : 
     549          63 :             state.dataUnitHeaters->UnitHeat(UnitHeatNum).FanOperatesDuringNoHeating = Alphas(10);
     550         170 :             if ((!UtilityRoutines::SameString(state.dataUnitHeaters->UnitHeat(UnitHeatNum).FanOperatesDuringNoHeating, "Yes")) &&
     551         107 :                 (!UtilityRoutines::SameString(state.dataUnitHeaters->UnitHeat(UnitHeatNum).FanOperatesDuringNoHeating, "No"))) {
     552           0 :                 ErrorsFound = true;
     553           0 :                 ShowSevereError(state, "Illegal " + cAlphaFields(10) + " = " + Alphas(10));
     554           0 :                 ShowContinueError(state, "Occurs in " + CurrentModuleObject + '=' + state.dataUnitHeaters->UnitHeat(UnitHeatNum).Name);
     555          63 :             } else if (UtilityRoutines::SameString(state.dataUnitHeaters->UnitHeat(UnitHeatNum).FanOperatesDuringNoHeating, "No")) {
     556          44 :                 state.dataUnitHeaters->UnitHeat(UnitHeatNum).FanOffNoHeating = true;
     557             :             }
     558             : 
     559          63 :             state.dataUnitHeaters->UnitHeat(UnitHeatNum).MaxVolHotWaterFlow = Numbers(2);
     560          63 :             state.dataUnitHeaters->UnitHeat(UnitHeatNum).MinVolHotWaterFlow = Numbers(3);
     561          63 :             state.dataUnitHeaters->UnitHeat(UnitHeatNum).MaxVolHotSteamFlow = Numbers(2);
     562          63 :             state.dataUnitHeaters->UnitHeat(UnitHeatNum).MinVolHotSteamFlow = Numbers(3);
     563             : 
     564          63 :             state.dataUnitHeaters->UnitHeat(UnitHeatNum).HotControlOffset = Numbers(4);
     565             :             // Set default convergence tolerance
     566          63 :             if (state.dataUnitHeaters->UnitHeat(UnitHeatNum).HotControlOffset <= 0.0) {
     567           3 :                 state.dataUnitHeaters->UnitHeat(UnitHeatNum).HotControlOffset = 0.001;
     568             :             }
     569             : 
     570          63 :             if (!lAlphaBlanks(11)) {
     571           0 :                 state.dataUnitHeaters->UnitHeat(UnitHeatNum).AvailManagerListName = Alphas(11);
     572             :             }
     573             : 
     574          63 :             state.dataUnitHeaters->UnitHeat(UnitHeatNum).HVACSizingIndex = 0;
     575          63 :             if (!lAlphaBlanks(12)) {
     576           0 :                 state.dataUnitHeaters->UnitHeat(UnitHeatNum).HVACSizingIndex =
     577           0 :                     UtilityRoutines::FindItemInList(Alphas(12), state.dataSize->ZoneHVACSizing);
     578           0 :                 if (state.dataUnitHeaters->UnitHeat(UnitHeatNum).HVACSizingIndex == 0) {
     579           0 :                     ShowSevereError(state, cAlphaFields(12) + " = " + Alphas(12) + " not found.");
     580           0 :                     ShowContinueError(state, "Occurs in " + CurrentModuleObject + " = " + state.dataUnitHeaters->UnitHeat(UnitHeatNum).Name);
     581           0 :                     ErrorsFound = true;
     582             :                 }
     583             :             }
     584             : 
     585             :             // check that unit heater air inlet node must be the same as a zone exhaust node
     586          63 :             ZoneNodeNotFound = true;
     587        3017 :             for (CtrlZone = 1; CtrlZone <= state.dataGlobal->NumOfZones; ++CtrlZone) {
     588        2954 :                 if (!state.dataZoneEquip->ZoneEquipConfig(CtrlZone).IsControlled) continue;
     589        4780 :                 for (NodeNum = 1; NodeNum <= state.dataZoneEquip->ZoneEquipConfig(CtrlZone).NumExhaustNodes; ++NodeNum) {
     590        4268 :                     if (state.dataUnitHeaters->UnitHeat(UnitHeatNum).AirInNode ==
     591        2134 :                         state.dataZoneEquip->ZoneEquipConfig(CtrlZone).ExhaustNode(NodeNum)) {
     592          63 :                         ZoneNodeNotFound = false;
     593          63 :                         break;
     594             :                     }
     595             :                 }
     596             :             }
     597          63 :             if (ZoneNodeNotFound) {
     598           0 :                 ShowSevereError(state,
     599           0 :                                 CurrentModuleObject + " = \"" + state.dataUnitHeaters->UnitHeat(UnitHeatNum).Name +
     600             :                                     "\". Unit heater air inlet node name must be the same as a zone exhaust node name.");
     601           0 :                 ShowContinueError(state, "..Zone exhaust node name is specified in ZoneHVAC:EquipmentConnections object.");
     602           0 :                 ShowContinueError(state,
     603           0 :                                   "..Unit heater air inlet node name = " +
     604           0 :                                       state.dataLoopNodes->NodeID(state.dataUnitHeaters->UnitHeat(UnitHeatNum).AirInNode));
     605           0 :                 ErrorsFound = true;
     606             :             }
     607             :             // check that unit heater air outlet node is a zone inlet node.
     608          63 :             ZoneNodeNotFound = true;
     609        3017 :             for (CtrlZone = 1; CtrlZone <= state.dataGlobal->NumOfZones; ++CtrlZone) {
     610        2954 :                 if (!state.dataZoneEquip->ZoneEquipConfig(CtrlZone).IsControlled) continue;
     611        5341 :                 for (NodeNum = 1; NodeNum <= state.dataZoneEquip->ZoneEquipConfig(CtrlZone).NumInletNodes; ++NodeNum) {
     612        5390 :                     if (state.dataUnitHeaters->UnitHeat(UnitHeatNum).AirOutNode ==
     613        2695 :                         state.dataZoneEquip->ZoneEquipConfig(CtrlZone).InletNode(NodeNum)) {
     614          63 :                         state.dataUnitHeaters->UnitHeat(UnitHeatNum).ZonePtr = CtrlZone;
     615          63 :                         ZoneNodeNotFound = false;
     616          63 :                         break;
     617             :                     }
     618             :                 }
     619             :             }
     620          63 :             if (ZoneNodeNotFound) {
     621           0 :                 ShowSevereError(state,
     622           0 :                                 CurrentModuleObject + " = \"" + state.dataUnitHeaters->UnitHeat(UnitHeatNum).Name +
     623             :                                     "\". Unit heater air outlet node name must be the same as a zone inlet node name.");
     624           0 :                 ShowContinueError(state, "..Zone inlet node name is specified in ZoneHVAC:EquipmentConnections object.");
     625           0 :                 ShowContinueError(state,
     626           0 :                                   "..Unit heater air outlet node name = " +
     627           0 :                                       state.dataLoopNodes->NodeID(state.dataUnitHeaters->UnitHeat(UnitHeatNum).AirOutNode));
     628           0 :                 ErrorsFound = true;
     629             :             }
     630             : 
     631             :             // Add fan to component sets array
     632         315 :             SetUpCompSets(state,
     633             :                           CurrentModuleObject,
     634          63 :                           state.dataUnitHeaters->UnitHeat(UnitHeatNum).Name,
     635          63 :                           state.dataUnitHeaters->UnitHeat(UnitHeatNum).FanType,
     636          63 :                           state.dataUnitHeaters->UnitHeat(UnitHeatNum).FanName,
     637          63 :                           state.dataLoopNodes->NodeID(state.dataUnitHeaters->UnitHeat(UnitHeatNum).AirInNode),
     638          63 :                           state.dataLoopNodes->NodeID(state.dataUnitHeaters->UnitHeat(UnitHeatNum).FanOutletNode));
     639             : 
     640             :             // Add heating coil to component sets array
     641         315 :             SetUpCompSets(state,
     642             :                           CurrentModuleObject,
     643          63 :                           state.dataUnitHeaters->UnitHeat(UnitHeatNum).Name,
     644          63 :                           state.dataUnitHeaters->UnitHeat(UnitHeatNum).HCoilTypeCh,
     645          63 :                           state.dataUnitHeaters->UnitHeat(UnitHeatNum).HCoilName,
     646          63 :                           state.dataLoopNodes->NodeID(state.dataUnitHeaters->UnitHeat(UnitHeatNum).FanOutletNode),
     647          63 :                           state.dataLoopNodes->NodeID(state.dataUnitHeaters->UnitHeat(UnitHeatNum).AirOutNode));
     648             : 
     649             :         } // ...loop over all of the unit heaters found in the input file
     650             : 
     651          14 :         Alphas.deallocate();
     652          14 :         Numbers.deallocate();
     653          14 :         cAlphaFields.deallocate();
     654          14 :         cNumericFields.deallocate();
     655          14 :         lAlphaBlanks.deallocate();
     656          14 :         lNumericBlanks.deallocate();
     657             : 
     658          14 :         if (ErrorsFound) ShowFatalError(state, std::string{RoutineName} + "Errors found in input");
     659             : 
     660             :         // Setup Report variables for the Unit Heaters, CurrentModuleObject='ZoneHVAC:UnitHeater'
     661          77 :         for (UnitHeatNum = 1; UnitHeatNum <= state.dataUnitHeaters->NumOfUnitHeats; ++UnitHeatNum) {
     662         252 :             SetupOutputVariable(state,
     663             :                                 "Zone Unit Heater Heating Rate",
     664             :                                 OutputProcessor::Unit::W,
     665          63 :                                 state.dataUnitHeaters->UnitHeat(UnitHeatNum).HeatPower,
     666             :                                 OutputProcessor::SOVTimeStepType::System,
     667             :                                 OutputProcessor::SOVStoreType::Average,
     668         126 :                                 state.dataUnitHeaters->UnitHeat(UnitHeatNum).Name);
     669         252 :             SetupOutputVariable(state,
     670             :                                 "Zone Unit Heater Heating Energy",
     671             :                                 OutputProcessor::Unit::J,
     672          63 :                                 state.dataUnitHeaters->UnitHeat(UnitHeatNum).HeatEnergy,
     673             :                                 OutputProcessor::SOVTimeStepType::System,
     674             :                                 OutputProcessor::SOVStoreType::Summed,
     675         126 :                                 state.dataUnitHeaters->UnitHeat(UnitHeatNum).Name);
     676         252 :             SetupOutputVariable(state,
     677             :                                 "Zone Unit Heater Fan Electricity Rate",
     678             :                                 OutputProcessor::Unit::W,
     679          63 :                                 state.dataUnitHeaters->UnitHeat(UnitHeatNum).ElecPower,
     680             :                                 OutputProcessor::SOVTimeStepType::System,
     681             :                                 OutputProcessor::SOVStoreType::Average,
     682         126 :                                 state.dataUnitHeaters->UnitHeat(UnitHeatNum).Name);
     683             :             // Note that the unit heater fan electric is NOT metered because this value is already metered through the fan component
     684         252 :             SetupOutputVariable(state,
     685             :                                 "Zone Unit Heater Fan Electricity Energy",
     686             :                                 OutputProcessor::Unit::J,
     687          63 :                                 state.dataUnitHeaters->UnitHeat(UnitHeatNum).ElecEnergy,
     688             :                                 OutputProcessor::SOVTimeStepType::System,
     689             :                                 OutputProcessor::SOVStoreType::Summed,
     690         126 :                                 state.dataUnitHeaters->UnitHeat(UnitHeatNum).Name);
     691         252 :             SetupOutputVariable(state,
     692             :                                 "Zone Unit Heater Fan Availability Status",
     693             :                                 OutputProcessor::Unit::None,
     694          63 :                                 state.dataUnitHeaters->UnitHeat(UnitHeatNum).AvailStatus,
     695             :                                 OutputProcessor::SOVTimeStepType::System,
     696             :                                 OutputProcessor::SOVStoreType::Average,
     697         126 :                                 state.dataUnitHeaters->UnitHeat(UnitHeatNum).Name);
     698          63 :             if (state.dataUnitHeaters->UnitHeat(UnitHeatNum).FanType_Num == FanType_SimpleOnOff) {
     699           0 :                 SetupOutputVariable(state,
     700             :                                     "Zone Unit Heater Fan Part Load Ratio",
     701             :                                     OutputProcessor::Unit::None,
     702           0 :                                     state.dataUnitHeaters->UnitHeat(UnitHeatNum).FanPartLoadRatio,
     703             :                                     OutputProcessor::SOVTimeStepType::System,
     704             :                                     OutputProcessor::SOVStoreType::Average,
     705           0 :                                     state.dataUnitHeaters->UnitHeat(UnitHeatNum).Name);
     706             :             }
     707             :         }
     708             : 
     709          77 :         for (UnitHeatNum = 1; UnitHeatNum <= state.dataUnitHeaters->NumOfUnitHeats; ++UnitHeatNum) {
     710          63 :             if (state.dataUnitHeaters->UnitHeat(UnitHeatNum).FanType_Num == DataHVACGlobals::FanType_SystemModelObject) {
     711          15 :                 state.dataRptCoilSelection->coilSelectionReportObj->setCoilSupplyFanInfo(state,
     712           3 :                                                                                          state.dataUnitHeaters->UnitHeat(UnitHeatNum).HCoilName,
     713           3 :                                                                                          state.dataUnitHeaters->UnitHeat(UnitHeatNum).HCoilTypeCh,
     714           3 :                                                                                          state.dataUnitHeaters->UnitHeat(UnitHeatNum).FanName,
     715             :                                                                                          DataAirSystems::ObjectVectorOOFanSystemModel,
     716           3 :                                                                                          state.dataUnitHeaters->UnitHeat(UnitHeatNum).Fan_Index);
     717             :             } else {
     718         300 :                 state.dataRptCoilSelection->coilSelectionReportObj->setCoilSupplyFanInfo(state,
     719          60 :                                                                                          state.dataUnitHeaters->UnitHeat(UnitHeatNum).HCoilName,
     720          60 :                                                                                          state.dataUnitHeaters->UnitHeat(UnitHeatNum).HCoilTypeCh,
     721          60 :                                                                                          state.dataUnitHeaters->UnitHeat(UnitHeatNum).FanName,
     722             :                                                                                          DataAirSystems::StructArrayLegacyFanModels,
     723          60 :                                                                                          state.dataUnitHeaters->UnitHeat(UnitHeatNum).Fan_Index);
     724             :             }
     725             :         }
     726          14 :     }
     727             : 
     728      638739 :     void InitUnitHeater(EnergyPlusData &state,
     729             :                         int const UnitHeatNum,                         // index for the current unit heater
     730             :                         int const ZoneNum,                             // number of zone being served
     731             :                         [[maybe_unused]] bool const FirstHVACIteration // TRUE if 1st HVAC simulation of system timestep
     732             :     )
     733             :     {
     734             : 
     735             :         // SUBROUTINE INFORMATION:
     736             :         //       AUTHOR         Rick Strand
     737             :         //       DATE WRITTEN   May 2000
     738             :         //       MODIFIED       Chandan Sharma, FSEC, March 2011: Added ZoneHVAC sys avail manager
     739             :         //       RE-ENGINEERED  na
     740             : 
     741             :         // PURPOSE OF THIS SUBROUTINE:
     742             :         // This subroutine initializes all of the data elements which are necessary
     743             :         // to simulate a unit heater.
     744             : 
     745             :         // METHODOLOGY EMPLOYED:
     746             :         // Uses the status flags to trigger initializations.
     747             : 
     748             :         // Using/Aliasing
     749             :         using DataHVACGlobals::FanType_SimpleOnOff;
     750      638739 :         auto &ZoneComp = state.dataHVACGlobal->ZoneComp;
     751      638739 :         auto &ZoneCompTurnFansOff = state.dataHVACGlobal->ZoneCompTurnFansOff;
     752      638739 :         auto &ZoneCompTurnFansOn = state.dataHVACGlobal->ZoneCompTurnFansOn;
     753             : 
     754             :         using DataZoneEquipment::CheckZoneEquipmentList;
     755             :         using FluidProperties::GetDensityGlycol;
     756             :         using PlantUtilities::InitComponentNodes;
     757             :         using PlantUtilities::ScanPlantLoopsForObject;
     758             :         using PlantUtilities::SetComponentFlowRate;
     759             :         using namespace DataZoneEnergyDemands;
     760             :         using WaterCoils::SimulateWaterCoilComponents;
     761             : 
     762             :         // SUBROUTINE PARAMETER DEFINITIONS:
     763             :         static constexpr std::string_view RoutineName("InitUnitHeater");
     764             : 
     765             :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     766             :         int Loop;
     767             :         int HotConNode; // hot water control node number in unit heater loop
     768             :         int InNode;     // inlet node number in unit heater loop
     769             :         int OutNode;    // outlet node number in unit heater loop
     770             :         Real64 RhoAir;  // air density at InNode
     771             :         Real64 TempSteamIn;
     772             :         Real64 SteamDensity;
     773             :         Real64 rho; // local fluid density
     774             :         bool errFlag;
     775             : 
     776             :         // Do the one time initializations
     777      638739 :         if (state.dataUnitHeaters->InitUnitHeaterOneTimeFlag) {
     778             : 
     779          14 :             state.dataUnitHeaters->MyEnvrnFlag.allocate(state.dataUnitHeaters->NumOfUnitHeats);
     780          14 :             state.dataUnitHeaters->MySizeFlag.allocate(state.dataUnitHeaters->NumOfUnitHeats);
     781          14 :             state.dataUnitHeaters->MyPlantScanFlag.allocate(state.dataUnitHeaters->NumOfUnitHeats);
     782          14 :             state.dataUnitHeaters->MyZoneEqFlag.allocate(state.dataUnitHeaters->NumOfUnitHeats);
     783          14 :             state.dataUnitHeaters->MyEnvrnFlag = true;
     784          14 :             state.dataUnitHeaters->MySizeFlag = true;
     785          14 :             state.dataUnitHeaters->MyPlantScanFlag = true;
     786          14 :             state.dataUnitHeaters->MyZoneEqFlag = true;
     787          14 :             state.dataUnitHeaters->InitUnitHeaterOneTimeFlag = false;
     788             :         }
     789             : 
     790      638739 :         if (allocated(ZoneComp)) {
     791      638735 :             if (state.dataUnitHeaters->MyZoneEqFlag(UnitHeatNum)) { // initialize the name of each availability manager list and zone number
     792         126 :                 ZoneComp(DataZoneEquipment::ZoneEquip::UnitHeater).ZoneCompAvailMgrs(UnitHeatNum).AvailManagerListName =
     793         126 :                     state.dataUnitHeaters->UnitHeat(UnitHeatNum).AvailManagerListName;
     794          63 :                 ZoneComp(DataZoneEquipment::ZoneEquip::UnitHeater).ZoneCompAvailMgrs(UnitHeatNum).ZoneNum = ZoneNum;
     795          63 :                 state.dataUnitHeaters->MyZoneEqFlag(UnitHeatNum) = false;
     796             :             }
     797      638735 :             state.dataUnitHeaters->UnitHeat(UnitHeatNum).AvailStatus =
     798      638735 :                 ZoneComp(DataZoneEquipment::ZoneEquip::UnitHeater).ZoneCompAvailMgrs(UnitHeatNum).AvailStatus;
     799             :         }
     800             : 
     801      638739 :         if (state.dataUnitHeaters->MyPlantScanFlag(UnitHeatNum) && allocated(state.dataPlnt->PlantLoop)) {
     802         120 :             if ((state.dataUnitHeaters->UnitHeat(UnitHeatNum).HeatingCoilType == DataPlant::PlantEquipmentType::CoilWaterSimpleHeating) ||
     803          57 :                 (state.dataUnitHeaters->UnitHeat(UnitHeatNum).HeatingCoilType == DataPlant::PlantEquipmentType::CoilSteamAirHeating)) {
     804           6 :                 errFlag = false;
     805          24 :                 ScanPlantLoopsForObject(state,
     806           6 :                                         state.dataUnitHeaters->UnitHeat(UnitHeatNum).HCoilName,
     807           6 :                                         state.dataUnitHeaters->UnitHeat(UnitHeatNum).HeatingCoilType,
     808           6 :                                         state.dataUnitHeaters->UnitHeat(UnitHeatNum).HWplantLoc,
     809             :                                         errFlag,
     810             :                                         _,
     811             :                                         _,
     812             :                                         _,
     813             :                                         _,
     814             :                                         _);
     815           6 :                 if (errFlag) {
     816           0 :                     ShowContinueError(state,
     817           0 :                                       "Reference Unit=\"" + state.dataUnitHeaters->UnitHeat(UnitHeatNum).Name + "\", type=ZoneHVAC:UnitHeater");
     818           0 :                     ShowFatalError(state, "InitUnitHeater: Program terminated due to previous condition(s).");
     819             :                 }
     820             : 
     821           6 :                 state.dataUnitHeaters->UnitHeat(UnitHeatNum).HotCoilOutNodeNum =
     822           6 :                     DataPlant::CompData::getPlantComponent(state, state.dataUnitHeaters->UnitHeat(UnitHeatNum).HWplantLoc).NodeNumOut;
     823             :             }
     824          63 :             state.dataUnitHeaters->MyPlantScanFlag(UnitHeatNum) = false;
     825      638676 :         } else if (state.dataUnitHeaters->MyPlantScanFlag(UnitHeatNum) && !state.dataGlobal->AnyPlantInModel) {
     826           0 :             state.dataUnitHeaters->MyPlantScanFlag(UnitHeatNum) = false;
     827             :         }
     828             :         // need to check all units to see if they are on Zone Equipment List or issue warning
     829      638739 :         if (!state.dataUnitHeaters->ZoneEquipmentListChecked && state.dataZoneEquip->ZoneEquipInputsFilled) {
     830          14 :             state.dataUnitHeaters->ZoneEquipmentListChecked = true;
     831          77 :             for (Loop = 1; Loop <= state.dataUnitHeaters->NumOfUnitHeats; ++Loop) {
     832          63 :                 if (CheckZoneEquipmentList(state, "ZoneHVAC:UnitHeater", state.dataUnitHeaters->UnitHeat(Loop).Name)) continue;
     833           0 :                 ShowSevereError(state,
     834           0 :                                 "InitUnitHeater: Unit=[UNIT HEATER," + state.dataUnitHeaters->UnitHeat(Loop).Name +
     835             :                                     "] is not on any ZoneHVAC:EquipmentList.  It will not be simulated.");
     836             :             }
     837             :         }
     838             : 
     839      638802 :         if (!state.dataGlobal->SysSizingCalc && state.dataUnitHeaters->MySizeFlag(UnitHeatNum) &&
     840          63 :             !state.dataUnitHeaters->MyPlantScanFlag(UnitHeatNum)) {
     841             : 
     842          63 :             SizeUnitHeater(state, UnitHeatNum);
     843             : 
     844          63 :             state.dataUnitHeaters->MySizeFlag(UnitHeatNum) = false;
     845             :         } // Do the one time initializations
     846             : 
     847      639080 :         if (state.dataGlobal->BeginEnvrnFlag && state.dataUnitHeaters->MyEnvrnFlag(UnitHeatNum) &&
     848         341 :             !state.dataUnitHeaters->MyPlantScanFlag(UnitHeatNum)) {
     849         341 :             InNode = state.dataUnitHeaters->UnitHeat(UnitHeatNum).AirInNode;
     850         341 :             OutNode = state.dataUnitHeaters->UnitHeat(UnitHeatNum).AirOutNode;
     851         341 :             HotConNode = state.dataUnitHeaters->UnitHeat(UnitHeatNum).HotControlNode;
     852         341 :             RhoAir = state.dataEnvrn->StdRhoAir;
     853             : 
     854             :             // set the mass flow rates from the input volume flow rates
     855         341 :             state.dataUnitHeaters->UnitHeat(UnitHeatNum).MaxAirMassFlow = RhoAir * state.dataUnitHeaters->UnitHeat(UnitHeatNum).MaxAirVolFlow;
     856             : 
     857             :             // set the node max and min mass flow rates
     858         341 :             state.dataLoopNodes->Node(OutNode).MassFlowRateMax = state.dataUnitHeaters->UnitHeat(UnitHeatNum).MaxAirMassFlow;
     859         341 :             state.dataLoopNodes->Node(OutNode).MassFlowRateMin = 0.0;
     860             : 
     861         341 :             state.dataLoopNodes->Node(InNode).MassFlowRateMax = state.dataUnitHeaters->UnitHeat(UnitHeatNum).MaxAirMassFlow;
     862         341 :             state.dataLoopNodes->Node(InNode).MassFlowRateMin = 0.0;
     863             : 
     864         341 :             if (state.dataUnitHeaters->UnitHeat(UnitHeatNum).Type == HCoilType::WaterHeatingCoil) {
     865          60 :                 rho = GetDensityGlycol(state,
     866          30 :                                        state.dataPlnt->PlantLoop(state.dataUnitHeaters->UnitHeat(UnitHeatNum).HWplantLoc.loopNum).FluidName,
     867             :                                        DataGlobalConstants::HWInitConvTemp,
     868          30 :                                        state.dataPlnt->PlantLoop(state.dataUnitHeaters->UnitHeat(UnitHeatNum).HWplantLoc.loopNum).FluidIndex,
     869             :                                        RoutineName);
     870             : 
     871          30 :                 state.dataUnitHeaters->UnitHeat(UnitHeatNum).MaxHotWaterFlow = rho * state.dataUnitHeaters->UnitHeat(UnitHeatNum).MaxVolHotWaterFlow;
     872          30 :                 state.dataUnitHeaters->UnitHeat(UnitHeatNum).MinHotWaterFlow = rho * state.dataUnitHeaters->UnitHeat(UnitHeatNum).MinVolHotWaterFlow;
     873         120 :                 InitComponentNodes(state,
     874          30 :                                    state.dataUnitHeaters->UnitHeat(UnitHeatNum).MinHotWaterFlow,
     875          30 :                                    state.dataUnitHeaters->UnitHeat(UnitHeatNum).MaxHotWaterFlow,
     876          30 :                                    state.dataUnitHeaters->UnitHeat(UnitHeatNum).HotControlNode,
     877          30 :                                    state.dataUnitHeaters->UnitHeat(UnitHeatNum).HotCoilOutNodeNum);
     878             :             }
     879         341 :             if (state.dataUnitHeaters->UnitHeat(UnitHeatNum).Type == HCoilType::SteamCoil) {
     880           0 :                 TempSteamIn = 100.00;
     881           0 :                 SteamDensity = GetSatDensityRefrig(
     882           0 :                     state, fluidNameSteam, TempSteamIn, 1.0, state.dataUnitHeaters->UnitHeat(UnitHeatNum).HCoil_FluidIndex, RoutineName);
     883           0 :                 state.dataUnitHeaters->UnitHeat(UnitHeatNum).MaxHotSteamFlow =
     884           0 :                     SteamDensity * state.dataUnitHeaters->UnitHeat(UnitHeatNum).MaxVolHotSteamFlow;
     885           0 :                 state.dataUnitHeaters->UnitHeat(UnitHeatNum).MinHotSteamFlow =
     886           0 :                     SteamDensity * state.dataUnitHeaters->UnitHeat(UnitHeatNum).MinVolHotSteamFlow;
     887             : 
     888           0 :                 InitComponentNodes(state,
     889           0 :                                    state.dataUnitHeaters->UnitHeat(UnitHeatNum).MinHotSteamFlow,
     890           0 :                                    state.dataUnitHeaters->UnitHeat(UnitHeatNum).MaxHotSteamFlow,
     891           0 :                                    state.dataUnitHeaters->UnitHeat(UnitHeatNum).HotControlNode,
     892           0 :                                    state.dataUnitHeaters->UnitHeat(UnitHeatNum).HotCoilOutNodeNum);
     893             :             }
     894             : 
     895         341 :             state.dataUnitHeaters->MyEnvrnFlag(UnitHeatNum) = false;
     896             :         } // ...end start of environment inits
     897             : 
     898      638739 :         if (!state.dataGlobal->BeginEnvrnFlag) state.dataUnitHeaters->MyEnvrnFlag(UnitHeatNum) = true;
     899             : 
     900             :         // These initializations are done every iteration...
     901      638739 :         InNode = state.dataUnitHeaters->UnitHeat(UnitHeatNum).AirInNode;
     902      638739 :         OutNode = state.dataUnitHeaters->UnitHeat(UnitHeatNum).AirOutNode;
     903             : 
     904      638739 :         state.dataUnitHeaters->QZnReq = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ZoneNum).RemainingOutputReqToHeatSP; // zone load needed
     905      638739 :         if (state.dataUnitHeaters->UnitHeat(UnitHeatNum).FanSchedPtr > 0) {
     906       13320 :             if (GetCurrentScheduleValue(state, state.dataUnitHeaters->UnitHeat(UnitHeatNum).FanSchedPtr) == 0.0 &&
     907           0 :                 state.dataUnitHeaters->UnitHeat(UnitHeatNum).FanType_Num == FanType_SimpleOnOff) {
     908           0 :                 state.dataUnitHeaters->UnitHeat(UnitHeatNum).OpMode = CycFanCycCoil;
     909             :             } else {
     910       13320 :                 state.dataUnitHeaters->UnitHeat(UnitHeatNum).OpMode = ContFanCycCoil;
     911             :             }
     912       13320 :             if ((state.dataUnitHeaters->QZnReq < SmallLoad) || state.dataZoneEnergyDemand->CurDeadBandOrSetback(ZoneNum)) {
     913             :                 // Unit is available, but there is no load on it or we are in setback/deadband
     914       12122 :                 if (!state.dataUnitHeaters->UnitHeat(UnitHeatNum).FanOffNoHeating &&
     915        4846 :                     GetCurrentScheduleValue(state, state.dataUnitHeaters->UnitHeat(UnitHeatNum).FanSchedPtr) > 0.0) {
     916        4846 :                     state.dataUnitHeaters->UnitHeat(UnitHeatNum).OpMode = ContFanCycCoil;
     917             :                 }
     918             :             }
     919             :         }
     920             : 
     921      638739 :         state.dataUnitHeaters->SetMassFlowRateToZero = false;
     922      638739 :         if (GetCurrentScheduleValue(state, state.dataUnitHeaters->UnitHeat(UnitHeatNum).SchedPtr) > 0) {
     923     1178194 :             if ((GetCurrentScheduleValue(state, state.dataUnitHeaters->UnitHeat(UnitHeatNum).FanAvailSchedPtr) > 0 || ZoneCompTurnFansOn) &&
     924      583363 :                 !ZoneCompTurnFansOff) {
     925     1247985 :                 if (state.dataUnitHeaters->UnitHeat(UnitHeatNum).FanOffNoHeating &&
     926      575180 :                     ((state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ZoneNum).RemainingOutputReqToHeatSP < SmallLoad) ||
     927      161988 :                      (state.dataZoneEnergyDemand->CurDeadBandOrSetback(ZoneNum)))) {
     928      251430 :                     state.dataUnitHeaters->SetMassFlowRateToZero = true;
     929             :                 }
     930             :             } else {
     931       11468 :                 state.dataUnitHeaters->SetMassFlowRateToZero = true;
     932             :             }
     933             :         } else {
     934       43908 :             state.dataUnitHeaters->SetMassFlowRateToZero = true;
     935             :         }
     936             : 
     937      638739 :         if (state.dataUnitHeaters->SetMassFlowRateToZero) {
     938      306806 :             state.dataLoopNodes->Node(InNode).MassFlowRate = 0.0;
     939      306806 :             state.dataLoopNodes->Node(InNode).MassFlowRateMaxAvail = 0.0;
     940      306806 :             state.dataLoopNodes->Node(InNode).MassFlowRateMinAvail = 0.0;
     941      306806 :             state.dataLoopNodes->Node(OutNode).MassFlowRate = 0.0;
     942      306806 :             state.dataLoopNodes->Node(OutNode).MassFlowRateMaxAvail = 0.0;
     943      306806 :             state.dataLoopNodes->Node(OutNode).MassFlowRateMinAvail = 0.0;
     944             :         } else {
     945      331933 :             state.dataLoopNodes->Node(InNode).MassFlowRate = state.dataUnitHeaters->UnitHeat(UnitHeatNum).MaxAirMassFlow;
     946      331933 :             state.dataLoopNodes->Node(InNode).MassFlowRateMaxAvail = state.dataUnitHeaters->UnitHeat(UnitHeatNum).MaxAirMassFlow;
     947      331933 :             state.dataLoopNodes->Node(InNode).MassFlowRateMinAvail = state.dataUnitHeaters->UnitHeat(UnitHeatNum).MaxAirMassFlow;
     948      331933 :             state.dataLoopNodes->Node(OutNode).MassFlowRate = state.dataUnitHeaters->UnitHeat(UnitHeatNum).MaxAirMassFlow;
     949      331933 :             state.dataLoopNodes->Node(OutNode).MassFlowRateMaxAvail = state.dataUnitHeaters->UnitHeat(UnitHeatNum).MaxAirMassFlow;
     950      331933 :             state.dataLoopNodes->Node(OutNode).MassFlowRateMinAvail = state.dataUnitHeaters->UnitHeat(UnitHeatNum).MaxAirMassFlow;
     951             :         }
     952             : 
     953             :         // Just in case the unit is off and conditions do not get sent through
     954             :         // the unit for some reason, set the outlet conditions equal to the inlet
     955             :         // conditions of the unit heater
     956      638739 :         state.dataLoopNodes->Node(OutNode).Temp = state.dataLoopNodes->Node(InNode).Temp;
     957      638739 :         state.dataLoopNodes->Node(OutNode).Press = state.dataLoopNodes->Node(InNode).Press;
     958      638739 :         state.dataLoopNodes->Node(OutNode).HumRat = state.dataLoopNodes->Node(InNode).HumRat;
     959      638739 :         state.dataLoopNodes->Node(OutNode).Enthalpy = state.dataLoopNodes->Node(InNode).Enthalpy;
     960      638739 :     }
     961             : 
     962          63 :     void SizeUnitHeater(EnergyPlusData &state, int const UnitHeatNum)
     963             :     {
     964             : 
     965             :         // SUBROUTINE INFORMATION:
     966             :         //       AUTHOR         Fred Buhl
     967             :         //       DATE WRITTEN   February 2002
     968             :         //       MODIFIED       August 2013 Daeho Kang, add component sizing table entries
     969             :         //                      July 2014, B. Nigusse, added scalable sizing
     970             :         //       RE-ENGINEERED  na
     971             : 
     972             :         // PURPOSE OF THIS SUBROUTINE:
     973             :         // This subroutine is for sizing Unit Heater components for which flow rates have not been
     974             :         // specified in the input.
     975             : 
     976             :         // METHODOLOGY EMPLOYED:
     977             :         // Obtains flow rates from the zone sizing arrays and plant sizing data.
     978             : 
     979             :         // Using/Aliasing
     980             :         using namespace DataSizing;
     981             :         using DataHVACGlobals::HeatingAirflowSizing;
     982             :         using DataHVACGlobals::HeatingCapacitySizing;
     983             :         using PlantUtilities::MyPlantSizingIndex;
     984             :         using Psychrometrics::CPHW;
     985             :         using SteamCoils::GetCoilSteamInletNode;
     986             :         using SteamCoils::GetCoilSteamOutletNode;
     987             : 
     988             :         // SUBROUTINE PARAMETER DEFINITIONS:
     989             :         static constexpr std::string_view RoutineName("SizeUnitHeater");
     990             : 
     991             :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     992             :         int PltSizHeatNum; // index of plant sizing object for 1st heating loop
     993             :         bool ErrorsFound;
     994             :         Real64 DesCoilLoad;
     995             :         Real64 TempSteamIn;
     996             :         Real64 EnthSteamInDry;
     997             :         Real64 EnthSteamOutWet;
     998             :         Real64 LatentHeatSteam;
     999             :         Real64 SteamDensity;
    1000          63 :         int CoilWaterInletNode(0);
    1001          63 :         int CoilWaterOutletNode(0);
    1002          63 :         int CoilSteamInletNode(0);
    1003          63 :         int CoilSteamOutletNode(0);
    1004             :         Real64 Cp;                     // local temporary for fluid specific heat
    1005             :         Real64 rho;                    // local temporary for fluid density
    1006             :         bool IsAutoSize;               // Indicator to autosize
    1007             :         Real64 MaxAirVolFlowDes;       // Autosized maximum air flow for reporting
    1008             :         Real64 MaxAirVolFlowUser;      // Hardsized maximum air flow for reporting
    1009             :         Real64 MaxVolHotWaterFlowDes;  // Autosized maximum hot water flow for reporting
    1010             :         Real64 MaxVolHotWaterFlowUser; // Hardsized maximum hot water flow for reporting
    1011             :         Real64 MaxVolHotSteamFlowDes;  // Autosized maximum hot steam flow for reporting
    1012             :         Real64 MaxVolHotSteamFlowUser; // Hardsized maximum hot steam flow for reporting
    1013         126 :         std::string CompName;          // component name
    1014         126 :         std::string CompType;          // component type
    1015         126 :         std::string SizingString;      // input field sizing description (e.g., Nominal Capacity)
    1016             :         Real64 TempSize;               // autosized value of coil input field
    1017          63 :         int FieldNum = 1;              // IDD numeric field number where input field description is found
    1018             :         int SizingMethod;  // Integer representation of sizing method name (e.g., CoolingAirflowSizing, HeatingAirflowSizing, CoolingCapacitySizing,
    1019             :                            // HeatingCapacitySizing, etc.)
    1020             :         bool PrintFlag;    // TRUE when sizing information is reported in the eio file
    1021             :         int zoneHVACIndex; // index of zoneHVAC equipment sizing specification
    1022          63 :         int SAFMethod(0);  // supply air flow rate sizing method (SupplyAirFlowRate, FlowPerFloorArea, FractionOfAutosizedCoolingAirflow,
    1023             :                            // FractionOfAutosizedHeatingAirflow ...)
    1024          63 :         int CapSizingMethod(0); // capacity sizing methods (HeatingDesignCapacity, CapacityPerFloorArea, FractionOfAutosizedCoolingCapacity, and
    1025             :                                 // FractionOfAutosizedHeatingCapacity )
    1026          63 :         bool DoWaterCoilSizing = false; // if TRUE do water coil sizing calculation
    1027             :         Real64 WaterCoilSizDeltaT;      // water coil deltaT for design water flow rate autosizing
    1028             :         int CoilNum;                    // index of water coil object
    1029             : 
    1030          63 :         auto &ZoneEqSizing(state.dataSize->ZoneEqSizing);
    1031          63 :         auto &CurZoneEqNum(state.dataSize->CurZoneEqNum);
    1032             : 
    1033          63 :         PltSizHeatNum = 0;
    1034          63 :         ErrorsFound = false;
    1035          63 :         IsAutoSize = false;
    1036          63 :         MaxAirVolFlowDes = 0.0;
    1037          63 :         MaxAirVolFlowUser = 0.0;
    1038          63 :         MaxVolHotWaterFlowDes = 0.0;
    1039          63 :         MaxVolHotWaterFlowUser = 0.0;
    1040          63 :         MaxVolHotSteamFlowDes = 0.0;
    1041          63 :         MaxVolHotSteamFlowUser = 0.0;
    1042             : 
    1043          63 :         state.dataSize->DataScalableSizingON = false;
    1044          63 :         state.dataSize->DataScalableCapSizingON = false;
    1045          63 :         state.dataSize->ZoneHeatingOnlyFan = true;
    1046          63 :         CompType = "ZoneHVAC:UnitHeater";
    1047          63 :         CompName = state.dataUnitHeaters->UnitHeat(UnitHeatNum).Name;
    1048          63 :         state.dataSize->DataZoneNumber = state.dataUnitHeaters->UnitHeat(UnitHeatNum).ZonePtr;
    1049          63 :         if (state.dataUnitHeaters->UnitHeat(UnitHeatNum).FanType_Num == DataHVACGlobals::FanType_SystemModelObject) {
    1050           3 :             state.dataSize->DataFanEnumType = DataAirSystems::ObjectVectorOOFanSystemModel;
    1051             :         } else {
    1052          60 :             state.dataSize->DataFanEnumType = DataAirSystems::StructArrayLegacyFanModels;
    1053             :         }
    1054          63 :         state.dataSize->DataFanIndex = state.dataUnitHeaters->UnitHeat(UnitHeatNum).Fan_Index;
    1055             :         // unit heater is always blow thru
    1056          63 :         state.dataSize->DataFanPlacement = DataSizing::ZoneFanPlacement::BlowThru;
    1057             : 
    1058          63 :         if (CurZoneEqNum > 0) {
    1059          63 :             if (state.dataUnitHeaters->UnitHeat(UnitHeatNum).HVACSizingIndex > 0) {
    1060           0 :                 zoneHVACIndex = state.dataUnitHeaters->UnitHeat(UnitHeatNum).HVACSizingIndex;
    1061           0 :                 SizingMethod = HeatingAirflowSizing;
    1062           0 :                 FieldNum = 1; //  N1 , \field Maximum Supply Air Flow Rate
    1063           0 :                 PrintFlag = true;
    1064           0 :                 SizingString = state.dataUnitHeaters->UnitHeatNumericFields(UnitHeatNum).FieldNames(FieldNum) + " [m3/s]";
    1065           0 :                 SAFMethod = state.dataSize->ZoneHVACSizing(zoneHVACIndex).HeatingSAFMethod;
    1066           0 :                 ZoneEqSizing(CurZoneEqNum).SizingMethod(SizingMethod) = SAFMethod;
    1067           0 :                 if (SAFMethod == None || SAFMethod == SupplyAirFlowRate || SAFMethod == FlowPerFloorArea ||
    1068             :                     SAFMethod == FractionOfAutosizedHeatingAirflow) {
    1069           0 :                     if (SAFMethod == SupplyAirFlowRate) {
    1070           0 :                         if (state.dataSize->ZoneHVACSizing(zoneHVACIndex).MaxHeatAirVolFlow > 0.0) {
    1071           0 :                             ZoneEqSizing(CurZoneEqNum).AirVolFlow = state.dataSize->ZoneHVACSizing(zoneHVACIndex).MaxHeatAirVolFlow;
    1072           0 :                             ZoneEqSizing(CurZoneEqNum).SystemAirFlow = true;
    1073             :                         }
    1074           0 :                         TempSize = state.dataSize->ZoneHVACSizing(zoneHVACIndex).MaxHeatAirVolFlow;
    1075           0 :                     } else if (SAFMethod == FlowPerFloorArea) {
    1076           0 :                         ZoneEqSizing(CurZoneEqNum).SystemAirFlow = true;
    1077           0 :                         ZoneEqSizing(CurZoneEqNum).AirVolFlow = state.dataSize->ZoneHVACSizing(zoneHVACIndex).MaxHeatAirVolFlow *
    1078           0 :                                                                 state.dataHeatBal->Zone(state.dataSize->DataZoneNumber).FloorArea;
    1079           0 :                         TempSize = ZoneEqSizing(CurZoneEqNum).AirVolFlow;
    1080           0 :                         state.dataSize->DataScalableSizingON = true;
    1081           0 :                     } else if (SAFMethod == FractionOfAutosizedHeatingAirflow) {
    1082           0 :                         state.dataSize->DataFracOfAutosizedCoolingAirflow = state.dataSize->ZoneHVACSizing(zoneHVACIndex).MaxHeatAirVolFlow;
    1083           0 :                         TempSize = AutoSize;
    1084           0 :                         state.dataSize->DataScalableSizingON = true;
    1085             :                     } else {
    1086           0 :                         TempSize = state.dataSize->ZoneHVACSizing(zoneHVACIndex).MaxHeatAirVolFlow;
    1087             :                     }
    1088           0 :                     bool errorsFound = false;
    1089           0 :                     HeatingAirFlowSizer sizingHeatingAirFlow;
    1090           0 :                     sizingHeatingAirFlow.overrideSizingString(SizingString);
    1091             :                     // sizingHeatingAirFlow.setHVACSizingIndexData(FanCoil(FanCoilNum).HVACSizingIndex);
    1092           0 :                     sizingHeatingAirFlow.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
    1093           0 :                     state.dataUnitHeaters->UnitHeat(UnitHeatNum).MaxAirVolFlow = sizingHeatingAirFlow.size(state, TempSize, errorsFound);
    1094             : 
    1095           0 :                 } else if (SAFMethod == FlowPerHeatingCapacity) {
    1096           0 :                     SizingMethod = HeatingCapacitySizing;
    1097           0 :                     TempSize = AutoSize;
    1098           0 :                     PrintFlag = false;
    1099           0 :                     state.dataSize->DataScalableSizingON = true;
    1100           0 :                     state.dataSize->DataFlowUsedForSizing = state.dataSize->FinalZoneSizing(CurZoneEqNum).DesHeatVolFlow;
    1101           0 :                     bool errorsFound = false;
    1102           0 :                     HeatingCapacitySizer sizerHeatingCapacity;
    1103           0 :                     sizerHeatingCapacity.overrideSizingString(SizingString);
    1104           0 :                     sizerHeatingCapacity.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
    1105           0 :                     TempSize = sizerHeatingCapacity.size(state, TempSize, errorsFound);
    1106           0 :                     if (state.dataSize->ZoneHVACSizing(zoneHVACIndex).HeatingCapMethod == FractionOfAutosizedHeatingCapacity) {
    1107           0 :                         state.dataSize->DataFracOfAutosizedHeatingCapacity = state.dataSize->ZoneHVACSizing(zoneHVACIndex).ScaledHeatingCapacity;
    1108             :                     }
    1109           0 :                     state.dataSize->DataAutosizedHeatingCapacity = TempSize;
    1110           0 :                     state.dataSize->DataFlowPerHeatingCapacity = state.dataSize->ZoneHVACSizing(zoneHVACIndex).MaxHeatAirVolFlow;
    1111           0 :                     SizingMethod = HeatingAirflowSizing;
    1112           0 :                     PrintFlag = true;
    1113           0 :                     TempSize = AutoSize;
    1114           0 :                     errorsFound = false;
    1115           0 :                     HeatingAirFlowSizer sizingHeatingAirFlow;
    1116           0 :                     sizingHeatingAirFlow.overrideSizingString(SizingString);
    1117             :                     // sizingHeatingAirFlow.setHVACSizingIndexData(FanCoil(FanCoilNum).HVACSizingIndex);
    1118           0 :                     sizingHeatingAirFlow.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
    1119           0 :                     state.dataUnitHeaters->UnitHeat(UnitHeatNum).MaxAirVolFlow = sizingHeatingAirFlow.size(state, TempSize, errorsFound);
    1120             :                 }
    1121           0 :                 state.dataSize->DataScalableSizingON = false;
    1122             :             } else {
    1123             :                 // no scalble sizing method has been specified. Sizing proceeds using the method
    1124             :                 // specified in the zoneHVAC object
    1125          63 :                 SizingMethod = HeatingAirflowSizing;
    1126          63 :                 FieldNum = 1; // N1 , \field Maximum Supply Air Flow Rate
    1127          63 :                 PrintFlag = true;
    1128          63 :                 SizingString = state.dataUnitHeaters->UnitHeatNumericFields(UnitHeatNum).FieldNames(FieldNum) + " [m3/s]";
    1129          63 :                 TempSize = state.dataUnitHeaters->UnitHeat(UnitHeatNum).MaxAirVolFlow;
    1130          63 :                 bool errorsFound = false;
    1131         126 :                 HeatingAirFlowSizer sizingHeatingAirFlow;
    1132          63 :                 sizingHeatingAirFlow.overrideSizingString(SizingString);
    1133             :                 // sizingHeatingAirFlow.setHVACSizingIndexData(FanCoil(FanCoilNum).HVACSizingIndex);
    1134          63 :                 sizingHeatingAirFlow.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
    1135          63 :                 state.dataUnitHeaters->UnitHeat(UnitHeatNum).MaxAirVolFlow = sizingHeatingAirFlow.size(state, TempSize, errorsFound);
    1136             :             }
    1137             :         }
    1138             : 
    1139          63 :         IsAutoSize = false;
    1140          63 :         if (state.dataUnitHeaters->UnitHeat(UnitHeatNum).MaxVolHotWaterFlow == AutoSize) {
    1141          43 :             IsAutoSize = true;
    1142             :         }
    1143             : 
    1144          63 :         if (state.dataUnitHeaters->UnitHeat(UnitHeatNum).Type == HCoilType::WaterHeatingCoil) {
    1145             : 
    1146           6 :             if (CurZoneEqNum > 0) {
    1147           6 :                 if (!IsAutoSize && !state.dataSize->ZoneSizingRunDone) { // Simulation continue
    1148           3 :                     if (state.dataUnitHeaters->UnitHeat(UnitHeatNum).MaxVolHotWaterFlow > 0.0) {
    1149          12 :                         BaseSizer::reportSizerOutput(state,
    1150             :                                                      "ZoneHVAC:UnitHeater",
    1151           3 :                                                      state.dataUnitHeaters->UnitHeat(UnitHeatNum).Name,
    1152             :                                                      "User-Specified Maximum Hot Water Flow [m3/s]",
    1153           9 :                                                      state.dataUnitHeaters->UnitHeat(UnitHeatNum).MaxVolHotWaterFlow);
    1154             :                     }
    1155             :                 } else {
    1156           3 :                     CheckZoneSizing(state, "ZoneHVAC:UnitHeater", state.dataUnitHeaters->UnitHeat(UnitHeatNum).Name);
    1157             : 
    1158           6 :                     CoilWaterInletNode = WaterCoils::GetCoilWaterInletNode(
    1159           6 :                         state, "Coil:Heating:Water", state.dataUnitHeaters->UnitHeat(UnitHeatNum).HCoilName, ErrorsFound);
    1160           6 :                     CoilWaterOutletNode = WaterCoils::GetCoilWaterOutletNode(
    1161           6 :                         state, "Coil:Heating:Water", state.dataUnitHeaters->UnitHeat(UnitHeatNum).HCoilName, ErrorsFound);
    1162           3 :                     if (IsAutoSize) {
    1163           6 :                         PltSizHeatNum = MyPlantSizingIndex(state,
    1164             :                                                            "Coil:Heating:Water",
    1165           3 :                                                            state.dataUnitHeaters->UnitHeat(UnitHeatNum).HCoilName,
    1166             :                                                            CoilWaterInletNode,
    1167             :                                                            CoilWaterOutletNode,
    1168             :                                                            ErrorsFound);
    1169           6 :                         CoilNum = WaterCoils::GetWaterCoilIndex(
    1170           6 :                             state, "COIL:HEATING:WATER", state.dataUnitHeaters->UnitHeat(UnitHeatNum).HCoilName, ErrorsFound);
    1171           3 :                         if (state.dataWaterCoils->WaterCoil(CoilNum).UseDesignWaterDeltaTemp) {
    1172           0 :                             WaterCoilSizDeltaT = state.dataWaterCoils->WaterCoil(CoilNum).DesignWaterDeltaTemp;
    1173           0 :                             DoWaterCoilSizing = true;
    1174             :                         } else {
    1175           3 :                             if (PltSizHeatNum > 0) {
    1176           3 :                                 WaterCoilSizDeltaT = state.dataSize->PlantSizData(PltSizHeatNum).DeltaT;
    1177           3 :                                 DoWaterCoilSizing = true;
    1178             :                             } else {
    1179           0 :                                 DoWaterCoilSizing = false;
    1180             :                                 // If there is no heating Plant Sizing object and autosizing was requested, issue fatal error message
    1181           0 :                                 ShowSevereError(state, "Autosizing of water coil requires a heating loop Sizing:Plant object");
    1182           0 :                                 ShowContinueError(state, "Occurs in ZoneHVAC:UnitHeater Object=" + state.dataUnitHeaters->UnitHeat(UnitHeatNum).Name);
    1183           0 :                                 ErrorsFound = true;
    1184             :                             }
    1185             :                         }
    1186             : 
    1187           3 :                         if (DoWaterCoilSizing) {
    1188           3 :                             SizingMethod = HeatingCapacitySizing;
    1189           3 :                             if (state.dataUnitHeaters->UnitHeat(UnitHeatNum).HVACSizingIndex > 0) {
    1190           0 :                                 zoneHVACIndex = state.dataUnitHeaters->UnitHeat(UnitHeatNum).HVACSizingIndex;
    1191           0 :                                 CapSizingMethod = state.dataSize->ZoneHVACSizing(zoneHVACIndex).HeatingCapMethod;
    1192           0 :                                 ZoneEqSizing(CurZoneEqNum).SizingMethod(SizingMethod) = CapSizingMethod;
    1193           0 :                                 if (CapSizingMethod == HeatingDesignCapacity || CapSizingMethod == CapacityPerFloorArea ||
    1194             :                                     CapSizingMethod == FractionOfAutosizedHeatingCapacity) {
    1195           0 :                                     if (CapSizingMethod == HeatingDesignCapacity) {
    1196           0 :                                         if (state.dataSize->ZoneHVACSizing(zoneHVACIndex).ScaledHeatingCapacity == AutoSize) {
    1197           0 :                                             ZoneEqSizing(CurZoneEqNum).DesHeatingLoad = state.dataSize->FinalZoneSizing(CurZoneEqNum).DesHeatLoad;
    1198             :                                         } else {
    1199           0 :                                             ZoneEqSizing(CurZoneEqNum).DesHeatingLoad =
    1200           0 :                                                 state.dataSize->ZoneHVACSizing(zoneHVACIndex).ScaledHeatingCapacity;
    1201             :                                         }
    1202           0 :                                         ZoneEqSizing(CurZoneEqNum).HeatingCapacity = true;
    1203           0 :                                         TempSize = AutoSize;
    1204           0 :                                     } else if (CapSizingMethod == CapacityPerFloorArea) {
    1205           0 :                                         ZoneEqSizing(CurZoneEqNum).HeatingCapacity = true;
    1206           0 :                                         ZoneEqSizing(CurZoneEqNum).DesHeatingLoad =
    1207           0 :                                             state.dataSize->ZoneHVACSizing(zoneHVACIndex).ScaledHeatingCapacity *
    1208           0 :                                             state.dataHeatBal->Zone(state.dataSize->DataZoneNumber).FloorArea;
    1209           0 :                                         state.dataSize->DataScalableCapSizingON = true;
    1210           0 :                                     } else if (CapSizingMethod == FractionOfAutosizedHeatingCapacity) {
    1211           0 :                                         state.dataSize->DataFracOfAutosizedHeatingCapacity =
    1212           0 :                                             state.dataSize->ZoneHVACSizing(zoneHVACIndex).ScaledHeatingCapacity;
    1213           0 :                                         state.dataSize->DataScalableCapSizingON = true;
    1214           0 :                                         TempSize = AutoSize;
    1215             :                                     }
    1216             :                                 }
    1217           0 :                                 PrintFlag = false;
    1218           0 :                                 bool errorsFound = false;
    1219           0 :                                 HeatingCapacitySizer sizerHeatingCapacity;
    1220           0 :                                 sizerHeatingCapacity.overrideSizingString(SizingString);
    1221           0 :                                 sizerHeatingCapacity.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
    1222           0 :                                 DesCoilLoad = sizerHeatingCapacity.size(state, TempSize, errorsFound);
    1223           0 :                                 state.dataSize->DataScalableCapSizingON = false;
    1224             :                             } else {
    1225           3 :                                 SizingString = "";
    1226           3 :                                 PrintFlag = false;
    1227           3 :                                 TempSize = AutoSize;
    1228           3 :                                 ZoneEqSizing(CurZoneEqNum).HeatingCapacity = true;
    1229           3 :                                 ZoneEqSizing(CurZoneEqNum).DesHeatingLoad = state.dataSize->FinalZoneSizing(CurZoneEqNum).DesHeatLoad;
    1230           3 :                                 bool errorsFound = false;
    1231           6 :                                 HeatingCapacitySizer sizerHeatingCapacity;
    1232           3 :                                 sizerHeatingCapacity.overrideSizingString(SizingString);
    1233           3 :                                 sizerHeatingCapacity.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
    1234           3 :                                 DesCoilLoad = sizerHeatingCapacity.size(state, TempSize, errorsFound);
    1235             :                             }
    1236             : 
    1237           3 :                             if (DesCoilLoad >= SmallLoad) {
    1238           6 :                                 rho = GetDensityGlycol(
    1239             :                                     state,
    1240           3 :                                     state.dataPlnt->PlantLoop(state.dataUnitHeaters->UnitHeat(UnitHeatNum).HWplantLoc.loopNum).FluidName,
    1241             :                                     DataGlobalConstants::HWInitConvTemp,
    1242           3 :                                     state.dataPlnt->PlantLoop(state.dataUnitHeaters->UnitHeat(UnitHeatNum).HWplantLoc.loopNum).FluidIndex,
    1243             :                                     RoutineName);
    1244           6 :                                 Cp = GetSpecificHeatGlycol(
    1245             :                                     state,
    1246           3 :                                     state.dataPlnt->PlantLoop(state.dataUnitHeaters->UnitHeat(UnitHeatNum).HWplantLoc.loopNum).FluidName,
    1247             :                                     DataGlobalConstants::HWInitConvTemp,
    1248           3 :                                     state.dataPlnt->PlantLoop(state.dataUnitHeaters->UnitHeat(UnitHeatNum).HWplantLoc.loopNum).FluidIndex,
    1249             :                                     RoutineName);
    1250           3 :                                 MaxVolHotWaterFlowDes = DesCoilLoad / (WaterCoilSizDeltaT * Cp * rho);
    1251             :                             } else {
    1252           0 :                                 MaxVolHotWaterFlowDes = 0.0;
    1253             :                             }
    1254             :                         }
    1255             :                     }
    1256           3 :                     if (IsAutoSize) {
    1257           3 :                         state.dataUnitHeaters->UnitHeat(UnitHeatNum).MaxVolHotWaterFlow = MaxVolHotWaterFlowDes;
    1258           9 :                         BaseSizer::reportSizerOutput(state,
    1259             :                                                      "ZoneHVAC:UnitHeater",
    1260           3 :                                                      state.dataUnitHeaters->UnitHeat(UnitHeatNum).Name,
    1261             :                                                      "Design Size Maximum Hot Water Flow [m3/s]",
    1262           6 :                                                      MaxVolHotWaterFlowDes);
    1263             :                     } else {
    1264           0 :                         if (state.dataUnitHeaters->UnitHeat(UnitHeatNum).MaxVolHotWaterFlow > 0.0 && MaxVolHotWaterFlowDes > 0.0) {
    1265           0 :                             MaxVolHotWaterFlowUser = state.dataUnitHeaters->UnitHeat(UnitHeatNum).MaxVolHotWaterFlow;
    1266           0 :                             BaseSizer::reportSizerOutput(state,
    1267             :                                                          "ZoneHVAC:UnitHeater",
    1268           0 :                                                          state.dataUnitHeaters->UnitHeat(UnitHeatNum).Name,
    1269             :                                                          "Design Size Maximum Hot Water Flow [m3/s]",
    1270             :                                                          MaxVolHotWaterFlowDes,
    1271             :                                                          "User-Specified Maximum Hot Water Flow [m3/s]",
    1272           0 :                                                          MaxVolHotWaterFlowUser);
    1273           0 :                             if (state.dataGlobal->DisplayExtraWarnings) {
    1274           0 :                                 if ((std::abs(MaxVolHotWaterFlowDes - MaxVolHotWaterFlowUser) / MaxVolHotWaterFlowUser) >
    1275           0 :                                     state.dataSize->AutoVsHardSizingThreshold) {
    1276           0 :                                     ShowMessage(state,
    1277           0 :                                                 "SizeUnitHeater: Potential issue with equipment sizing for ZoneHVAC:UnitHeater " +
    1278           0 :                                                     state.dataUnitHeaters->UnitHeat(UnitHeatNum).Name);
    1279           0 :                                     ShowContinueError(state,
    1280           0 :                                                       format("User-Specified Maximum Hot Water Flow of {:.5R} [m3/s]", MaxVolHotWaterFlowUser));
    1281           0 :                                     ShowContinueError(
    1282           0 :                                         state, format("differs from Design Size Maximum Hot Water Flow of {:.5R} [m3/s]", MaxVolHotWaterFlowDes));
    1283           0 :                                     ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
    1284           0 :                                     ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
    1285             :                                 }
    1286             :                             }
    1287             :                         }
    1288             :                     }
    1289             :                 }
    1290             :             }
    1291             :         } else {
    1292          57 :             state.dataUnitHeaters->UnitHeat(UnitHeatNum).MaxVolHotWaterFlow = 0.0;
    1293             :         }
    1294             : 
    1295          63 :         IsAutoSize = false;
    1296          63 :         if (state.dataUnitHeaters->UnitHeat(UnitHeatNum).MaxVolHotSteamFlow == AutoSize) {
    1297          43 :             IsAutoSize = true;
    1298             :         }
    1299             : 
    1300          63 :         if (state.dataUnitHeaters->UnitHeat(UnitHeatNum).Type == HCoilType::SteamCoil) {
    1301             : 
    1302           0 :             if (CurZoneEqNum > 0) {
    1303           0 :                 if (!IsAutoSize && !state.dataSize->ZoneSizingRunDone) { // Simulation continue
    1304           0 :                     if (state.dataUnitHeaters->UnitHeat(UnitHeatNum).MaxVolHotSteamFlow > 0.0) {
    1305           0 :                         BaseSizer::reportSizerOutput(state,
    1306             :                                                      "ZoneHVAC:UnitHeater",
    1307           0 :                                                      state.dataUnitHeaters->UnitHeat(UnitHeatNum).Name,
    1308             :                                                      "User-Specified Maximum Steam Flow [m3/s]",
    1309           0 :                                                      state.dataUnitHeaters->UnitHeat(UnitHeatNum).MaxVolHotSteamFlow);
    1310             :                     }
    1311             :                 } else {
    1312           0 :                     CheckZoneSizing(state, "ZoneHVAC:UnitHeater", state.dataUnitHeaters->UnitHeat(UnitHeatNum).Name);
    1313             : 
    1314           0 :                     CoilSteamInletNode =
    1315           0 :                         GetCoilSteamInletNode(state, "Coil:Heating:Steam", state.dataUnitHeaters->UnitHeat(UnitHeatNum).HCoilName, ErrorsFound);
    1316           0 :                     CoilSteamOutletNode =
    1317           0 :                         GetCoilSteamInletNode(state, "Coil:Heating:Steam", state.dataUnitHeaters->UnitHeat(UnitHeatNum).HCoilName, ErrorsFound);
    1318           0 :                     if (IsAutoSize) {
    1319           0 :                         PltSizHeatNum = MyPlantSizingIndex(state,
    1320             :                                                            "Coil:Heating:Steam",
    1321           0 :                                                            state.dataUnitHeaters->UnitHeat(UnitHeatNum).HCoilName,
    1322             :                                                            CoilSteamInletNode,
    1323             :                                                            CoilSteamOutletNode,
    1324             :                                                            ErrorsFound);
    1325           0 :                         if (PltSizHeatNum > 0) {
    1326           0 :                             if (state.dataUnitHeaters->UnitHeat(UnitHeatNum).HVACSizingIndex > 0) {
    1327           0 :                                 zoneHVACIndex = state.dataUnitHeaters->UnitHeat(UnitHeatNum).HVACSizingIndex;
    1328           0 :                                 SizingMethod = HeatingCapacitySizing;
    1329           0 :                                 CapSizingMethod = state.dataSize->ZoneHVACSizing(zoneHVACIndex).HeatingCapMethod;
    1330           0 :                                 ZoneEqSizing(CurZoneEqNum).SizingMethod(SizingMethod) = CapSizingMethod;
    1331           0 :                                 if (CapSizingMethod == HeatingDesignCapacity || CapSizingMethod == CapacityPerFloorArea ||
    1332             :                                     CapSizingMethod == FractionOfAutosizedHeatingCapacity) {
    1333           0 :                                     if (CapSizingMethod == HeatingDesignCapacity) {
    1334           0 :                                         if (state.dataSize->ZoneHVACSizing(zoneHVACIndex).ScaledHeatingCapacity == AutoSize) {
    1335           0 :                                             ZoneEqSizing(CurZoneEqNum).DesHeatingLoad = state.dataSize->FinalZoneSizing(CurZoneEqNum).DesHeatLoad;
    1336             :                                         } else {
    1337           0 :                                             ZoneEqSizing(CurZoneEqNum).DesHeatingLoad =
    1338           0 :                                                 state.dataSize->ZoneHVACSizing(zoneHVACIndex).ScaledHeatingCapacity;
    1339             :                                         }
    1340           0 :                                         ZoneEqSizing(CurZoneEqNum).HeatingCapacity = true;
    1341           0 :                                         TempSize = AutoSize;
    1342           0 :                                     } else if (CapSizingMethod == CapacityPerFloorArea) {
    1343           0 :                                         ZoneEqSizing(CurZoneEqNum).HeatingCapacity = true;
    1344           0 :                                         ZoneEqSizing(CurZoneEqNum).DesHeatingLoad =
    1345           0 :                                             state.dataSize->ZoneHVACSizing(zoneHVACIndex).ScaledHeatingCapacity *
    1346           0 :                                             state.dataHeatBal->Zone(state.dataSize->DataZoneNumber).FloorArea;
    1347           0 :                                         state.dataSize->DataScalableCapSizingON = true;
    1348           0 :                                     } else if (CapSizingMethod == FractionOfAutosizedHeatingCapacity) {
    1349           0 :                                         state.dataSize->DataFracOfAutosizedHeatingCapacity =
    1350           0 :                                             state.dataSize->ZoneHVACSizing(zoneHVACIndex).ScaledHeatingCapacity;
    1351           0 :                                         TempSize = AutoSize;
    1352           0 :                                         state.dataSize->DataScalableCapSizingON = true;
    1353             :                                     }
    1354             :                                 }
    1355           0 :                                 SizingMethod = HeatingCapacitySizing;
    1356           0 :                                 PrintFlag = false;
    1357           0 :                                 bool errorsFound = false;
    1358           0 :                                 HeatingCapacitySizer sizerHeatingCapacity;
    1359           0 :                                 sizerHeatingCapacity.overrideSizingString(SizingString);
    1360           0 :                                 sizerHeatingCapacity.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
    1361           0 :                                 DesCoilLoad = sizerHeatingCapacity.size(state, TempSize, errorsFound);
    1362           0 :                                 state.dataSize->DataScalableCapSizingON = false;
    1363             :                             } else {
    1364           0 :                                 DesCoilLoad = state.dataSize->FinalZoneSizing(CurZoneEqNum).DesHeatLoad;
    1365             :                             }
    1366           0 :                             if (DesCoilLoad >= SmallLoad) {
    1367           0 :                                 TempSteamIn = 100.00;
    1368           0 :                                 EnthSteamInDry =
    1369           0 :                                     GetSatEnthalpyRefrig(state, fluidNameSteam, TempSteamIn, 1.0, state.dataUnitHeaters->RefrigIndex, RoutineName);
    1370           0 :                                 EnthSteamOutWet =
    1371           0 :                                     GetSatEnthalpyRefrig(state, fluidNameSteam, TempSteamIn, 0.0, state.dataUnitHeaters->RefrigIndex, RoutineName);
    1372           0 :                                 LatentHeatSteam = EnthSteamInDry - EnthSteamOutWet;
    1373           0 :                                 SteamDensity =
    1374           0 :                                     GetSatDensityRefrig(state, fluidNameSteam, TempSteamIn, 1.0, state.dataUnitHeaters->RefrigIndex, RoutineName);
    1375           0 :                                 MaxVolHotSteamFlowDes =
    1376           0 :                                     DesCoilLoad / (SteamDensity * (LatentHeatSteam + state.dataSize->PlantSizData(PltSizHeatNum).DeltaT *
    1377           0 :                                                                                          CPHW(state.dataSize->PlantSizData(PltSizHeatNum).ExitTemp)));
    1378             :                             } else {
    1379           0 :                                 MaxVolHotSteamFlowDes = 0.0;
    1380             :                             }
    1381             :                         } else {
    1382           0 :                             ShowSevereError(state, "Autosizing of Steam flow requires a heating loop Sizing:Plant object");
    1383           0 :                             ShowContinueError(state, "Occurs in ZoneHVAC:UnitHeater Object=" + state.dataUnitHeaters->UnitHeat(UnitHeatNum).Name);
    1384           0 :                             ErrorsFound = true;
    1385             :                         }
    1386             :                     }
    1387           0 :                     if (IsAutoSize) {
    1388           0 :                         state.dataUnitHeaters->UnitHeat(UnitHeatNum).MaxVolHotSteamFlow = MaxVolHotSteamFlowDes;
    1389           0 :                         BaseSizer::reportSizerOutput(state,
    1390             :                                                      "ZoneHVAC:UnitHeater",
    1391           0 :                                                      state.dataUnitHeaters->UnitHeat(UnitHeatNum).Name,
    1392             :                                                      "Design Size Maximum Steam Flow [m3/s]",
    1393           0 :                                                      MaxVolHotSteamFlowDes);
    1394             :                     } else {
    1395           0 :                         if (state.dataUnitHeaters->UnitHeat(UnitHeatNum).MaxVolHotSteamFlow > 0.0 && MaxVolHotSteamFlowDes > 0.0) {
    1396           0 :                             MaxVolHotSteamFlowUser = state.dataUnitHeaters->UnitHeat(UnitHeatNum).MaxVolHotSteamFlow;
    1397           0 :                             BaseSizer::reportSizerOutput(state,
    1398             :                                                          "ZoneHVAC:UnitHeater",
    1399           0 :                                                          state.dataUnitHeaters->UnitHeat(UnitHeatNum).Name,
    1400             :                                                          "Design Size Maximum Steam Flow [m3/s]",
    1401             :                                                          MaxVolHotSteamFlowDes,
    1402             :                                                          "User-Specified Maximum Steam Flow [m3/s]",
    1403           0 :                                                          MaxVolHotSteamFlowUser);
    1404           0 :                             if (state.dataGlobal->DisplayExtraWarnings) {
    1405           0 :                                 if ((std::abs(MaxVolHotSteamFlowDes - MaxVolHotSteamFlowUser) / MaxVolHotSteamFlowUser) >
    1406           0 :                                     state.dataSize->AutoVsHardSizingThreshold) {
    1407           0 :                                     ShowMessage(state,
    1408           0 :                                                 "SizeUnitHeater: Potential issue with equipment sizing for ZoneHVAC:UnitHeater " +
    1409           0 :                                                     state.dataUnitHeaters->UnitHeat(UnitHeatNum).Name);
    1410           0 :                                     ShowContinueError(state, format("User-Specified Maximum Steam Flow of {:.5R} [m3/s]", MaxVolHotSteamFlowUser));
    1411           0 :                                     ShowContinueError(state,
    1412           0 :                                                       format("differs from Design Size Maximum Steam Flow of {:.5R} [m3/s]", MaxVolHotSteamFlowDes));
    1413           0 :                                     ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
    1414           0 :                                     ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
    1415             :                                 }
    1416             :                             }
    1417             :                         }
    1418             :                     }
    1419             :                 }
    1420             :             }
    1421             :         } else {
    1422          63 :             state.dataUnitHeaters->UnitHeat(UnitHeatNum).MaxVolHotSteamFlow = 0.0;
    1423             :         }
    1424             : 
    1425             :         // set the design air flow rate for the heating coil
    1426             : 
    1427         189 :         WaterCoils::SetCoilDesFlow(state,
    1428          63 :                                    state.dataUnitHeaters->UnitHeat(UnitHeatNum).HCoilTypeCh,
    1429          63 :                                    state.dataUnitHeaters->UnitHeat(UnitHeatNum).HCoilName,
    1430          63 :                                    state.dataUnitHeaters->UnitHeat(UnitHeatNum).MaxAirVolFlow,
    1431             :                                    ErrorsFound);
    1432          63 :         if (CurZoneEqNum > 0) {
    1433          63 :             ZoneEqSizing(CurZoneEqNum).MaxHWVolFlow = state.dataUnitHeaters->UnitHeat(UnitHeatNum).MaxVolHotWaterFlow;
    1434             :         }
    1435             : 
    1436          63 :         if (ErrorsFound) {
    1437           0 :             ShowFatalError(state, "Preceding sizing errors cause program termination");
    1438             :         }
    1439          63 :     }
    1440             : 
    1441      638739 :     void CalcUnitHeater(EnergyPlusData &state,
    1442             :                         int &UnitHeatNum,              // number of the current fan coil unit being simulated
    1443             :                         int const ZoneNum,             // number of zone being served
    1444             :                         bool const FirstHVACIteration, // TRUE if 1st HVAC simulation of system timestep
    1445             :                         Real64 &PowerMet,              // Sensible power supplied (W)
    1446             :                         Real64 &LatOutputProvided      // Latent power supplied (kg/s), negative = dehumidification
    1447             :     )
    1448             :     {
    1449             : 
    1450             :         // SUBROUTINE INFORMATION:
    1451             :         //       AUTHOR         Rick Strand
    1452             :         //       DATE WRITTEN   May 2000
    1453             :         //       MODIFIED       Don Shirey, Aug 2009 (LatOutputProvided)
    1454             :         //                      July 2012, Chandan Sharma - FSEC: Added zone sys avail managers
    1455             :         //       RE-ENGINEERED  na
    1456             : 
    1457             :         // PURPOSE OF THIS SUBROUTINE:
    1458             :         // This subroutine mainly controls the action of the unit heater
    1459             :         // based on the user input for controls and the defined controls
    1460             :         // algorithms.  There are currently (at the initial creation of this
    1461             :         // subroutine) two control methods: on-off fan operation or continuous
    1462             :         // fan operation.
    1463             : 
    1464             :         // METHODOLOGY EMPLOYED:
    1465             :         // Unit is controlled based on user input and what is happening in the
    1466             :         // simulation.  There are various cases to consider:
    1467             :         // 1. OFF: Unit is schedule off.  All flow rates are set to zero and
    1468             :         //    the temperatures are set to zone conditions.
    1469             :         // 2. NO LOAD OR COOLING/ON-OFF FAN CONTROL: Unit is available, but
    1470             :         //    there is no heating load.  All flow rates are set to zero and
    1471             :         //    the temperatures are set to zone conditions.
    1472             :         // 3. NO LOAD OR COOLING/CONTINUOUS FAN CONTROL: Unit is available and
    1473             :         //    the fan is running (if it is scheduled to be available also).
    1474             :         //    No heating is provided, only circulation via the fan running.
    1475             :         // 4. HEATING: The unit is on/available and there is a heating load.
    1476             :         //    The heating coil is modulated (constant fan speed) to meet the
    1477             :         //    heating load.
    1478             : 
    1479             :         // REFERENCES:
    1480             :         // ASHRAE Systems and Equipment Handbook (SI), 1996. page 31.7
    1481             : 
    1482             :         // Using/Aliasing
    1483             :         using namespace DataZoneEnergyDemands;
    1484             :         using DataHVACGlobals::FanType_SimpleOnOff;
    1485      638739 :         auto &ZoneCompTurnFansOff = state.dataHVACGlobal->ZoneCompTurnFansOff;
    1486      638739 :         auto &ZoneCompTurnFansOn = state.dataHVACGlobal->ZoneCompTurnFansOn;
    1487             :         using General::SolveRoot;
    1488             :         using PlantUtilities::SetComponentFlowRate;
    1489             : 
    1490             :         // SUBROUTINE PARAMETER DEFINITIONS:
    1491      638739 :         int constexpr MaxIter(100); // maximum number of iterations
    1492             : 
    1493             :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    1494             :         int ControlNode;      // the hot water inlet node
    1495             :         int InletNode;        // unit air inlet node
    1496             :         int OutletNode;       // unit air outlet node
    1497             :         Real64 ControlOffset; // tolerance for output control
    1498             :         Real64 MaxWaterFlow;  // maximum water flow for heating or cooling [kg/sec]
    1499             :         Real64 MinWaterFlow;  // minimum water flow for heating or cooling [kg/sec]
    1500             :         Real64 QUnitOut;      // heating or sens. cooling provided by fan coil unit [watts]
    1501             :         Real64 LatentOutput;  // Latent (moisture) add/removal rate, negative is dehumidification [kg/s]
    1502             :         Real64 SpecHumOut;    // Specific humidity ratio of outlet air (kg moisture / kg moist air)
    1503             :         Real64 SpecHumIn;     // Specific humidity ratio of inlet air (kg moisture / kg moist air)
    1504             :         Real64 mdot;          // local temporary for fluid mass flow rate
    1505             :         int OpMode;
    1506             :         Real64 PartLoadFrac;
    1507             :         Real64 NoOutput;
    1508             :         Real64 FullOutput;
    1509             :         int SolFlag; // return flag from RegulaFalsi for sensible load
    1510             :         bool UnitOn;
    1511             : 
    1512             :         // initialize local variables
    1513      638739 :         QUnitOut = 0.0;
    1514      638739 :         NoOutput = 0.0;
    1515      638739 :         FullOutput = 0.0;
    1516      638739 :         LatentOutput = 0.0;
    1517      638739 :         MaxWaterFlow = 0.0;
    1518      638739 :         MinWaterFlow = 0.0;
    1519      638739 :         PartLoadFrac = 0.0;
    1520      638739 :         SolFlag = 0; // # of iterations IF positive, -1 means failed to converge, -2 means bounds are incorrect
    1521      638739 :         InletNode = state.dataUnitHeaters->UnitHeat(UnitHeatNum).AirInNode;
    1522      638739 :         OutletNode = state.dataUnitHeaters->UnitHeat(UnitHeatNum).AirOutNode;
    1523      638739 :         ControlNode = state.dataUnitHeaters->UnitHeat(UnitHeatNum).HotControlNode;
    1524      638739 :         ControlOffset = state.dataUnitHeaters->UnitHeat(UnitHeatNum).HotControlOffset;
    1525      638739 :         UnitOn = false;
    1526      638739 :         OpMode = state.dataUnitHeaters->UnitHeat(UnitHeatNum).OpMode;
    1527             : 
    1528      638739 :         if (OpMode != CycFanCycCoil) {
    1529             : 
    1530     1288946 :             if (GetCurrentScheduleValue(state, state.dataUnitHeaters->UnitHeat(UnitHeatNum).SchedPtr) <= 0 ||
    1531     1189662 :                 ((GetCurrentScheduleValue(state, state.dataUnitHeaters->UnitHeat(UnitHeatNum).FanAvailSchedPtr) <= 0 && !ZoneCompTurnFansOn) ||
    1532      583363 :                  ZoneCompTurnFansOff)) {
    1533             :                 // Case 1: OFF-->unit schedule says that it it not available
    1534             :                 //         OR child fan in not available OR child fan not being cycled ON by sys avail manager
    1535             :                 //         OR child fan being forced OFF by sys avail manager
    1536       55376 :                 state.dataUnitHeaters->HCoilOn = false;
    1537       55376 :                 if (state.dataUnitHeaters->UnitHeat(UnitHeatNum).Type == HCoilType::WaterHeatingCoil) {
    1538        4585 :                     mdot = 0.0; // try to turn off
    1539             : 
    1540       13755 :                     SetComponentFlowRate(state,
    1541             :                                          mdot,
    1542        4585 :                                          state.dataUnitHeaters->UnitHeat(UnitHeatNum).HotControlNode,
    1543        4585 :                                          state.dataUnitHeaters->UnitHeat(UnitHeatNum).HotCoilOutNodeNum,
    1544        4585 :                                          state.dataUnitHeaters->UnitHeat(UnitHeatNum).HWplantLoc);
    1545             :                 }
    1546       55376 :                 if (state.dataUnitHeaters->UnitHeat(UnitHeatNum).Type == HCoilType::SteamCoil) {
    1547           0 :                     mdot = 0.0; // try to turn off
    1548             : 
    1549           0 :                     SetComponentFlowRate(state,
    1550             :                                          mdot,
    1551           0 :                                          state.dataUnitHeaters->UnitHeat(UnitHeatNum).HotControlNode,
    1552           0 :                                          state.dataUnitHeaters->UnitHeat(UnitHeatNum).HotCoilOutNodeNum,
    1553           0 :                                          state.dataUnitHeaters->UnitHeat(UnitHeatNum).HWplantLoc);
    1554             :                 }
    1555       55376 :                 CalcUnitHeaterComponents(state, UnitHeatNum, FirstHVACIteration, QUnitOut);
    1556             : 
    1557      583363 :             } else if ((state.dataUnitHeaters->QZnReq < SmallLoad) || state.dataZoneEnergyDemand->CurDeadBandOrSetback(ZoneNum)) {
    1558             :                 // Unit is available, but there is no load on it or we are in setback/deadband
    1559      377103 :                 if (!state.dataUnitHeaters->UnitHeat(UnitHeatNum).FanOffNoHeating) {
    1560             : 
    1561             :                     // Case 2: NO LOAD OR COOLING/ON-OFF FAN CONTROL-->turn everything off
    1562             :                     //         because there is no load on the unit heater
    1563      125673 :                     state.dataUnitHeaters->HCoilOn = false;
    1564      125673 :                     if (state.dataUnitHeaters->UnitHeat(UnitHeatNum).Type == HCoilType::WaterHeatingCoil) {
    1565        9403 :                         mdot = 0.0; // try to turn off
    1566             : 
    1567       28209 :                         SetComponentFlowRate(state,
    1568             :                                              mdot,
    1569        9403 :                                              state.dataUnitHeaters->UnitHeat(UnitHeatNum).HotControlNode,
    1570        9403 :                                              state.dataUnitHeaters->UnitHeat(UnitHeatNum).HotCoilOutNodeNum,
    1571        9403 :                                              state.dataUnitHeaters->UnitHeat(UnitHeatNum).HWplantLoc);
    1572             :                     }
    1573      125673 :                     if (state.dataUnitHeaters->UnitHeat(UnitHeatNum).Type == HCoilType::SteamCoil) {
    1574           0 :                         mdot = 0.0; // try to turn off
    1575             : 
    1576           0 :                         SetComponentFlowRate(state,
    1577             :                                              mdot,
    1578           0 :                                              state.dataUnitHeaters->UnitHeat(UnitHeatNum).HotControlNode,
    1579           0 :                                              state.dataUnitHeaters->UnitHeat(UnitHeatNum).HotCoilOutNodeNum,
    1580           0 :                                              state.dataUnitHeaters->UnitHeat(UnitHeatNum).HWplantLoc);
    1581             :                     }
    1582      125673 :                     CalcUnitHeaterComponents(state, UnitHeatNum, FirstHVACIteration, QUnitOut);
    1583             : 
    1584             :                 } else {
    1585             :                     // Case 3: NO LOAD OR COOLING/CONTINUOUS FAN CONTROL-->let the fan
    1586             :                     //         continue to run even though there is no load (air circulation)
    1587             :                     // Note that the flow rates were already set in the initialization routine
    1588             :                     // so there is really nothing else left to do except call the components.
    1589             : 
    1590      251430 :                     state.dataUnitHeaters->HCoilOn = false;
    1591      251430 :                     if (state.dataUnitHeaters->UnitHeat(UnitHeatNum).Type == HCoilType::WaterHeatingCoil) {
    1592        5751 :                         mdot = 0.0; // try to turn off
    1593             : 
    1594        5751 :                         if (state.dataUnitHeaters->UnitHeat(UnitHeatNum).HWplantLoc.loopNum > 0) {
    1595       17253 :                             SetComponentFlowRate(state,
    1596             :                                                  mdot,
    1597        5751 :                                                  state.dataUnitHeaters->UnitHeat(UnitHeatNum).HotControlNode,
    1598        5751 :                                                  state.dataUnitHeaters->UnitHeat(UnitHeatNum).HotCoilOutNodeNum,
    1599        5751 :                                                  state.dataUnitHeaters->UnitHeat(UnitHeatNum).HWplantLoc);
    1600             :                         }
    1601             :                     }
    1602      251430 :                     if (state.dataUnitHeaters->UnitHeat(UnitHeatNum).Type == HCoilType::SteamCoil) {
    1603           0 :                         mdot = 0.0; // try to turn off
    1604           0 :                         if (state.dataUnitHeaters->UnitHeat(UnitHeatNum).HWplantLoc.loopNum > 0) {
    1605           0 :                             SetComponentFlowRate(state,
    1606             :                                                  mdot,
    1607           0 :                                                  state.dataUnitHeaters->UnitHeat(UnitHeatNum).HotControlNode,
    1608           0 :                                                  state.dataUnitHeaters->UnitHeat(UnitHeatNum).HotCoilOutNodeNum,
    1609           0 :                                                  state.dataUnitHeaters->UnitHeat(UnitHeatNum).HWplantLoc);
    1610             :                         }
    1611             :                     }
    1612             : 
    1613      251430 :                     CalcUnitHeaterComponents(state, UnitHeatNum, FirstHVACIteration, QUnitOut);
    1614             :                 }
    1615             : 
    1616             :             } else { // Case 4: HEATING-->unit is available and there is a heating load
    1617             : 
    1618      206260 :                 switch (state.dataUnitHeaters->UnitHeat(UnitHeatNum).Type) {
    1619             : 
    1620       13684 :                 case HCoilType::WaterHeatingCoil: {
    1621             : 
    1622             :                     // On the first HVAC iteration the system values are given to the controller, but after that
    1623             :                     // the demand limits are in place and there needs to be feedback to the Zone Equipment
    1624       13684 :                     if (FirstHVACIteration) {
    1625        6842 :                         MaxWaterFlow = state.dataUnitHeaters->UnitHeat(UnitHeatNum).MaxHotWaterFlow;
    1626        6842 :                         MinWaterFlow = state.dataUnitHeaters->UnitHeat(UnitHeatNum).MinHotWaterFlow;
    1627             :                     } else {
    1628        6842 :                         MaxWaterFlow = state.dataLoopNodes->Node(ControlNode).MassFlowRateMaxAvail;
    1629        6842 :                         MinWaterFlow = state.dataLoopNodes->Node(ControlNode).MassFlowRateMinAvail;
    1630             :                     }
    1631             :                     // control water flow to obtain output matching QZnReq
    1632       95788 :                     ControlCompOutput(state,
    1633       13684 :                                       state.dataUnitHeaters->UnitHeat(UnitHeatNum).Name,
    1634       13684 :                                       state.dataUnitHeaters->cMO_UnitHeater,
    1635             :                                       UnitHeatNum,
    1636             :                                       FirstHVACIteration,
    1637       13684 :                                       state.dataUnitHeaters->QZnReq,
    1638             :                                       ControlNode,
    1639             :                                       MaxWaterFlow,
    1640             :                                       MinWaterFlow,
    1641             :                                       ControlOffset,
    1642       13684 :                                       state.dataUnitHeaters->UnitHeat(UnitHeatNum).ControlCompTypeNum,
    1643       13684 :                                       state.dataUnitHeaters->UnitHeat(UnitHeatNum).CompErrIndex,
    1644             :                                       _,
    1645             :                                       _,
    1646             :                                       _,
    1647             :                                       _,
    1648             :                                       _,
    1649       13684 :                                       state.dataUnitHeaters->UnitHeat(UnitHeatNum).HWplantLoc);
    1650       13684 :                     break;
    1651             :                 }
    1652      192576 :                 case HCoilType::Electric:
    1653             :                 case HCoilType::Gas:
    1654             :                 case HCoilType::SteamCoil: {
    1655      192576 :                     state.dataUnitHeaters->HCoilOn = true;
    1656      192576 :                     CalcUnitHeaterComponents(state, UnitHeatNum, FirstHVACIteration, QUnitOut);
    1657      192576 :                     break;
    1658             :                 }
    1659           0 :                 default:
    1660           0 :                     break;
    1661             :                 }
    1662             :             }
    1663     1277478 :             QUnitOut = state.dataLoopNodes->Node(OutletNode).MassFlowRate *
    1664     1277478 :                        (PsyHFnTdbW(state.dataLoopNodes->Node(OutletNode).Temp, state.dataLoopNodes->Node(InletNode).HumRat) -
    1665      638739 :                         PsyHFnTdbW(state.dataLoopNodes->Node(InletNode).Temp, state.dataLoopNodes->Node(InletNode).HumRat));
    1666      638739 :             if (state.dataLoopNodes->Node(InletNode).MassFlowRateMax > 0.0) {
    1667      561150 :                 state.dataUnitHeaters->UnitHeat(UnitHeatNum).FanPartLoadRatio =
    1668      561150 :                     state.dataLoopNodes->Node(InletNode).MassFlowRate / state.dataLoopNodes->Node(InletNode).MassFlowRateMax;
    1669             :             }
    1670             :         } else { // OnOff fan and cycling
    1671           0 :             if ((state.dataUnitHeaters->QZnReq < SmallLoad) || (state.dataZoneEnergyDemand->CurDeadBandOrSetback(ZoneNum)) ||
    1672           0 :                 GetCurrentScheduleValue(state, state.dataUnitHeaters->UnitHeat(UnitHeatNum).SchedPtr) <= 0 ||
    1673           0 :                 ((GetCurrentScheduleValue(state, state.dataUnitHeaters->UnitHeat(UnitHeatNum).FanAvailSchedPtr) <= 0 && !ZoneCompTurnFansOn) ||
    1674           0 :                  ZoneCompTurnFansOff)) {
    1675             :                 // Case 1: OFF-->unit schedule says that it it not available
    1676             :                 //         OR child fan in not available OR child fan not being cycled ON by sys avail manager
    1677             :                 //         OR child fan being forced OFF by sys avail manager
    1678           0 :                 PartLoadFrac = 0.0;
    1679           0 :                 state.dataUnitHeaters->HCoilOn = false;
    1680           0 :                 CalcUnitHeaterComponents(state, UnitHeatNum, FirstHVACIteration, QUnitOut, OpMode, PartLoadFrac);
    1681             : 
    1682           0 :                 if (state.dataLoopNodes->Node(InletNode).MassFlowRateMax > 0.0) {
    1683           0 :                     state.dataUnitHeaters->UnitHeat(UnitHeatNum).FanPartLoadRatio =
    1684           0 :                         state.dataLoopNodes->Node(InletNode).MassFlowRate / state.dataLoopNodes->Node(InletNode).MassFlowRateMax;
    1685             :                 }
    1686             : 
    1687             :             } else { // Case 4: HEATING-->unit is available and there is a heating load
    1688             : 
    1689           0 :                 state.dataUnitHeaters->HCoilOn = true;
    1690           0 :                 UnitOn = true;
    1691             : 
    1692             :                 // Find part load ratio of unit heater coils
    1693           0 :                 PartLoadFrac = 0.0;
    1694           0 :                 CalcUnitHeaterComponents(state, UnitHeatNum, FirstHVACIteration, NoOutput, OpMode, PartLoadFrac);
    1695           0 :                 if ((NoOutput - state.dataUnitHeaters->QZnReq) < SmallLoad) {
    1696             :                     // Unit heater is unable to meet the load with coil off, set PLR = 1
    1697           0 :                     PartLoadFrac = 1.0;
    1698           0 :                     CalcUnitHeaterComponents(state, UnitHeatNum, FirstHVACIteration, FullOutput, OpMode, PartLoadFrac);
    1699           0 :                     if ((FullOutput - state.dataUnitHeaters->QZnReq) > SmallLoad) {
    1700             :                         // Unit heater full load capacity is able to meet the load, Find PLR
    1701           0 :                         auto opMode = state.dataUnitHeaters->UnitHeat(UnitHeatNum).OpMode;
    1702             : 
    1703           0 :                         auto f = [&state, UnitHeatNum, FirstHVACIteration, opMode](Real64 const PartLoadRatio) {
    1704             :                             // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    1705             :                             Real64 QUnitOut; // heating provided by unit heater [watts]
    1706             : 
    1707           0 :                             CalcUnitHeaterComponents(state, UnitHeatNum, FirstHVACIteration, QUnitOut, opMode, PartLoadRatio);
    1708             : 
    1709             :                             // Calculate residual based on output calculation flag
    1710           0 :                             if (state.dataUnitHeaters->QZnReq != 0.0) {
    1711           0 :                                 return (QUnitOut - state.dataUnitHeaters->QZnReq) / state.dataUnitHeaters->QZnReq;
    1712             :                             } else
    1713           0 :                                 return 0.0;
    1714           0 :                         };
    1715             : 
    1716             :                         // Tolerance is in fraction of load, MaxIter = 30, SolFalg = # of iterations or error as appropriate
    1717           0 :                         SolveRoot(state, 0.001, MaxIter, SolFlag, PartLoadFrac, f, 0.0, 1.0);
    1718             :                     }
    1719             :                 }
    1720             : 
    1721           0 :                 CalcUnitHeaterComponents(state, UnitHeatNum, FirstHVACIteration, QUnitOut, OpMode, PartLoadFrac);
    1722             : 
    1723             :             } // ...end of unit ON/OFF IF-THEN block
    1724           0 :             state.dataUnitHeaters->UnitHeat(UnitHeatNum).PartLoadFrac = PartLoadFrac;
    1725           0 :             state.dataUnitHeaters->UnitHeat(UnitHeatNum).FanPartLoadRatio = PartLoadFrac;
    1726           0 :             state.dataLoopNodes->Node(OutletNode).MassFlowRate = state.dataLoopNodes->Node(InletNode).MassFlowRate;
    1727             :         }
    1728             : 
    1729             :         // CR9155 Remove specific humidity calculations
    1730      638739 :         SpecHumOut = state.dataLoopNodes->Node(OutletNode).HumRat;
    1731      638739 :         SpecHumIn = state.dataLoopNodes->Node(InletNode).HumRat;
    1732      638739 :         LatentOutput = state.dataLoopNodes->Node(OutletNode).MassFlowRate * (SpecHumOut - SpecHumIn); // Latent rate (kg/s), dehumid = negative
    1733             : 
    1734     1277478 :         QUnitOut = state.dataLoopNodes->Node(OutletNode).MassFlowRate *
    1735     1277478 :                    (PsyHFnTdbW(state.dataLoopNodes->Node(OutletNode).Temp, state.dataLoopNodes->Node(InletNode).HumRat) -
    1736      638739 :                     PsyHFnTdbW(state.dataLoopNodes->Node(InletNode).Temp, state.dataLoopNodes->Node(InletNode).HumRat));
    1737             : 
    1738             :         // Report variables...
    1739      638739 :         state.dataUnitHeaters->UnitHeat(UnitHeatNum).HeatPower = max(0.0, QUnitOut);
    1740      638739 :         if (state.dataUnitHeaters->UnitHeat(UnitHeatNum).FanType_Num != DataHVACGlobals::FanType_SystemModelObject) {
    1741      625419 :             state.dataUnitHeaters->UnitHeat(UnitHeatNum).ElecPower = Fans::GetFanPower(state, state.dataUnitHeaters->UnitHeat(UnitHeatNum).Fan_Index);
    1742             :         } else {
    1743       13320 :             state.dataUnitHeaters->UnitHeat(UnitHeatNum).ElecPower =
    1744       13320 :                 state.dataHVACFan->fanObjs[state.dataUnitHeaters->UnitHeat(UnitHeatNum).Fan_Index]->fanPower();
    1745             :         }
    1746             : 
    1747      638739 :         PowerMet = QUnitOut;
    1748      638739 :         LatOutputProvided = LatentOutput;
    1749      638739 :     }
    1750             : 
    1751      791702 :     void CalcUnitHeaterComponents(EnergyPlusData &state,
    1752             :                                   int const UnitHeatNum,               // Unit index in unit heater array
    1753             :                                   bool const FirstHVACIteration,       // flag for 1st HVAV iteration in the time step
    1754             :                                   Real64 &LoadMet,                     // load met by unit (watts)
    1755             :                                   Optional_int_const OpMode,           // fan operating mode
    1756             :                                   Optional<Real64 const> PartLoadRatio // part-load ratio
    1757             :     )
    1758             :     {
    1759             : 
    1760             :         // SUBROUTINE INFORMATION:
    1761             :         //       AUTHOR         Rick Strand
    1762             :         //       DATE WRITTEN   May 2000
    1763             :         //       MODIFIED       July 2012, Chandan Sharma - FSEC: Added zone sys avail managers
    1764             :         //       RE-ENGINEERED  na
    1765             : 
    1766             :         // PURPOSE OF THIS SUBROUTINE:
    1767             :         // This subroutine launches the individual component simulations.
    1768             :         // This is called either when the unit is off to carry null conditions
    1769             :         // through the unit or during control iterations to continue updating
    1770             :         // what is going on within the unit.
    1771             : 
    1772             :         // METHODOLOGY EMPLOYED:
    1773             :         // Simply calls the different components in order.
    1774             : 
    1775             :         // Using/Aliasing
    1776             :         using DataHVACGlobals::FanType_SimpleOnOff;
    1777      791702 :         auto &ZoneCompTurnFansOff = state.dataHVACGlobal->ZoneCompTurnFansOff;
    1778      791702 :         auto &ZoneCompTurnFansOn = state.dataHVACGlobal->ZoneCompTurnFansOn;
    1779             :         using HeatingCoils::SimulateHeatingCoilComponents;
    1780             :         using PlantUtilities::SetComponentFlowRate;
    1781             :         using SteamCoils::SimulateSteamCoilComponents;
    1782             :         using WaterCoils::SimulateWaterCoilComponents;
    1783             : 
    1784             :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    1785             :         Real64 AirMassFlow;  // total mass flow through the unit
    1786             :         Real64 CpAirZn;      // specific heat of dry air at zone conditions (zone conditions same as unit inlet)
    1787             :         int HCoilInAirNode;  // inlet node number for fan exit/coil inlet
    1788             :         int InletNode;       // unit air inlet node
    1789             :         int OutletNode;      // unit air outlet node
    1790             :         Real64 QCoilReq;     // Heat addition required from an electric/gas heating coil
    1791             :         Real64 mdot;         // local temporary for fluid mass flow rate
    1792             :         int FanOpMode;       // Fan operting mode or fan type
    1793             :         Real64 PartLoadFrac; // part-load ratio
    1794             : 
    1795      791702 :         InletNode = state.dataUnitHeaters->UnitHeat(UnitHeatNum).AirInNode;
    1796      791702 :         OutletNode = state.dataUnitHeaters->UnitHeat(UnitHeatNum).AirOutNode;
    1797      791702 :         QCoilReq = 0.0;
    1798             : 
    1799      791702 :         if (present(PartLoadRatio)) {
    1800           0 :             PartLoadFrac = PartLoadRatio;
    1801             :         } else {
    1802      791702 :             PartLoadFrac = 1.0;
    1803             :         }
    1804      791702 :         if (present(OpMode)) {
    1805           0 :             FanOpMode = OpMode;
    1806             :         } else {
    1807      791702 :             FanOpMode = ContFanCycCoil;
    1808             :         }
    1809      791702 :         if (FanOpMode != CycFanCycCoil) {
    1810      791702 :             if (state.dataUnitHeaters->UnitHeat(UnitHeatNum).FanType_Num != DataHVACGlobals::FanType_SystemModelObject) {
    1811     2140944 :                 Fans::SimulateFanComponents(state,
    1812      713648 :                                             state.dataUnitHeaters->UnitHeat(UnitHeatNum).FanName,
    1813             :                                             FirstHVACIteration,
    1814      713648 :                                             state.dataUnitHeaters->UnitHeat(UnitHeatNum).Fan_Index,
    1815             :                                             _,
    1816             :                                             ZoneCompTurnFansOn,
    1817             :                                             ZoneCompTurnFansOff);
    1818             :             } else {
    1819       78054 :                 state.dataHVACFan->fanObjs[state.dataUnitHeaters->UnitHeat(UnitHeatNum).Fan_Index]->simulate(
    1820             :                     state, _, ZoneCompTurnFansOn, ZoneCompTurnFansOff, _);
    1821             :             }
    1822             : 
    1823      791702 :             switch (state.dataUnitHeaters->UnitHeat(UnitHeatNum).Type) {
    1824             : 
    1825      186386 :             case HCoilType::WaterHeatingCoil: {
    1826             : 
    1827      559158 :                 SimulateWaterCoilComponents(state,
    1828      186386 :                                             state.dataUnitHeaters->UnitHeat(UnitHeatNum).HCoilName,
    1829             :                                             FirstHVACIteration,
    1830      186386 :                                             state.dataUnitHeaters->UnitHeat(UnitHeatNum).HCoil_Index);
    1831      186386 :                 break;
    1832             :             }
    1833           0 :             case HCoilType::SteamCoil: {
    1834             : 
    1835           0 :                 if (!state.dataUnitHeaters->HCoilOn) {
    1836           0 :                     QCoilReq = 0.0;
    1837             :                 } else {
    1838           0 :                     HCoilInAirNode = state.dataUnitHeaters->UnitHeat(UnitHeatNum).FanOutletNode;
    1839           0 :                     CpAirZn = PsyCpAirFnW(state.dataLoopNodes->Node(state.dataUnitHeaters->UnitHeat(UnitHeatNum).AirInNode).HumRat);
    1840           0 :                     QCoilReq =
    1841           0 :                         state.dataUnitHeaters->QZnReq - state.dataLoopNodes->Node(HCoilInAirNode).MassFlowRate * CpAirZn *
    1842           0 :                                                             (state.dataLoopNodes->Node(HCoilInAirNode).Temp -
    1843           0 :                                                              state.dataLoopNodes->Node(state.dataUnitHeaters->UnitHeat(UnitHeatNum).AirInNode).Temp);
    1844             :                 }
    1845           0 :                 if (QCoilReq < 0.0) QCoilReq = 0.0; // a heating coil can only heat, not cool
    1846           0 :                 SimulateSteamCoilComponents(state,
    1847           0 :                                             state.dataUnitHeaters->UnitHeat(UnitHeatNum).HCoilName,
    1848             :                                             FirstHVACIteration,
    1849           0 :                                             state.dataUnitHeaters->UnitHeat(UnitHeatNum).HCoil_Index,
    1850             :                                             QCoilReq);
    1851           0 :                 break;
    1852             :             }
    1853      605316 :             case HCoilType::Electric:
    1854             :             case HCoilType::Gas: {
    1855             : 
    1856      605316 :                 if (!state.dataUnitHeaters->HCoilOn) {
    1857      412740 :                     QCoilReq = 0.0;
    1858             :                 } else {
    1859      192576 :                     HCoilInAirNode = state.dataUnitHeaters->UnitHeat(UnitHeatNum).FanOutletNode;
    1860      192576 :                     CpAirZn = PsyCpAirFnW(state.dataLoopNodes->Node(state.dataUnitHeaters->UnitHeat(UnitHeatNum).AirInNode).HumRat);
    1861      192576 :                     QCoilReq =
    1862      385152 :                         state.dataUnitHeaters->QZnReq - state.dataLoopNodes->Node(HCoilInAirNode).MassFlowRate * CpAirZn *
    1863      385152 :                                                             (state.dataLoopNodes->Node(HCoilInAirNode).Temp -
    1864      192576 :                                                              state.dataLoopNodes->Node(state.dataUnitHeaters->UnitHeat(UnitHeatNum).AirInNode).Temp);
    1865             :                 }
    1866      605316 :                 if (QCoilReq < 0.0) QCoilReq = 0.0; // a heating coil can only heat, not cool
    1867     1815948 :                 SimulateHeatingCoilComponents(state,
    1868      605316 :                                               state.dataUnitHeaters->UnitHeat(UnitHeatNum).HCoilName,
    1869             :                                               FirstHVACIteration,
    1870             :                                               QCoilReq,
    1871      605316 :                                               state.dataUnitHeaters->UnitHeat(UnitHeatNum).HCoil_Index);
    1872      605316 :                 break;
    1873             :             }
    1874           0 :             default:
    1875           0 :                 break;
    1876             :             }
    1877             : 
    1878      791702 :             AirMassFlow = state.dataLoopNodes->Node(OutletNode).MassFlowRate;
    1879             : 
    1880      791702 :             state.dataLoopNodes->Node(InletNode).MassFlowRate =
    1881      791702 :                 state.dataLoopNodes->Node(OutletNode).MassFlowRate; // maintain continuity through unit heater
    1882             : 
    1883             :         } else { // OnOff fan cycling
    1884             : 
    1885           0 :             state.dataLoopNodes->Node(InletNode).MassFlowRate = state.dataLoopNodes->Node(InletNode).MassFlowRateMax * PartLoadFrac;
    1886           0 :             AirMassFlow = state.dataLoopNodes->Node(InletNode).MassFlowRate;
    1887             :             // Set the fan inlet node maximum available mass flow rates for cycling fans
    1888           0 :             state.dataLoopNodes->Node(InletNode).MassFlowRateMaxAvail = AirMassFlow;
    1889             : 
    1890           0 :             if (QCoilReq < 0.0) QCoilReq = 0.0; // a heating coil can only heat, not cool
    1891           0 :             if (state.dataUnitHeaters->UnitHeat(UnitHeatNum).FanType_Num != DataHVACGlobals::FanType_SystemModelObject) {
    1892           0 :                 Fans::SimulateFanComponents(state,
    1893           0 :                                             state.dataUnitHeaters->UnitHeat(UnitHeatNum).FanName,
    1894             :                                             FirstHVACIteration,
    1895           0 :                                             state.dataUnitHeaters->UnitHeat(UnitHeatNum).Fan_Index,
    1896             :                                             _,
    1897             :                                             ZoneCompTurnFansOn,
    1898             :                                             ZoneCompTurnFansOff);
    1899             :             } else {
    1900           0 :                 state.dataHVACFan->fanObjs[state.dataUnitHeaters->UnitHeat(UnitHeatNum).Fan_Index]->simulate(
    1901             :                     state, _, ZoneCompTurnFansOn, ZoneCompTurnFansOff, _);
    1902             :             }
    1903           0 :             switch (state.dataUnitHeaters->UnitHeat(UnitHeatNum).Type) {
    1904             : 
    1905           0 :             case HCoilType::WaterHeatingCoil: {
    1906             : 
    1907           0 :                 if (!state.dataUnitHeaters->HCoilOn) {
    1908           0 :                     mdot = 0.0;
    1909           0 :                     QCoilReq = 0.0;
    1910             :                 } else {
    1911           0 :                     HCoilInAirNode = state.dataUnitHeaters->UnitHeat(UnitHeatNum).FanOutletNode;
    1912           0 :                     CpAirZn = PsyCpAirFnW(state.dataLoopNodes->Node(state.dataUnitHeaters->UnitHeat(UnitHeatNum).AirInNode).HumRat);
    1913           0 :                     QCoilReq =
    1914           0 :                         state.dataUnitHeaters->QZnReq - state.dataLoopNodes->Node(HCoilInAirNode).MassFlowRate * CpAirZn *
    1915           0 :                                                             (state.dataLoopNodes->Node(HCoilInAirNode).Temp -
    1916           0 :                                                              state.dataLoopNodes->Node(state.dataUnitHeaters->UnitHeat(UnitHeatNum).AirInNode).Temp);
    1917           0 :                     mdot = state.dataUnitHeaters->UnitHeat(UnitHeatNum).MaxHotWaterFlow * PartLoadFrac;
    1918             :                 }
    1919           0 :                 if (QCoilReq < 0.0) QCoilReq = 0.0; // a heating coil can only heat, not cool
    1920           0 :                 SetComponentFlowRate(state,
    1921             :                                      mdot,
    1922           0 :                                      state.dataUnitHeaters->UnitHeat(UnitHeatNum).HotControlNode,
    1923           0 :                                      state.dataUnitHeaters->UnitHeat(UnitHeatNum).HotCoilOutNodeNum,
    1924           0 :                                      state.dataUnitHeaters->UnitHeat(UnitHeatNum).HWplantLoc);
    1925           0 :                 SimulateWaterCoilComponents(state,
    1926           0 :                                             state.dataUnitHeaters->UnitHeat(UnitHeatNum).HCoilName,
    1927             :                                             FirstHVACIteration,
    1928           0 :                                             state.dataUnitHeaters->UnitHeat(UnitHeatNum).HCoil_Index,
    1929             :                                             QCoilReq,
    1930             :                                             FanOpMode,
    1931             :                                             PartLoadFrac);
    1932           0 :                 break;
    1933             :             }
    1934           0 :             case HCoilType::SteamCoil: {
    1935           0 :                 if (!state.dataUnitHeaters->HCoilOn) {
    1936           0 :                     mdot = 0.0;
    1937           0 :                     QCoilReq = 0.0;
    1938             :                 } else {
    1939           0 :                     HCoilInAirNode = state.dataUnitHeaters->UnitHeat(UnitHeatNum).FanOutletNode;
    1940           0 :                     CpAirZn = PsyCpAirFnW(state.dataLoopNodes->Node(state.dataUnitHeaters->UnitHeat(UnitHeatNum).AirInNode).HumRat);
    1941           0 :                     QCoilReq =
    1942           0 :                         state.dataUnitHeaters->QZnReq - state.dataLoopNodes->Node(HCoilInAirNode).MassFlowRate * CpAirZn *
    1943           0 :                                                             (state.dataLoopNodes->Node(HCoilInAirNode).Temp -
    1944           0 :                                                              state.dataLoopNodes->Node(state.dataUnitHeaters->UnitHeat(UnitHeatNum).AirInNode).Temp);
    1945           0 :                     mdot = state.dataUnitHeaters->UnitHeat(UnitHeatNum).MaxHotSteamFlow * PartLoadFrac;
    1946             :                 }
    1947           0 :                 if (QCoilReq < 0.0) QCoilReq = 0.0; // a heating coil can only heat, not cool
    1948           0 :                 SetComponentFlowRate(state,
    1949             :                                      mdot,
    1950           0 :                                      state.dataUnitHeaters->UnitHeat(UnitHeatNum).HotControlNode,
    1951           0 :                                      state.dataUnitHeaters->UnitHeat(UnitHeatNum).HotCoilOutNodeNum,
    1952           0 :                                      state.dataUnitHeaters->UnitHeat(UnitHeatNum).HWplantLoc);
    1953           0 :                 SimulateSteamCoilComponents(state,
    1954           0 :                                             state.dataUnitHeaters->UnitHeat(UnitHeatNum).HCoilName,
    1955             :                                             FirstHVACIteration,
    1956           0 :                                             state.dataUnitHeaters->UnitHeat(UnitHeatNum).HCoil_Index,
    1957             :                                             QCoilReq,
    1958             :                                             _,
    1959             :                                             FanOpMode,
    1960             :                                             PartLoadFrac);
    1961           0 :                 break;
    1962             :             }
    1963           0 :             case HCoilType::Electric:
    1964             :             case HCoilType::Gas: {
    1965             : 
    1966           0 :                 if (!state.dataUnitHeaters->HCoilOn) {
    1967           0 :                     QCoilReq = 0.0;
    1968             :                 } else {
    1969           0 :                     HCoilInAirNode = state.dataUnitHeaters->UnitHeat(UnitHeatNum).FanOutletNode;
    1970           0 :                     CpAirZn = PsyCpAirFnW(state.dataLoopNodes->Node(state.dataUnitHeaters->UnitHeat(UnitHeatNum).AirInNode).HumRat);
    1971           0 :                     QCoilReq =
    1972           0 :                         state.dataUnitHeaters->QZnReq - state.dataLoopNodes->Node(HCoilInAirNode).MassFlowRate * CpAirZn *
    1973           0 :                                                             (state.dataLoopNodes->Node(HCoilInAirNode).Temp -
    1974           0 :                                                              state.dataLoopNodes->Node(state.dataUnitHeaters->UnitHeat(UnitHeatNum).AirInNode).Temp);
    1975             :                 }
    1976           0 :                 if (QCoilReq < 0.0) QCoilReq = 0.0; // a heating coil can only heat, not cool
    1977           0 :                 SimulateHeatingCoilComponents(state,
    1978           0 :                                               state.dataUnitHeaters->UnitHeat(UnitHeatNum).HCoilName,
    1979             :                                               FirstHVACIteration,
    1980             :                                               QCoilReq,
    1981           0 :                                               state.dataUnitHeaters->UnitHeat(UnitHeatNum).HCoil_Index,
    1982             :                                               _,
    1983             :                                               _,
    1984             :                                               FanOpMode,
    1985             :                                               PartLoadFrac);
    1986           0 :                 break;
    1987             :             }
    1988           0 :             default:
    1989           0 :                 break;
    1990             :             }
    1991           0 :             state.dataLoopNodes->Node(OutletNode).MassFlowRate =
    1992           0 :                 state.dataLoopNodes->Node(InletNode).MassFlowRate; // maintain continuity through unit heater
    1993             :         }
    1994     1583404 :         LoadMet = AirMassFlow * (PsyHFnTdbW(state.dataLoopNodes->Node(OutletNode).Temp, state.dataLoopNodes->Node(InletNode).HumRat) -
    1995      791702 :                                  PsyHFnTdbW(state.dataLoopNodes->Node(InletNode).Temp, state.dataLoopNodes->Node(InletNode).HumRat));
    1996      791702 :     }
    1997             : 
    1998             :     // SUBROUTINE UpdateUnitHeater
    1999             : 
    2000             :     // No update routine needed in this module since all of the updates happen on
    2001             :     // the Node derived type directly and these updates are done by other routines.
    2002             : 
    2003             :     // END SUBROUTINE UpdateUnitHeater
    2004             : 
    2005      638739 :     void ReportUnitHeater(EnergyPlusData &state, int const UnitHeatNum) // Unit index in unit heater array
    2006             :     {
    2007             : 
    2008             :         // SUBROUTINE INFORMATION:
    2009             :         //       AUTHOR         Rick Strand
    2010             :         //       DATE WRITTEN   May 2000
    2011             :         //       MODIFIED       na
    2012             :         //       RE-ENGINEERED  na
    2013             : 
    2014             :         // PURPOSE OF THIS SUBROUTINE:
    2015             :         // This subroutine needs a description.
    2016             : 
    2017             :         // METHODOLOGY EMPLOYED:
    2018             :         // Needs description, as appropriate.
    2019             : 
    2020             :         // Using/Aliasing
    2021      638739 :         auto &TimeStepSys = state.dataHVACGlobal->TimeStepSys;
    2022             : 
    2023      638739 :         state.dataUnitHeaters->UnitHeat(UnitHeatNum).HeatEnergy =
    2024      638739 :             state.dataUnitHeaters->UnitHeat(UnitHeatNum).HeatPower * TimeStepSys * DataGlobalConstants::SecInHour;
    2025      638739 :         state.dataUnitHeaters->UnitHeat(UnitHeatNum).ElecEnergy =
    2026      638739 :             state.dataUnitHeaters->UnitHeat(UnitHeatNum).ElecPower * TimeStepSys * DataGlobalConstants::SecInHour;
    2027             : 
    2028      638739 :         if (state.dataUnitHeaters->UnitHeat(UnitHeatNum).FirstPass) { // reset sizing flags so other zone equipment can size normally
    2029         116 :             if (!state.dataGlobal->SysSizingCalc) {
    2030          63 :                 DataSizing::resetHVACSizingGlobals(state, state.dataSize->CurZoneEqNum, 0, state.dataUnitHeaters->UnitHeat(UnitHeatNum).FirstPass);
    2031             :             }
    2032             :         }
    2033      638739 :     }
    2034             : 
    2035             : } // namespace UnitHeater
    2036             : 
    2037        2313 : } // namespace EnergyPlus

Generated by: LCOV version 1.13