LCOV - code coverage report
Current view: top level - EnergyPlus - UnitHeater.cc (source / functions) Hit Total Coverage
Test: lcov.output.filtered Lines: 519 958 54.2 %
Date: 2024-08-24 18:31:18 Functions: 7 9 77.8 %

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

Generated by: LCOV version 1.14