LCOV - code coverage report
Current view: top level - EnergyPlus - HeatingCoils.cc (source / functions) Coverage Total Hit
Test: lcov.output.filtered Lines: 65.4 % 1670 1092
Test Date: 2025-06-02 12:03:30 Functions: 88.0 % 25 22

            Line data    Source code
       1              : // EnergyPlus, Copyright (c) 1996-2025, The Board of Trustees of the University of Illinois,
       2              : // The Regents of the University of California, through Lawrence Berkeley National Laboratory
       3              : // (subject to receipt of any required approvals from the U.S. Dept. of Energy), Oak Ridge
       4              : // National Laboratory, managed by UT-Battelle, Alliance for Sustainable Energy, LLC, and other
       5              : // contributors. All rights reserved.
       6              : //
       7              : // NOTICE: This Software was developed under funding from the U.S. Department of Energy and the
       8              : // U.S. Government consequently retains certain rights. As such, the U.S. Government has been
       9              : // granted for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable,
      10              : // worldwide license in the Software to reproduce, distribute copies to the public, prepare
      11              : // derivative works, and perform publicly and display publicly, and to permit others to do so.
      12              : //
      13              : // Redistribution and use in source and binary forms, with or without modification, are permitted
      14              : // provided that the following conditions are met:
      15              : //
      16              : // (1) Redistributions of source code must retain the above copyright notice, this list of
      17              : //     conditions and the following disclaimer.
      18              : //
      19              : // (2) Redistributions in binary form must reproduce the above copyright notice, this list of
      20              : //     conditions and the following disclaimer in the documentation and/or other materials
      21              : //     provided with the distribution.
      22              : //
      23              : // (3) Neither the name of the University of California, Lawrence Berkeley National Laboratory,
      24              : //     the University of Illinois, U.S. Dept. of Energy nor the names of its contributors may be
      25              : //     used to endorse or promote products derived from this software without specific prior
      26              : //     written permission.
      27              : //
      28              : // (4) Use of EnergyPlus(TM) Name. If Licensee (i) distributes the software in stand-alone form
      29              : //     without changes from the version obtained under this License, or (ii) Licensee makes a
      30              : //     reference solely to the software portion of its product, Licensee must refer to the
      31              : //     software as "EnergyPlus version X" software, where "X" is the version number Licensee
      32              : //     obtained under this License and may not use a different name for the software. Except as
      33              : //     specifically required in this Section (4), Licensee shall not use in a company name, a
      34              : //     product name, in advertising, publicity, or other promotional activities any name, trade
      35              : //     name, trademark, logo, or other designation of "EnergyPlus", "E+", "e+" or confusingly
      36              : //     similar designation, without the U.S. Department of Energy's prior written consent.
      37              : //
      38              : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
      39              : // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
      40              : // AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
      41              : // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
      42              : // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
      43              : // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      44              : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
      45              : // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
      46              : // POSSIBILITY OF SUCH DAMAGE.
      47              : 
      48              : // 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/All_Simple_Sizing.hh>
      57              : #include <EnergyPlus/Autosizing/HeatingCapacitySizing.hh>
      58              : #include <EnergyPlus/BranchNodeConnections.hh>
      59              : #include <EnergyPlus/Coils/CoilCoolingDX.hh>
      60              : #include <EnergyPlus/CurveManager.hh>
      61              : #include <EnergyPlus/DXCoils.hh>
      62              : #include <EnergyPlus/Data/EnergyPlusData.hh>
      63              : #include <EnergyPlus/DataContaminantBalance.hh>
      64              : #include <EnergyPlus/DataEnvironment.hh>
      65              : #include <EnergyPlus/DataGlobalConstants.hh>
      66              : #include <EnergyPlus/DataHVACGlobals.hh>
      67              : #include <EnergyPlus/DataHeatBalance.hh>
      68              : #include <EnergyPlus/DataLoopNode.hh>
      69              : #include <EnergyPlus/DataSizing.hh>
      70              : #include <EnergyPlus/EMSManager.hh>
      71              : #include <EnergyPlus/FaultsManager.hh>
      72              : #include <EnergyPlus/General.hh>
      73              : #include <EnergyPlus/GlobalNames.hh>
      74              : #include <EnergyPlus/HeatingCoils.hh>
      75              : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
      76              : #include <EnergyPlus/NodeInputManager.hh>
      77              : #include <EnergyPlus/OutputProcessor.hh>
      78              : #include <EnergyPlus/OutputReportPredefined.hh>
      79              : #include <EnergyPlus/Psychrometrics.hh>
      80              : #include <EnergyPlus/RefrigeratedCase.hh>
      81              : #include <EnergyPlus/ScheduleManager.hh>
      82              : #include <EnergyPlus/UtilityRoutines.hh>
      83              : #include <EnergyPlus/VariableSpeedCoils.hh>
      84              : 
      85              : namespace EnergyPlus { // NOLINT(modernize-concat-nested-namespaces) // TODO: Take out this lint when we want to apply formatting for nested
      86              :                        // namespacing
      87              : 
      88              : namespace HeatingCoils {
      89              :     // Module containing the HeatingCoil simulation routines other than the Water coils
      90              : 
      91              :     // MODULE INFORMATION:
      92              :     //       AUTHOR         Richard J. Liesen
      93              :     //       DATE WRITTEN   May 2000
      94              :     //       MODIFIED       Therese Stovall June 2008 to add references to refrigeration condensers
      95              : 
      96              :     // PURPOSE OF THIS MODULE:
      97              :     // To encapsulate the data and algorithms required to
      98              :     // manage the HeatingCoil System Component
      99              : 
     100       233160 :     void SimulateHeatingCoilComponents(EnergyPlusData &state,
     101              :                                        std::string_view CompName,
     102              :                                        bool const FirstHVACIteration,
     103              :                                        ObjexxFCL::Optional<Real64 const> QCoilReq, // coil load to be met
     104              :                                        ObjexxFCL::Optional_int CompIndex,
     105              :                                        ObjexxFCL::Optional<Real64> QCoilActual, // coil load actually delivered returned to calling component
     106              :                                        ObjexxFCL::Optional_bool_const SuppHeat, // True if current heating coil is a supplemental heating coil
     107              :                                        ObjexxFCL::Optional<HVAC::FanOp const> fanOpMode, // fan operating mode, FanOp::Cycling or FanOp::Continuous
     108              :                                        ObjexxFCL::Optional<Real64 const> PartLoadRatio,  // part-load ratio of heating coil
     109              :                                        ObjexxFCL::Optional_int StageNum,
     110              :                                        ObjexxFCL::Optional<Real64 const> SpeedRatio // Speed ratio of MultiStage heating coil
     111              :     )
     112              :     {
     113              : 
     114              :         // SUBROUTINE INFORMATION:
     115              :         //       AUTHOR         Richard Liesen
     116              :         //       DATE WRITTEN   May 2000
     117              : 
     118              :         // PURPOSE OF THIS SUBROUTINE:
     119              :         // This subroutine manages HeatingCoil component simulation.
     120              : 
     121              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     122       233160 :         int CoilNum(0);       // The HeatingCoil that you are currently loading input into
     123              :         Real64 QCoilActual2;  // coil load actually delivered returned from specific coil
     124              :         HVAC::FanOp fanOp;    // fan operating mode
     125              :         Real64 PartLoadFrac;  // part-load fraction of heating coil
     126              :         Real64 QCoilRequired; // local variable for optional argument
     127              : 
     128              :         // Obtains and Allocates HeatingCoil related parameters from input file
     129       233160 :         if (state.dataHeatingCoils->GetCoilsInputFlag) { // First time subroutine has been entered
     130           21 :             GetHeatingCoilInput(state);
     131           21 :             state.dataHeatingCoils->GetCoilsInputFlag = false;
     132              :         }
     133              : 
     134              :         // Find the correct HeatingCoilNumber with the Coil Name
     135       233160 :         if (present(CompIndex)) {
     136       233160 :             if (CompIndex == 0) {
     137        81878 :                 CoilNum = Util::FindItemInList(CompName, state.dataHeatingCoils->HeatingCoil);
     138        81878 :                 if (CoilNum == 0) {
     139            0 :                     ShowFatalError(state, format("SimulateHeatingCoilComponents: Coil not found={}", CompName));
     140              :                 }
     141              :                 //    CompIndex=CoilNum
     142              :             } else {
     143       151282 :                 CoilNum = CompIndex;
     144       151282 :                 if (CoilNum > state.dataHeatingCoils->NumHeatingCoils || CoilNum < 1) {
     145            0 :                     ShowFatalError(state,
     146            0 :                                    format("SimulateHeatingCoilComponents: Invalid CompIndex passed={}, Number of Heating Coils={}, Coil name={}",
     147              :                                           CoilNum,
     148            0 :                                           state.dataHeatingCoils->NumHeatingCoils,
     149              :                                           CompName));
     150              :                 }
     151       151282 :                 if (state.dataHeatingCoils->CheckEquipName(CoilNum)) {
     152           76 :                     if (!CompName.empty() && CompName != state.dataHeatingCoils->HeatingCoil(CoilNum).Name) {
     153            0 :                         ShowFatalError(
     154              :                             state,
     155            0 :                             format("SimulateHeatingCoilComponents: Invalid CompIndex passed={}, Coil name={}, stored Coil Name for that index={}",
     156              :                                    CoilNum,
     157              :                                    CompName,
     158            0 :                                    state.dataHeatingCoils->HeatingCoil(CoilNum).Name));
     159              :                     }
     160           76 :                     state.dataHeatingCoils->CheckEquipName(CoilNum) = false;
     161              :                 }
     162              :             }
     163              :         } else {
     164            0 :             ShowSevereError(state, "SimulateHeatingCoilComponents: CompIndex argument not used.");
     165            0 :             ShowContinueError(state, format("..CompName = {}", CompName));
     166            0 :             ShowFatalError(state, "Preceding conditions cause termination.");
     167              :         }
     168              : 
     169       233160 :         if (present(SuppHeat)) {
     170       138362 :             state.dataHeatingCoils->CoilIsSuppHeater = SuppHeat;
     171              :         } else {
     172        94798 :             state.dataHeatingCoils->CoilIsSuppHeater = false;
     173              :         }
     174              : 
     175       233160 :         if (present(fanOpMode)) {
     176       138934 :             fanOp = fanOpMode;
     177              :         } else {
     178        94226 :             fanOp = HVAC::FanOp::Continuous;
     179              :         }
     180              : 
     181       233160 :         if (present(PartLoadRatio)) {
     182        67273 :             PartLoadFrac = PartLoadRatio;
     183              :         } else {
     184       165887 :             PartLoadFrac = 1.0;
     185              :         }
     186              : 
     187       233160 :         if (present(QCoilReq)) {
     188       167678 :             QCoilRequired = QCoilReq;
     189              :         } else {
     190        65482 :             QCoilRequired = DataLoopNode::SensedLoadFlagValue;
     191              :         }
     192              : 
     193              :         // With the correct CoilNum Initialize
     194       233160 :         InitHeatingCoil(state, CoilNum, FirstHVACIteration, QCoilRequired); // Initialize all HeatingCoil related parameters
     195              : 
     196              :         // Calculate the Correct HeatingCoil Model with the current CoilNum
     197       233160 :         switch (state.dataHeatingCoils->HeatingCoil(CoilNum).HCoilType_Num) {
     198        73698 :         case HVAC::Coil_HeatingElectric: {
     199        73698 :             CalcElectricHeatingCoil(state, CoilNum, QCoilRequired, QCoilActual2, fanOp, PartLoadFrac);
     200        73698 :         } break;
     201          217 :         case HVAC::Coil_HeatingElectric_MultiStage: {
     202          217 :             CalcMultiStageElectricHeatingCoil(
     203              :                 state,
     204              :                 CoilNum,
     205              :                 SpeedRatio,
     206              :                 PartLoadRatio,
     207              :                 StageNum,
     208              :                 fanOp,
     209              :                 QCoilActual2,
     210          217 :                 state.dataHeatingCoils->CoilIsSuppHeater); // Autodesk:OPTIONAL SpeedRatio, PartLoadRatio, StageNum used without PRESENT check
     211          217 :         } break;
     212       159191 :         case HVAC::Coil_HeatingGasOrOtherFuel: {
     213       159191 :             CalcFuelHeatingCoil(state, CoilNum, QCoilRequired, QCoilActual2, fanOp, PartLoadFrac);
     214       159191 :         } break;
     215           50 :         case HVAC::Coil_HeatingGas_MultiStage: {
     216           50 :             CalcMultiStageGasHeatingCoil(state,
     217              :                                          CoilNum,
     218              :                                          SpeedRatio,
     219              :                                          PartLoadRatio,
     220              :                                          StageNum,
     221              :                                          fanOp); // Autodesk:OPTIONAL SpeedRatio, PartLoadRatio, StageNum used without PRESENT check
     222           50 :         } break;
     223            4 :         case HVAC::Coil_HeatingDesuperheater: {
     224            4 :             CalcDesuperheaterHeatingCoil(state, CoilNum, QCoilRequired, QCoilActual2);
     225            4 :         } break;
     226            0 :         default:
     227            0 :             QCoilActual2 = 0.0;
     228            0 :             break;
     229              :         }
     230              : 
     231              :         // Update the current HeatingCoil to the outlet nodes
     232       233160 :         UpdateHeatingCoil(state, CoilNum);
     233              : 
     234              :         // Report the current HeatingCoil
     235       233160 :         ReportHeatingCoil(state, CoilNum, state.dataHeatingCoils->CoilIsSuppHeater);
     236              : 
     237       233160 :         if (present(QCoilActual)) {
     238       126147 :             QCoilActual = QCoilActual2;
     239              :         }
     240       233160 :     }
     241              : 
     242          123 :     void GetHeatingCoilInput(EnergyPlusData &state)
     243              :     {
     244              : 
     245              :         // SUBROUTINE INFORMATION:
     246              :         //       AUTHOR         Richard Liesen
     247              :         //       DATE WRITTEN   May 2000
     248              : 
     249              :         // PURPOSE OF THIS SUBROUTINE:
     250              :         // Obtains input data for coils and stores it in coil data structures
     251              : 
     252              :         // METHODOLOGY EMPLOYED:
     253              :         // Uses "Get" routines to read in data.
     254              : 
     255              :         // SUBROUTINE PARAMETER DEFINITIONS:
     256              :         static constexpr std::string_view RoutineName = "GetHeatingCoilInput: "; // include trailing blank space
     257              :         static constexpr std::string_view routineName = "GetHeatingCoilInput";
     258              : 
     259              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     260          123 :         std::string CurrentModuleObject; // for ease in getting objects
     261          123 :         Array1D_string Alphas;           // Alpha input items for object
     262          123 :         Array1D_string cAlphaFields;     // Alpha field names
     263          123 :         Array1D_string cNumericFields;   // Numeric field names
     264          123 :         Array1D<Real64> Numbers;         // Numeric input items for object
     265          123 :         Array1D_bool lAlphaBlanks;       // Logical array, alpha field input BLANK = .TRUE.
     266          123 :         Array1D_bool lNumericBlanks;     // Logical array, numeric field input BLANK = .TRUE.
     267              :         int NumAlphas;
     268              :         int NumNums;
     269              :         int IOStat;
     270              :         int StageNum;
     271              :         bool DXCoilErrFlag; // Used in GetDXCoil mining functions
     272              :         bool errFlag;
     273              : 
     274          123 :         state.dataHeatingCoils->NumElecCoil = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Coil:Heating:Electric");
     275          246 :         state.dataHeatingCoils->NumElecCoilMultiStage =
     276          123 :             state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Coil:Heating:Electric:MultiStage");
     277          123 :         state.dataHeatingCoils->NumFuelCoil = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Coil:Heating:Fuel");
     278          246 :         state.dataHeatingCoils->NumGasCoilMultiStage =
     279          123 :             state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Coil:Heating:Gas:MultiStage");
     280          246 :         state.dataHeatingCoils->NumDesuperheaterCoil =
     281          123 :             state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Coil:Heating:Desuperheater");
     282          123 :         state.dataHeatingCoils->NumHeatingCoils = state.dataHeatingCoils->NumElecCoil + state.dataHeatingCoils->NumElecCoilMultiStage +
     283          123 :                                                   state.dataHeatingCoils->NumFuelCoil + state.dataHeatingCoils->NumGasCoilMultiStage +
     284          123 :                                                   state.dataHeatingCoils->NumDesuperheaterCoil;
     285          123 :         if (state.dataHeatingCoils->NumHeatingCoils > 0) {
     286          123 :             state.dataHeatingCoils->HeatingCoil.allocate(state.dataHeatingCoils->NumHeatingCoils);
     287          123 :             state.dataHeatingCoils->HeatingCoilNumericFields.allocate(state.dataHeatingCoils->NumHeatingCoils);
     288          123 :             state.dataHeatingCoils->ValidSourceType.dimension(state.dataHeatingCoils->NumHeatingCoils, false);
     289          123 :             state.dataHeatingCoils->CheckEquipName.dimension(state.dataHeatingCoils->NumHeatingCoils, true);
     290              :         }
     291              : 
     292          246 :         state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(
     293          123 :             state, "Coil:Heating:Electric", state.dataHeatingCoils->TotalArgs, NumAlphas, NumNums);
     294          123 :         state.dataHeatingCoils->MaxNums = max(state.dataHeatingCoils->MaxNums, NumNums);
     295          123 :         state.dataHeatingCoils->MaxAlphas = max(state.dataHeatingCoils->MaxAlphas, NumAlphas);
     296          246 :         state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(
     297          123 :             state, "Coil:Heating:Electric:MultiStage", state.dataHeatingCoils->TotalArgs, NumAlphas, NumNums);
     298          123 :         state.dataHeatingCoils->MaxNums = max(state.dataHeatingCoils->MaxNums, NumNums);
     299          123 :         state.dataHeatingCoils->MaxAlphas = max(state.dataHeatingCoils->MaxAlphas, NumAlphas);
     300          246 :         state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(
     301          123 :             state, "Coil:Heating:Fuel", state.dataHeatingCoils->TotalArgs, NumAlphas, NumNums);
     302          123 :         state.dataHeatingCoils->MaxNums = max(state.dataHeatingCoils->MaxNums, NumNums);
     303          123 :         state.dataHeatingCoils->MaxAlphas = max(state.dataHeatingCoils->MaxAlphas, NumAlphas);
     304          246 :         state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(
     305          123 :             state, "Coil:Heating:Gas:MultiStage", state.dataHeatingCoils->TotalArgs, NumAlphas, NumNums);
     306          123 :         state.dataHeatingCoils->MaxNums = max(state.dataHeatingCoils->MaxNums, NumNums);
     307          123 :         state.dataHeatingCoils->MaxAlphas = max(state.dataHeatingCoils->MaxAlphas, NumAlphas);
     308          246 :         state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(
     309          123 :             state, "Coil:Heating:Desuperheater", state.dataHeatingCoils->TotalArgs, NumAlphas, NumNums);
     310          123 :         state.dataHeatingCoils->MaxNums = max(state.dataHeatingCoils->MaxNums, NumNums);
     311          123 :         state.dataHeatingCoils->MaxAlphas = max(state.dataHeatingCoils->MaxAlphas, NumAlphas);
     312              : 
     313          123 :         Alphas.allocate(state.dataHeatingCoils->MaxAlphas);
     314          123 :         cAlphaFields.allocate(state.dataHeatingCoils->MaxAlphas);
     315          123 :         cNumericFields.allocate(state.dataHeatingCoils->MaxNums);
     316          123 :         Numbers.dimension(state.dataHeatingCoils->MaxNums, 0.0);
     317          123 :         lAlphaBlanks.dimension(state.dataHeatingCoils->MaxAlphas, true);
     318          123 :         lNumericBlanks.dimension(state.dataHeatingCoils->MaxNums, true);
     319              : 
     320              :         // Get the data for electric heating coils
     321          181 :         for (int ElecCoilNum = 1; ElecCoilNum <= state.dataHeatingCoils->NumElecCoil; ++ElecCoilNum) {
     322              : 
     323           58 :             auto &heatingCoil = state.dataHeatingCoils->HeatingCoil(ElecCoilNum);
     324           58 :             auto &heatingCoilNumericFields = state.dataHeatingCoils->HeatingCoilNumericFields(ElecCoilNum);
     325              : 
     326           58 :             CurrentModuleObject = "Coil:Heating:Electric";
     327           58 :             heatingCoil.FuelType = Constant::eFuel::Electricity;
     328              : 
     329           58 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
     330              :                                                                      CurrentModuleObject,
     331              :                                                                      ElecCoilNum,
     332              :                                                                      Alphas,
     333              :                                                                      NumAlphas,
     334              :                                                                      Numbers,
     335              :                                                                      NumNums,
     336              :                                                                      IOStat,
     337              :                                                                      lNumericBlanks,
     338              :                                                                      lAlphaBlanks,
     339              :                                                                      cAlphaFields,
     340              :                                                                      cNumericFields);
     341              : 
     342           58 :             ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)};
     343           58 :             heatingCoilNumericFields.FieldNames.allocate(state.dataHeatingCoils->MaxNums);
     344           58 :             heatingCoilNumericFields.FieldNames = cNumericFields;
     345              : 
     346              :             // InputErrorsFound will be set to True if problem was found, left untouched otherwise
     347           58 :             GlobalNames::VerifyUniqueCoilName(
     348           58 :                 state, CurrentModuleObject, Alphas(1), state.dataHeatingCoils->InputErrorsFound, CurrentModuleObject + " Name");
     349              : 
     350           58 :             heatingCoil.Name = Alphas(1);
     351           58 :             if (lAlphaBlanks(2)) {
     352           18 :                 heatingCoil.availSched = Sched::GetScheduleAlwaysOn(state);
     353           40 :             } else if ((heatingCoil.availSched = Sched::GetSchedule(state, Alphas(2))) == nullptr) {
     354            0 :                 ShowSevereItemNotFound(state, eoh, cAlphaFields(2), Alphas(2));
     355            0 :                 state.dataHeatingCoils->InputErrorsFound = true;
     356              :             }
     357              : 
     358           58 :             heatingCoil.HeatingCoilType = "Heating";
     359           58 :             heatingCoil.HeatingCoilModel = "Electric";
     360           58 :             heatingCoil.HCoilType_Num = HVAC::Coil_HeatingElectric;
     361              : 
     362           58 :             heatingCoil.Efficiency = Numbers(1);
     363           58 :             heatingCoil.NominalCapacity = Numbers(2);
     364           58 :             errFlag = false;
     365           58 :             heatingCoil.AirInletNodeNum = GetOnlySingleNode(state,
     366           58 :                                                             Alphas(3),
     367              :                                                             errFlag,
     368              :                                                             DataLoopNode::ConnectionObjectType::CoilHeatingElectric,
     369           58 :                                                             Alphas(1),
     370              :                                                             DataLoopNode::NodeFluidType::Air,
     371              :                                                             DataLoopNode::ConnectionType::Inlet,
     372              :                                                             NodeInputManager::CompFluidStream::Primary,
     373              :                                                             DataLoopNode::ObjectIsNotParent);
     374           58 :             state.dataHeatingCoils->InputErrorsFound = errFlag || state.dataHeatingCoils->InputErrorsFound;
     375           58 :             errFlag = false;
     376           58 :             heatingCoil.AirOutletNodeNum = GetOnlySingleNode(state,
     377           58 :                                                              Alphas(4),
     378              :                                                              errFlag,
     379              :                                                              DataLoopNode::ConnectionObjectType::CoilHeatingElectric,
     380           58 :                                                              Alphas(1),
     381              :                                                              DataLoopNode::NodeFluidType::Air,
     382              :                                                              DataLoopNode::ConnectionType::Outlet,
     383              :                                                              NodeInputManager::CompFluidStream::Primary,
     384              :                                                              DataLoopNode::ObjectIsNotParent);
     385           58 :             state.dataHeatingCoils->InputErrorsFound = errFlag || state.dataHeatingCoils->InputErrorsFound;
     386              : 
     387           58 :             BranchNodeConnections::TestCompSet(state, CurrentModuleObject, Alphas(1), Alphas(3), Alphas(4), "Air Nodes");
     388              : 
     389           58 :             errFlag = false;
     390           58 :             heatingCoil.TempSetPointNodeNum = GetOnlySingleNode(state,
     391           58 :                                                                 Alphas(5),
     392              :                                                                 errFlag,
     393              :                                                                 DataLoopNode::ConnectionObjectType::CoilHeatingElectric,
     394           58 :                                                                 Alphas(1),
     395              :                                                                 DataLoopNode::NodeFluidType::Air,
     396              :                                                                 DataLoopNode::ConnectionType::Sensor,
     397              :                                                                 NodeInputManager::CompFluidStream::Primary,
     398              :                                                                 DataLoopNode::ObjectIsNotParent);
     399           58 :             state.dataHeatingCoils->InputErrorsFound = errFlag || state.dataHeatingCoils->InputErrorsFound;
     400              : 
     401              :             // Setup Report variables for the Electric Coils
     402              :             // CurrentModuleObject = "Coil:Heating:Electric"
     403          116 :             SetupOutputVariable(state,
     404              :                                 "Heating Coil Heating Energy",
     405              :                                 Constant::Units::J,
     406           58 :                                 heatingCoil.HeatingCoilLoad,
     407              :                                 OutputProcessor::TimeStepType::System,
     408              :                                 OutputProcessor::StoreType::Sum,
     409           58 :                                 heatingCoil.Name,
     410              :                                 Constant::eResource::EnergyTransfer,
     411              :                                 OutputProcessor::Group::HVAC,
     412              :                                 OutputProcessor::EndUseCat::HeatingCoils);
     413          116 :             SetupOutputVariable(state,
     414              :                                 "Heating Coil Heating Rate",
     415              :                                 Constant::Units::W,
     416           58 :                                 heatingCoil.HeatingCoilRate,
     417              :                                 OutputProcessor::TimeStepType::System,
     418              :                                 OutputProcessor::StoreType::Average,
     419           58 :                                 heatingCoil.Name);
     420          116 :             SetupOutputVariable(state,
     421              :                                 "Heating Coil Electricity Energy",
     422              :                                 Constant::Units::J,
     423           58 :                                 heatingCoil.ElecUseLoad,
     424              :                                 OutputProcessor::TimeStepType::System,
     425              :                                 OutputProcessor::StoreType::Sum,
     426           58 :                                 heatingCoil.Name,
     427              :                                 Constant::eResource::Electricity,
     428              :                                 OutputProcessor::Group::HVAC,
     429              :                                 OutputProcessor::EndUseCat::Heating);
     430          116 :             SetupOutputVariable(state,
     431              :                                 "Heating Coil Electricity Rate",
     432              :                                 Constant::Units::W,
     433           58 :                                 heatingCoil.ElecUseRate,
     434              :                                 OutputProcessor::TimeStepType::System,
     435              :                                 OutputProcessor::StoreType::Average,
     436           58 :                                 heatingCoil.Name);
     437              :         }
     438              : 
     439              :         // Get the data for electric heating coils
     440          132 :         for (int ElecCoilNum = 1; ElecCoilNum <= state.dataHeatingCoils->NumElecCoilMultiStage; ++ElecCoilNum) {
     441              : 
     442            9 :             int CoilNum = state.dataHeatingCoils->NumElecCoil + ElecCoilNum;
     443            9 :             auto &heatingCoil = state.dataHeatingCoils->HeatingCoil(CoilNum);
     444            9 :             auto &heatingCoilNumericFields = state.dataHeatingCoils->HeatingCoilNumericFields(CoilNum);
     445              : 
     446            9 :             CurrentModuleObject = "Coil:Heating:Electric:MultiStage";
     447            9 :             heatingCoil.FuelType = Constant::eFuel::Electricity;
     448              : 
     449            9 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
     450              :                                                                      CurrentModuleObject,
     451              :                                                                      ElecCoilNum,
     452              :                                                                      Alphas,
     453              :                                                                      NumAlphas,
     454              :                                                                      Numbers,
     455              :                                                                      NumNums,
     456              :                                                                      IOStat,
     457              :                                                                      lNumericBlanks,
     458              :                                                                      lAlphaBlanks,
     459              :                                                                      cAlphaFields,
     460              :                                                                      cNumericFields);
     461              : 
     462            9 :             ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)};
     463            9 :             heatingCoilNumericFields.FieldNames.allocate(state.dataHeatingCoils->MaxNums);
     464            9 :             heatingCoilNumericFields.FieldNames = cNumericFields;
     465              : 
     466              :             // InputErrorsFound will be set to True if problem was found, left untouched otherwise
     467            9 :             GlobalNames::VerifyUniqueCoilName(
     468            9 :                 state, CurrentModuleObject, Alphas(1), state.dataHeatingCoils->InputErrorsFound, CurrentModuleObject + " Name");
     469            9 :             heatingCoil.Name = Alphas(1);
     470            9 :             if (lAlphaBlanks(2)) {
     471            0 :                 heatingCoil.availSched = Sched::GetScheduleAlwaysOn(state);
     472            9 :             } else if ((heatingCoil.availSched = Sched::GetSchedule(state, Alphas(2))) == nullptr) {
     473            0 :                 ShowSevereItemNotFound(state, eoh, cAlphaFields(2), Alphas(2));
     474            0 :                 state.dataHeatingCoils->InputErrorsFound = true;
     475              :             }
     476              : 
     477            9 :             heatingCoil.HeatingCoilType = "Heating";
     478            9 :             heatingCoil.HeatingCoilModel = "Electric:MultiStage";
     479            9 :             heatingCoil.HCoilType_Num = HVAC::Coil_HeatingElectric_MultiStage;
     480              : 
     481            9 :             heatingCoil.NumOfStages = static_cast<int>(Numbers(1));
     482              : 
     483            9 :             heatingCoil.MSEfficiency.allocate(heatingCoil.NumOfStages);
     484            9 :             heatingCoil.MSNominalCapacity.allocate(heatingCoil.NumOfStages);
     485              : 
     486           27 :             for (StageNum = 1; StageNum <= heatingCoil.NumOfStages; ++StageNum) {
     487              : 
     488           18 :                 heatingCoil.MSEfficiency(StageNum) = Numbers(StageNum * 2);
     489           18 :                 heatingCoil.MSNominalCapacity(StageNum) = Numbers(StageNum * 2 + 1);
     490              :             }
     491              : 
     492            9 :             errFlag = false;
     493            9 :             heatingCoil.AirInletNodeNum = GetOnlySingleNode(state,
     494            9 :                                                             Alphas(3),
     495              :                                                             errFlag,
     496              :                                                             DataLoopNode::ConnectionObjectType::CoilHeatingElectricMultiStage,
     497            9 :                                                             Alphas(1),
     498              :                                                             DataLoopNode::NodeFluidType::Air,
     499              :                                                             DataLoopNode::ConnectionType::Inlet,
     500              :                                                             NodeInputManager::CompFluidStream::Primary,
     501              :                                                             DataLoopNode::ObjectIsNotParent);
     502            9 :             state.dataHeatingCoils->InputErrorsFound = errFlag || state.dataHeatingCoils->InputErrorsFound;
     503            9 :             errFlag = false;
     504            9 :             heatingCoil.AirOutletNodeNum = GetOnlySingleNode(state,
     505            9 :                                                              Alphas(4),
     506              :                                                              errFlag,
     507              :                                                              DataLoopNode::ConnectionObjectType::CoilHeatingElectricMultiStage,
     508            9 :                                                              Alphas(1),
     509              :                                                              DataLoopNode::NodeFluidType::Air,
     510              :                                                              DataLoopNode::ConnectionType::Outlet,
     511              :                                                              NodeInputManager::CompFluidStream::Primary,
     512              :                                                              DataLoopNode::ObjectIsNotParent);
     513            9 :             state.dataHeatingCoils->InputErrorsFound = errFlag || state.dataHeatingCoils->InputErrorsFound;
     514              : 
     515            9 :             BranchNodeConnections::TestCompSet(state, CurrentModuleObject, Alphas(1), Alphas(3), Alphas(4), "Air Nodes");
     516              : 
     517            9 :             errFlag = false;
     518            9 :             heatingCoil.TempSetPointNodeNum = GetOnlySingleNode(state,
     519            9 :                                                                 Alphas(5),
     520              :                                                                 errFlag,
     521              :                                                                 DataLoopNode::ConnectionObjectType::CoilHeatingElectricMultiStage,
     522            9 :                                                                 Alphas(1),
     523              :                                                                 DataLoopNode::NodeFluidType::Air,
     524              :                                                                 DataLoopNode::ConnectionType::Sensor,
     525              :                                                                 NodeInputManager::CompFluidStream::Primary,
     526              :                                                                 DataLoopNode::ObjectIsNotParent);
     527            9 :             state.dataHeatingCoils->InputErrorsFound = errFlag || state.dataHeatingCoils->InputErrorsFound;
     528              : 
     529              :             // Setup Report variables for the Electric Coils
     530              :             // CurrentModuleObject = "Coil:Heating:Electric:MultiStage"
     531           18 :             SetupOutputVariable(state,
     532              :                                 "Heating Coil Heating Energy",
     533              :                                 Constant::Units::J,
     534            9 :                                 heatingCoil.HeatingCoilLoad,
     535              :                                 OutputProcessor::TimeStepType::System,
     536              :                                 OutputProcessor::StoreType::Sum,
     537            9 :                                 heatingCoil.Name,
     538              :                                 Constant::eResource::EnergyTransfer,
     539              :                                 OutputProcessor::Group::HVAC,
     540              :                                 OutputProcessor::EndUseCat::HeatingCoils);
     541           18 :             SetupOutputVariable(state,
     542              :                                 "Heating Coil Heating Rate",
     543              :                                 Constant::Units::W,
     544            9 :                                 heatingCoil.HeatingCoilRate,
     545              :                                 OutputProcessor::TimeStepType::System,
     546              :                                 OutputProcessor::StoreType::Average,
     547            9 :                                 heatingCoil.Name);
     548           18 :             SetupOutputVariable(state,
     549              :                                 "Heating Coil Electricity Energy",
     550              :                                 Constant::Units::J,
     551            9 :                                 heatingCoil.ElecUseLoad,
     552              :                                 OutputProcessor::TimeStepType::System,
     553              :                                 OutputProcessor::StoreType::Sum,
     554            9 :                                 heatingCoil.Name,
     555              :                                 Constant::eResource::Electricity,
     556              :                                 OutputProcessor::Group::HVAC,
     557              :                                 OutputProcessor::EndUseCat::Heating);
     558           18 :             SetupOutputVariable(state,
     559              :                                 "Heating Coil Electricity Rate",
     560              :                                 Constant::Units::W,
     561            9 :                                 heatingCoil.ElecUseRate,
     562              :                                 OutputProcessor::TimeStepType::System,
     563              :                                 OutputProcessor::StoreType::Average,
     564            9 :                                 heatingCoil.Name);
     565              :         }
     566              : 
     567              :         // Get the data for for fuel heating coils
     568          230 :         for (int FuelCoilNum = 1; FuelCoilNum <= state.dataHeatingCoils->NumFuelCoil; ++FuelCoilNum) {
     569              : 
     570          107 :             int CoilNum = state.dataHeatingCoils->NumElecCoil + state.dataHeatingCoils->NumElecCoilMultiStage + FuelCoilNum;
     571          107 :             auto &heatingCoil = state.dataHeatingCoils->HeatingCoil(CoilNum);
     572          107 :             auto &heatingCoilNumericFields = state.dataHeatingCoils->HeatingCoilNumericFields(CoilNum);
     573              : 
     574          107 :             CurrentModuleObject = "Coil:Heating:Fuel";
     575              : 
     576          107 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
     577              :                                                                      CurrentModuleObject,
     578              :                                                                      FuelCoilNum,
     579              :                                                                      Alphas,
     580              :                                                                      NumAlphas,
     581              :                                                                      Numbers,
     582              :                                                                      NumNums,
     583              :                                                                      IOStat,
     584              :                                                                      lNumericBlanks,
     585              :                                                                      lAlphaBlanks,
     586              :                                                                      cAlphaFields,
     587              :                                                                      cNumericFields);
     588              : 
     589          107 :             ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)};
     590          107 :             heatingCoilNumericFields.FieldNames.allocate(state.dataHeatingCoils->MaxNums);
     591          107 :             heatingCoilNumericFields.FieldNames = cNumericFields;
     592              : 
     593              :             // InputErrorsFound will be set to True if problem was found, left untouched otherwise
     594          107 :             GlobalNames::VerifyUniqueCoilName(
     595          107 :                 state, CurrentModuleObject, Alphas(1), state.dataHeatingCoils->InputErrorsFound, CurrentModuleObject + " Name");
     596          107 :             heatingCoil.Name = Alphas(1);
     597          107 :             if (lAlphaBlanks(2)) {
     598           13 :                 heatingCoil.availSched = Sched::GetScheduleAlwaysOn(state);
     599           94 :             } else if ((heatingCoil.availSched = Sched::GetSchedule(state, Alphas(2))) == nullptr) {
     600            0 :                 ShowSevereItemNotFound(state, eoh, cAlphaFields(2), Alphas(2));
     601            0 :                 state.dataHeatingCoils->InputErrorsFound = true;
     602              :             }
     603              : 
     604          107 :             heatingCoil.HeatingCoilType = "Heating";
     605          107 :             heatingCoil.HeatingCoilModel = "Fuel";
     606          107 :             heatingCoil.HCoilType_Num = HVAC::Coil_HeatingGasOrOtherFuel;
     607              : 
     608          107 :             heatingCoil.FuelType = static_cast<Constant::eFuel>(getEnumValue(Constant::eFuelNamesUC, Alphas(3)));
     609          107 :             if (!(heatingCoil.FuelType == Constant::eFuel::NaturalGas || heatingCoil.FuelType == Constant::eFuel::Propane ||
     610            3 :                   heatingCoil.FuelType == Constant::eFuel::Diesel || heatingCoil.FuelType == Constant::eFuel::Gasoline ||
     611            3 :                   heatingCoil.FuelType == Constant::eFuel::FuelOilNo1 || heatingCoil.FuelType == Constant::eFuel::FuelOilNo2 ||
     612            3 :                   heatingCoil.FuelType == Constant::eFuel::OtherFuel1 || heatingCoil.FuelType == Constant::eFuel::OtherFuel2 ||
     613            2 :                   heatingCoil.FuelType == Constant::eFuel::Coal)) {
     614            2 :                 ShowSevereError(state,
     615            2 :                                 format("{}{}: Invalid {} entered ={} for {}={}",
     616              :                                        RoutineName,
     617              :                                        CurrentModuleObject,
     618              :                                        cAlphaFields(3),
     619              :                                        Alphas(3),
     620              :                                        cAlphaFields(1),
     621              :                                        Alphas(1)));
     622            1 :                 state.dataHeatingCoils->InputErrorsFound = true;
     623              :             }
     624          107 :             std::string const sFuelType(Constant::eFuelNames[static_cast<int>(heatingCoil.FuelType)]);
     625              : 
     626          107 :             heatingCoil.Efficiency = Numbers(1);
     627          107 :             heatingCoil.NominalCapacity = Numbers(2);
     628          107 :             errFlag = false;
     629          107 :             heatingCoil.AirInletNodeNum = GetOnlySingleNode(state,
     630          107 :                                                             Alphas(4),
     631              :                                                             errFlag,
     632              :                                                             DataLoopNode::ConnectionObjectType::CoilHeatingFuel,
     633          107 :                                                             Alphas(1),
     634              :                                                             DataLoopNode::NodeFluidType::Air,
     635              :                                                             DataLoopNode::ConnectionType::Inlet,
     636              :                                                             NodeInputManager::CompFluidStream::Primary,
     637              :                                                             DataLoopNode::ObjectIsNotParent);
     638          107 :             state.dataHeatingCoils->InputErrorsFound = errFlag || state.dataHeatingCoils->InputErrorsFound;
     639          107 :             errFlag = false;
     640          107 :             heatingCoil.AirOutletNodeNum = GetOnlySingleNode(state,
     641          107 :                                                              Alphas(5),
     642              :                                                              errFlag,
     643              :                                                              DataLoopNode::ConnectionObjectType::CoilHeatingFuel,
     644          107 :                                                              Alphas(1),
     645              :                                                              DataLoopNode::NodeFluidType::Air,
     646              :                                                              DataLoopNode::ConnectionType::Outlet,
     647              :                                                              NodeInputManager::CompFluidStream::Primary,
     648              :                                                              DataLoopNode::ObjectIsNotParent);
     649          107 :             state.dataHeatingCoils->InputErrorsFound = errFlag || state.dataHeatingCoils->InputErrorsFound;
     650              : 
     651          107 :             BranchNodeConnections::TestCompSet(state, CurrentModuleObject, Alphas(1), Alphas(4), Alphas(5), "Air Nodes");
     652              : 
     653          107 :             errFlag = false;
     654          107 :             heatingCoil.TempSetPointNodeNum = GetOnlySingleNode(state,
     655          107 :                                                                 Alphas(6),
     656              :                                                                 errFlag,
     657              :                                                                 DataLoopNode::ConnectionObjectType::CoilHeatingFuel,
     658          107 :                                                                 Alphas(1),
     659              :                                                                 DataLoopNode::NodeFluidType::Air,
     660              :                                                                 DataLoopNode::ConnectionType::Sensor,
     661              :                                                                 NodeInputManager::CompFluidStream::Primary,
     662              :                                                                 DataLoopNode::ObjectIsNotParent);
     663          107 :             state.dataHeatingCoils->InputErrorsFound = errFlag || state.dataHeatingCoils->InputErrorsFound;
     664              : 
     665              :             // parasitic electric load associated with the fuel heating coil
     666          107 :             heatingCoil.ParasiticElecLoad = Numbers(3);
     667              : 
     668          107 :             heatingCoil.PLFCurveIndex = Curve::GetCurveIndex(state, Alphas(7)); // convert curve name to number
     669              : 
     670              :             // parasitic fuel load associated with the gas heating coil (standing pilot light)
     671          107 :             heatingCoil.ParasiticFuelCapacity = Numbers(4);
     672              : 
     673              :             // Setup Report variables for the Fuel Coils
     674              :             // CurrentModuleObject = "Coil:Heating:OtherFuel"
     675              : 
     676          214 :             SetupOutputVariable(state,
     677              :                                 "Heating Coil Heating Energy",
     678              :                                 Constant::Units::J,
     679          107 :                                 heatingCoil.HeatingCoilLoad,
     680              :                                 OutputProcessor::TimeStepType::System,
     681              :                                 OutputProcessor::StoreType::Sum,
     682          107 :                                 heatingCoil.Name,
     683              :                                 Constant::eResource::EnergyTransfer,
     684              :                                 OutputProcessor::Group::HVAC,
     685              :                                 OutputProcessor::EndUseCat::HeatingCoils);
     686          214 :             SetupOutputVariable(state,
     687              :                                 "Heating Coil Heating Rate",
     688              :                                 Constant::Units::W,
     689          107 :                                 heatingCoil.HeatingCoilRate,
     690              :                                 OutputProcessor::TimeStepType::System,
     691              :                                 OutputProcessor::StoreType::Average,
     692          107 :                                 heatingCoil.Name);
     693          321 :             SetupOutputVariable(state,
     694          214 :                                 format("Heating Coil {} Energy", sFuelType),
     695              :                                 Constant::Units::J,
     696          107 :                                 heatingCoil.FuelUseLoad,
     697              :                                 OutputProcessor::TimeStepType::System,
     698              :                                 OutputProcessor::StoreType::Sum,
     699          107 :                                 heatingCoil.Name,
     700          107 :                                 Constant::eFuel2eResource[(int)heatingCoil.FuelType],
     701              :                                 OutputProcessor::Group::HVAC,
     702              :                                 OutputProcessor::EndUseCat::Heating);
     703          321 :             SetupOutputVariable(state,
     704          214 :                                 format("Heating Coil {} Rate", sFuelType),
     705              :                                 Constant::Units::W,
     706          107 :                                 heatingCoil.FuelUseRate,
     707              :                                 OutputProcessor::TimeStepType::System,
     708              :                                 OutputProcessor::StoreType::Average,
     709          107 :                                 heatingCoil.Name);
     710          214 :             SetupOutputVariable(state,
     711              :                                 "Heating Coil Electricity Energy",
     712              :                                 Constant::Units::J,
     713          107 :                                 heatingCoil.ElecUseLoad,
     714              :                                 OutputProcessor::TimeStepType::System,
     715              :                                 OutputProcessor::StoreType::Sum,
     716          107 :                                 heatingCoil.Name,
     717              :                                 Constant::eResource::Electricity,
     718              :                                 OutputProcessor::Group::HVAC,
     719              :                                 OutputProcessor::EndUseCat::Heating);
     720          214 :             SetupOutputVariable(state,
     721              :                                 "Heating Coil Electricity Rate",
     722              :                                 Constant::Units::W,
     723          107 :                                 heatingCoil.ElecUseRate,
     724              :                                 OutputProcessor::TimeStepType::System,
     725              :                                 OutputProcessor::StoreType::Average,
     726          107 :                                 heatingCoil.Name);
     727          214 :             SetupOutputVariable(state,
     728              :                                 "Heating Coil Runtime Fraction",
     729              :                                 Constant::Units::None,
     730          107 :                                 heatingCoil.RTF,
     731              :                                 OutputProcessor::TimeStepType::System,
     732              :                                 OutputProcessor::StoreType::Average,
     733          107 :                                 heatingCoil.Name);
     734          321 :             SetupOutputVariable(state,
     735          214 :                                 "Heating Coil Ancillary " + sFuelType + " Rate",
     736              :                                 Constant::Units::W,
     737          107 :                                 heatingCoil.ParasiticFuelRate,
     738              :                                 OutputProcessor::TimeStepType::System,
     739              :                                 OutputProcessor::StoreType::Average,
     740          107 :                                 heatingCoil.Name);
     741          321 :             SetupOutputVariable(state,
     742          214 :                                 "Heating Coil Ancillary " + sFuelType + " Energy",
     743              :                                 Constant::Units::J,
     744          107 :                                 heatingCoil.ParasiticFuelConsumption,
     745              :                                 OutputProcessor::TimeStepType::System,
     746              :                                 OutputProcessor::StoreType::Sum,
     747          107 :                                 heatingCoil.Name,
     748          107 :                                 Constant::eFuel2eResource[(int)heatingCoil.FuelType],
     749              :                                 OutputProcessor::Group::HVAC,
     750              :                                 OutputProcessor::EndUseCat::Heating);
     751          107 :         }
     752              : 
     753              :         // Get the data for for gas multistage heating coils
     754          126 :         for (int FuelCoilNum = 1; FuelCoilNum <= state.dataHeatingCoils->NumGasCoilMultiStage; ++FuelCoilNum) {
     755              : 
     756            3 :             int CoilNum = state.dataHeatingCoils->NumElecCoil + state.dataHeatingCoils->NumElecCoilMultiStage + state.dataHeatingCoils->NumFuelCoil +
     757            3 :                           FuelCoilNum;
     758            3 :             auto &heatingCoil = state.dataHeatingCoils->HeatingCoil(CoilNum);
     759            3 :             auto &heatingCoilNumericFields = state.dataHeatingCoils->HeatingCoilNumericFields(CoilNum);
     760            3 :             CurrentModuleObject = "Coil:Heating:Gas:MultiStage";
     761            3 :             heatingCoil.FuelType = Constant::eFuel::NaturalGas;
     762              : 
     763            3 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
     764              :                                                                      CurrentModuleObject,
     765              :                                                                      FuelCoilNum,
     766              :                                                                      Alphas,
     767              :                                                                      NumAlphas,
     768              :                                                                      Numbers,
     769              :                                                                      NumNums,
     770              :                                                                      IOStat,
     771              :                                                                      lNumericBlanks,
     772              :                                                                      lAlphaBlanks,
     773              :                                                                      cAlphaFields,
     774              :                                                                      cNumericFields);
     775              : 
     776            3 :             ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)};
     777              : 
     778            3 :             heatingCoilNumericFields.FieldNames.allocate(state.dataHeatingCoils->MaxNums);
     779            3 :             heatingCoilNumericFields.FieldNames = cNumericFields;
     780              : 
     781              :             // InputErrorsFound will be set to True if problem was found, left untouched otherwise
     782            3 :             GlobalNames::VerifyUniqueCoilName(
     783            3 :                 state, CurrentModuleObject, Alphas(1), state.dataHeatingCoils->InputErrorsFound, CurrentModuleObject + " Name");
     784            3 :             heatingCoil.Name = Alphas(1);
     785              : 
     786            3 :             if (lAlphaBlanks(2)) {
     787            0 :                 heatingCoil.availSched = Sched::GetScheduleAlwaysOn(state);
     788            3 :             } else if ((heatingCoil.availSched = Sched::GetSchedule(state, Alphas(2))) == nullptr) {
     789            0 :                 ShowSevereItemNotFound(state, eoh, cAlphaFields(2), Alphas(2));
     790            0 :                 state.dataHeatingCoils->InputErrorsFound = true;
     791              :             }
     792              : 
     793            3 :             heatingCoil.HeatingCoilType = "Heating";
     794            3 :             heatingCoil.HeatingCoilModel = "Gas:MultiStage";
     795            3 :             heatingCoil.HCoilType_Num = HVAC::Coil_HeatingGas_MultiStage;
     796              : 
     797            3 :             heatingCoil.ParasiticFuelCapacity = Numbers(1);
     798              : 
     799            3 :             heatingCoil.NumOfStages = static_cast<int>(Numbers(2));
     800              : 
     801            3 :             heatingCoil.MSEfficiency.allocate(heatingCoil.NumOfStages);
     802            3 :             heatingCoil.MSNominalCapacity.allocate(heatingCoil.NumOfStages);
     803            3 :             heatingCoil.MSParasiticElecLoad.allocate(heatingCoil.NumOfStages);
     804              : 
     805            8 :             for (StageNum = 1; StageNum <= heatingCoil.NumOfStages; ++StageNum) {
     806              : 
     807            5 :                 heatingCoil.MSEfficiency(StageNum) = Numbers(StageNum * 3);
     808            5 :                 heatingCoil.MSNominalCapacity(StageNum) = Numbers(StageNum * 3 + 1);
     809            5 :                 heatingCoil.MSParasiticElecLoad(StageNum) = Numbers(StageNum * 3 + 2);
     810              :             }
     811              : 
     812            3 :             errFlag = false;
     813            3 :             heatingCoil.AirInletNodeNum = GetOnlySingleNode(state,
     814            3 :                                                             Alphas(3),
     815              :                                                             errFlag,
     816              :                                                             DataLoopNode::ConnectionObjectType::CoilHeatingGasMultiStage,
     817            3 :                                                             Alphas(1),
     818              :                                                             DataLoopNode::NodeFluidType::Air,
     819              :                                                             DataLoopNode::ConnectionType::Inlet,
     820              :                                                             NodeInputManager::CompFluidStream::Primary,
     821              :                                                             DataLoopNode::ObjectIsNotParent);
     822            3 :             state.dataHeatingCoils->InputErrorsFound = errFlag || state.dataHeatingCoils->InputErrorsFound;
     823            3 :             errFlag = false;
     824            3 :             heatingCoil.AirOutletNodeNum = GetOnlySingleNode(state,
     825            3 :                                                              Alphas(4),
     826              :                                                              errFlag,
     827              :                                                              DataLoopNode::ConnectionObjectType::CoilHeatingGasMultiStage,
     828            3 :                                                              Alphas(1),
     829              :                                                              DataLoopNode::NodeFluidType::Air,
     830              :                                                              DataLoopNode::ConnectionType::Outlet,
     831              :                                                              NodeInputManager::CompFluidStream::Primary,
     832              :                                                              DataLoopNode::ObjectIsNotParent);
     833            3 :             state.dataHeatingCoils->InputErrorsFound = errFlag || state.dataHeatingCoils->InputErrorsFound;
     834              : 
     835            3 :             BranchNodeConnections::TestCompSet(state, CurrentModuleObject, Alphas(1), Alphas(3), Alphas(4), "Air Nodes");
     836              : 
     837            3 :             errFlag = false;
     838            3 :             heatingCoil.TempSetPointNodeNum = GetOnlySingleNode(state,
     839            3 :                                                                 Alphas(5),
     840              :                                                                 errFlag,
     841              :                                                                 DataLoopNode::ConnectionObjectType::CoilHeatingGasMultiStage,
     842            3 :                                                                 Alphas(1),
     843              :                                                                 DataLoopNode::NodeFluidType::Air,
     844              :                                                                 DataLoopNode::ConnectionType::Sensor,
     845              :                                                                 NodeInputManager::CompFluidStream::Primary,
     846              :                                                                 DataLoopNode::ObjectIsNotParent);
     847            3 :             state.dataHeatingCoils->InputErrorsFound = errFlag || state.dataHeatingCoils->InputErrorsFound;
     848              : 
     849              :             // parasitic electric load associated with the gas heating coil
     850            3 :             heatingCoil.ParasiticElecLoad = Numbers(10);
     851              : 
     852            3 :             heatingCoil.PLFCurveIndex = Curve::GetCurveIndex(state, Alphas(6)); // convert curve name to number
     853              : 
     854              :             // parasitic gas load associated with the gas heating coil (standing pilot light)
     855              : 
     856              :             // Setup Report variables for the Gas Coils
     857              :             // CurrentModuleObject = "Coil:Heating:Gas:MultiStage"
     858            6 :             SetupOutputVariable(state,
     859              :                                 "Heating Coil Heating Energy",
     860              :                                 Constant::Units::J,
     861            3 :                                 heatingCoil.HeatingCoilLoad,
     862              :                                 OutputProcessor::TimeStepType::System,
     863              :                                 OutputProcessor::StoreType::Sum,
     864            3 :                                 heatingCoil.Name,
     865              :                                 Constant::eResource::EnergyTransfer,
     866              :                                 OutputProcessor::Group::HVAC,
     867              :                                 OutputProcessor::EndUseCat::HeatingCoils);
     868            6 :             SetupOutputVariable(state,
     869              :                                 "Heating Coil Heating Rate",
     870              :                                 Constant::Units::W,
     871            3 :                                 heatingCoil.HeatingCoilRate,
     872              :                                 OutputProcessor::TimeStepType::System,
     873              :                                 OutputProcessor::StoreType::Average,
     874            3 :                                 heatingCoil.Name);
     875            6 :             SetupOutputVariable(state,
     876              :                                 "Heating Coil NaturalGas Energy",
     877              :                                 Constant::Units::J,
     878            3 :                                 heatingCoil.FuelUseLoad,
     879              :                                 OutputProcessor::TimeStepType::System,
     880              :                                 OutputProcessor::StoreType::Sum,
     881            3 :                                 heatingCoil.Name,
     882              :                                 Constant::eResource::NaturalGas,
     883              :                                 OutputProcessor::Group::HVAC,
     884              :                                 OutputProcessor::EndUseCat::Heating);
     885            6 :             SetupOutputVariable(state,
     886              :                                 "Heating Coil NaturalGas Rate",
     887              :                                 Constant::Units::W,
     888            3 :                                 heatingCoil.FuelUseRate,
     889              :                                 OutputProcessor::TimeStepType::System,
     890              :                                 OutputProcessor::StoreType::Average,
     891            3 :                                 heatingCoil.Name);
     892            6 :             SetupOutputVariable(state,
     893              :                                 "Heating Coil Electricity Energy",
     894              :                                 Constant::Units::J,
     895            3 :                                 heatingCoil.ElecUseLoad,
     896              :                                 OutputProcessor::TimeStepType::System,
     897              :                                 OutputProcessor::StoreType::Sum,
     898            3 :                                 heatingCoil.Name,
     899              :                                 Constant::eResource::Electricity,
     900              :                                 OutputProcessor::Group::HVAC,
     901              :                                 OutputProcessor::EndUseCat::Heating);
     902            6 :             SetupOutputVariable(state,
     903              :                                 "Heating Coil Electricity Rate",
     904              :                                 Constant::Units::W,
     905            3 :                                 heatingCoil.ElecUseRate,
     906              :                                 OutputProcessor::TimeStepType::System,
     907              :                                 OutputProcessor::StoreType::Average,
     908            3 :                                 heatingCoil.Name);
     909            6 :             SetupOutputVariable(state,
     910              :                                 "Heating Coil Runtime Fraction",
     911              :                                 Constant::Units::None,
     912            3 :                                 heatingCoil.RTF,
     913              :                                 OutputProcessor::TimeStepType::System,
     914              :                                 OutputProcessor::StoreType::Average,
     915            3 :                                 heatingCoil.Name);
     916            6 :             SetupOutputVariable(state,
     917              :                                 "Heating Coil Ancillary NaturalGas Rate",
     918              :                                 Constant::Units::W,
     919            3 :                                 heatingCoil.ParasiticFuelRate,
     920              :                                 OutputProcessor::TimeStepType::System,
     921              :                                 OutputProcessor::StoreType::Average,
     922            3 :                                 heatingCoil.Name);
     923            6 :             SetupOutputVariable(state,
     924              :                                 "Heating Coil Ancillary NaturalGas Energy",
     925              :                                 Constant::Units::J,
     926            3 :                                 heatingCoil.ParasiticFuelConsumption,
     927              :                                 OutputProcessor::TimeStepType::System,
     928              :                                 OutputProcessor::StoreType::Sum,
     929            3 :                                 heatingCoil.Name,
     930              :                                 Constant::eResource::NaturalGas,
     931              :                                 OutputProcessor::Group::HVAC,
     932              :                                 OutputProcessor::EndUseCat::Heating);
     933              :         }
     934              : 
     935              :         // Get the data for for desuperheater heating coils
     936          124 :         for (int DesuperheaterCoilNum = 1; DesuperheaterCoilNum <= state.dataHeatingCoils->NumDesuperheaterCoil; ++DesuperheaterCoilNum) {
     937              : 
     938            1 :             int CoilNum = state.dataHeatingCoils->NumElecCoil + state.dataHeatingCoils->NumElecCoilMultiStage + state.dataHeatingCoils->NumFuelCoil +
     939            1 :                           state.dataHeatingCoils->NumGasCoilMultiStage + DesuperheaterCoilNum;
     940            1 :             auto &heatingCoil = state.dataHeatingCoils->HeatingCoil(CoilNum);
     941            1 :             auto &heatingCoilNumericFields = state.dataHeatingCoils->HeatingCoilNumericFields(CoilNum);
     942            1 :             CurrentModuleObject = "Coil:Heating:Desuperheater";
     943            1 :             heatingCoil.FuelType = Constant::eFuel::Electricity;
     944              : 
     945            1 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
     946              :                                                                      CurrentModuleObject,
     947              :                                                                      DesuperheaterCoilNum,
     948              :                                                                      Alphas,
     949              :                                                                      NumAlphas,
     950              :                                                                      Numbers,
     951              :                                                                      NumNums,
     952              :                                                                      IOStat,
     953              :                                                                      lNumericBlanks,
     954              :                                                                      lAlphaBlanks,
     955              :                                                                      cAlphaFields,
     956              :                                                                      cNumericFields);
     957              : 
     958            1 :             ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)};
     959            1 :             heatingCoilNumericFields.FieldNames.allocate(state.dataHeatingCoils->MaxNums);
     960            1 :             heatingCoilNumericFields.FieldNames = cNumericFields;
     961              : 
     962              :             // InputErrorsFound will be set to True if problem was found, left untouched otherwise
     963            1 :             GlobalNames::VerifyUniqueCoilName(
     964            1 :                 state, CurrentModuleObject, Alphas(1), state.dataHeatingCoils->InputErrorsFound, CurrentModuleObject + " Name");
     965            1 :             heatingCoil.Name = Alphas(1);
     966            1 :             if (lAlphaBlanks(2)) {
     967            0 :                 heatingCoil.availSched = Sched::GetScheduleAlwaysOn(state);
     968            1 :             } else if ((heatingCoil.availSched = Sched::GetSchedule(state, Alphas(2))) == nullptr) {
     969            0 :                 ShowSevereItemNotFound(state, eoh, cAlphaFields(2), Alphas(2));
     970            0 :                 state.dataHeatingCoils->InputErrorsFound = true;
     971            1 :             } else if (!heatingCoil.availSched->checkMinMaxVals(state, Clusive::In, 0.0, Clusive::In, 1.0)) {
     972            0 :                 Sched::ShowSevereBadMinMax(state, eoh, cAlphaFields(2), Alphas(2), Clusive::In, 0.0, Clusive::In, 1.0);
     973            0 :                 state.dataHeatingCoils->InputErrorsFound = true;
     974              :             }
     975              : 
     976            1 :             heatingCoil.HeatingCoilType = "Heating";
     977            1 :             heatingCoil.HeatingCoilModel = "Desuperheater";
     978            1 :             heatingCoil.HCoilType_Num = HVAC::Coil_HeatingDesuperheater;
     979              : 
     980              :             // HeatingCoil(CoilNum)%Efficiency       = Numbers(1)
     981              :             //(Numbers(1)) error limits checked and defaults applied on efficiency after
     982              :             //       identifying souce type.
     983              : 
     984            1 :             errFlag = false;
     985            1 :             heatingCoil.AirInletNodeNum = GetOnlySingleNode(state,
     986            1 :                                                             Alphas(3),
     987              :                                                             errFlag,
     988              :                                                             DataLoopNode::ConnectionObjectType::CoilHeatingDesuperheater,
     989            1 :                                                             Alphas(1),
     990              :                                                             DataLoopNode::NodeFluidType::Air,
     991              :                                                             DataLoopNode::ConnectionType::Inlet,
     992              :                                                             NodeInputManager::CompFluidStream::Primary,
     993              :                                                             DataLoopNode::ObjectIsNotParent);
     994            1 :             state.dataHeatingCoils->InputErrorsFound = errFlag || state.dataHeatingCoils->InputErrorsFound;
     995            1 :             errFlag = false;
     996            1 :             heatingCoil.AirOutletNodeNum = GetOnlySingleNode(state,
     997            1 :                                                              Alphas(4),
     998              :                                                              errFlag,
     999              :                                                              DataLoopNode::ConnectionObjectType::CoilHeatingDesuperheater,
    1000            1 :                                                              Alphas(1),
    1001              :                                                              DataLoopNode::NodeFluidType::Air,
    1002              :                                                              DataLoopNode::ConnectionType::Outlet,
    1003              :                                                              NodeInputManager::CompFluidStream::Primary,
    1004              :                                                              DataLoopNode::ObjectIsNotParent);
    1005            1 :             state.dataHeatingCoils->InputErrorsFound = errFlag || state.dataHeatingCoils->InputErrorsFound;
    1006              : 
    1007            1 :             BranchNodeConnections::TestCompSet(state, CurrentModuleObject, Alphas(1), Alphas(3), Alphas(4), "Air Nodes");
    1008              : 
    1009            2 :             if ((Util::SameString(Alphas(5), "Refrigeration:Condenser:AirCooled")) ||
    1010            2 :                 (Util::SameString(Alphas(5), "Refrigeration:Condenser:EvaporativeCooled")) ||
    1011            2 :                 (Util::SameString(Alphas(5), "Refrigeration:Condenser:WaterCooled"))) {
    1012            0 :                 if (lNumericBlanks(1)) {
    1013            0 :                     heatingCoil.Efficiency = 0.8;
    1014              :                 } else {
    1015            0 :                     heatingCoil.Efficiency = Numbers(1);
    1016            0 :                     if (Numbers(1) < 0.0 || Numbers(1) > 0.9) {
    1017            0 :                         ShowSevereError(
    1018              :                             state,
    1019            0 :                             format("{}, \"{}\" heat reclaim recovery efficiency must be >= 0 and <=0.9", CurrentModuleObject, heatingCoil.Name));
    1020            0 :                         state.dataHeatingCoils->InputErrorsFound = true;
    1021              :                     }
    1022              :                 }
    1023              :             } else {
    1024            1 :                 if (lNumericBlanks(1)) {
    1025            0 :                     heatingCoil.Efficiency = 0.25;
    1026              :                 } else {
    1027            1 :                     heatingCoil.Efficiency = Numbers(1);
    1028            1 :                     if (Numbers(1) < 0.0 || Numbers(1) > 0.3) {
    1029            0 :                         ShowSevereError(
    1030              :                             state,
    1031            0 :                             format("{}, \"{}\" heat reclaim recovery efficiency must be >= 0 and <=0.3", CurrentModuleObject, heatingCoil.Name));
    1032            0 :                         state.dataHeatingCoils->InputErrorsFound = true;
    1033              :                     }
    1034              :                 }
    1035              :             }
    1036              : 
    1037              :             // Find the DX equipment index associated with the desuperheater heating coil.
    1038              :             // The CoilNum may not be found here when zone heating equip. exists. Check again in InitHeatingCoil.
    1039              :             // (when zone equipment heating coils are included in the input, the air loop DX equipment has not yet been read in)
    1040            1 :             if (Util::SameString(Alphas(5), "Refrigeration:CompressorRack")) {
    1041            1 :                 heatingCoil.ReclaimHeatingSource = HeatObjTypes::COMPRESSORRACK_REFRIGERATEDCASE;
    1042            2 :                 RefrigeratedCase::GetRefrigeratedRackIndex(
    1043            1 :                     state, Alphas(6), heatingCoil.ReclaimHeatingSourceIndexNum, DataHeatBalance::RefrigSystemType::Rack, DXCoilErrFlag, Alphas(5));
    1044            1 :                 if (heatingCoil.ReclaimHeatingSourceIndexNum > 0) {
    1045            1 :                     if (allocated(state.dataHeatBal->HeatReclaimRefrigeratedRack)) {
    1046              :                         DataHeatBalance::HeatReclaimDataBase &HeatReclaim =
    1047            1 :                             state.dataHeatBal->HeatReclaimRefrigeratedRack(heatingCoil.ReclaimHeatingSourceIndexNum);
    1048            1 :                         if (!allocated(HeatReclaim.HVACDesuperheaterReclaimedHeat)) {
    1049            1 :                             HeatReclaim.HVACDesuperheaterReclaimedHeat.allocate(state.dataHeatingCoils->NumDesuperheaterCoil);
    1050            1 :                             std::fill(HeatReclaim.HVACDesuperheaterReclaimedHeat.begin(), HeatReclaim.HVACDesuperheaterReclaimedHeat.end(), 0.0);
    1051              :                         }
    1052            1 :                         HeatReclaim.ReclaimEfficiencyTotal += heatingCoil.Efficiency;
    1053            1 :                         if (HeatReclaim.ReclaimEfficiencyTotal > 0.3) {
    1054            0 :                             ShowSevereError(
    1055              :                                 state,
    1056            0 :                                 format("{}, \"{}\" sum of heat reclaim recovery efficiencies from the same source coil: \"{} \" cannot be over 0.3",
    1057              :                                        HVAC::cAllCoilTypes(heatingCoil.HCoilType_Num),
    1058            0 :                                        heatingCoil.Name,
    1059            0 :                                        heatingCoil.ReclaimHeatingCoilName));
    1060              :                         }
    1061            1 :                         state.dataHeatingCoils->ValidSourceType(CoilNum) = true;
    1062              :                     }
    1063              :                 }
    1064            0 :             } else if ((Util::SameString(Alphas(5), "Refrigeration:Condenser:AirCooled")) ||
    1065            0 :                        (Util::SameString(Alphas(5), "Refrigeration:Condenser:EvaporativeCooled")) ||
    1066            0 :                        (Util::SameString(Alphas(5), "Refrigeration:Condenser:WaterCooled"))) {
    1067            0 :                 heatingCoil.ReclaimHeatingSource = HeatObjTypes::CONDENSER_REFRIGERATION;
    1068            0 :                 RefrigeratedCase::GetRefrigeratedRackIndex(state,
    1069            0 :                                                            Alphas(6),
    1070            0 :                                                            heatingCoil.ReclaimHeatingSourceIndexNum,
    1071              :                                                            DataHeatBalance::RefrigSystemType::Detailed,
    1072              :                                                            DXCoilErrFlag,
    1073            0 :                                                            Alphas(5));
    1074            0 :                 if (heatingCoil.ReclaimHeatingSourceIndexNum > 0) {
    1075            0 :                     if (allocated(state.dataHeatBal->HeatReclaimRefrigCondenser)) {
    1076              :                         DataHeatBalance::HeatReclaimDataBase &HeatReclaim =
    1077            0 :                             state.dataHeatBal->HeatReclaimRefrigCondenser(heatingCoil.ReclaimHeatingSourceIndexNum);
    1078            0 :                         if (!allocated(HeatReclaim.HVACDesuperheaterReclaimedHeat)) {
    1079            0 :                             HeatReclaim.HVACDesuperheaterReclaimedHeat.allocate(state.dataHeatingCoils->NumDesuperheaterCoil);
    1080            0 :                             std::fill(HeatReclaim.HVACDesuperheaterReclaimedHeat.begin(), HeatReclaim.HVACDesuperheaterReclaimedHeat.end(), 0.0);
    1081              :                         }
    1082            0 :                         HeatReclaim.ReclaimEfficiencyTotal += heatingCoil.Efficiency;
    1083            0 :                         if (HeatReclaim.ReclaimEfficiencyTotal > 0.9) {
    1084            0 :                             ShowSevereError(
    1085              :                                 state,
    1086            0 :                                 format("{}, \"{}\" sum of heat reclaim recovery efficiencies from the same source coil: \"{} \" cannot be over 0.9",
    1087              :                                        HVAC::cAllCoilTypes(heatingCoil.HCoilType_Num),
    1088            0 :                                        heatingCoil.Name,
    1089            0 :                                        heatingCoil.ReclaimHeatingCoilName));
    1090              :                         }
    1091            0 :                         state.dataHeatingCoils->ValidSourceType(CoilNum) = true;
    1092              :                     }
    1093              :                 }
    1094            0 :             } else if (Util::SameString(Alphas(5), "Coil:Cooling:DX:SingleSpeed")) {
    1095            0 :                 heatingCoil.ReclaimHeatingSource = HeatObjTypes::COIL_DX_COOLING;
    1096            0 :                 DXCoils::GetDXCoilIndex(state, Alphas(6), heatingCoil.ReclaimHeatingSourceIndexNum, DXCoilErrFlag, Alphas(5));
    1097            0 :                 if (heatingCoil.ReclaimHeatingSourceIndexNum > 0) {
    1098            0 :                     if (allocated(state.dataHeatBal->HeatReclaimDXCoil)) {
    1099              :                         DataHeatBalance::HeatReclaimDataBase &HeatReclaim =
    1100            0 :                             state.dataHeatBal->HeatReclaimDXCoil(heatingCoil.ReclaimHeatingSourceIndexNum);
    1101            0 :                         if (!allocated(HeatReclaim.HVACDesuperheaterReclaimedHeat)) {
    1102            0 :                             HeatReclaim.HVACDesuperheaterReclaimedHeat.allocate(state.dataHeatingCoils->NumDesuperheaterCoil);
    1103            0 :                             std::fill(HeatReclaim.HVACDesuperheaterReclaimedHeat.begin(), HeatReclaim.HVACDesuperheaterReclaimedHeat.end(), 0.0);
    1104              :                         }
    1105            0 :                         HeatReclaim.ReclaimEfficiencyTotal += heatingCoil.Efficiency;
    1106            0 :                         if (HeatReclaim.ReclaimEfficiencyTotal > 0.3) {
    1107            0 :                             ShowSevereError(
    1108              :                                 state,
    1109            0 :                                 format("{}, \"{}\" sum of heat reclaim recovery efficiencies from the same source coil: \"{} \" cannot be over 0.3",
    1110              :                                        HVAC::cAllCoilTypes(heatingCoil.HCoilType_Num),
    1111            0 :                                        heatingCoil.Name,
    1112            0 :                                        heatingCoil.ReclaimHeatingCoilName));
    1113              :                         }
    1114            0 :                         state.dataHeatingCoils->ValidSourceType(CoilNum) = true;
    1115              :                     }
    1116              :                 }
    1117            0 :                 if (heatingCoil.ReclaimHeatingSourceIndexNum > 0) {
    1118            0 :                     state.dataHeatingCoils->ValidSourceType(CoilNum) = true;
    1119              :                 }
    1120            0 :             } else if (Util::SameString(Alphas(5), "Coil:Cooling:DX:VariableSpeed")) {
    1121            0 :                 heatingCoil.ReclaimHeatingSource = HeatObjTypes::COIL_DX_VARIABLE_COOLING;
    1122            0 :                 heatingCoil.ReclaimHeatingSourceIndexNum = VariableSpeedCoils::GetCoilIndexVariableSpeed(state, Alphas(5), Alphas(6), DXCoilErrFlag);
    1123            0 :                 if (heatingCoil.ReclaimHeatingSourceIndexNum > 0) {
    1124            0 :                     if (allocated(state.dataHeatBal->HeatReclaimVS_Coil)) {
    1125              :                         DataHeatBalance::HeatReclaimDataBase &HeatReclaim =
    1126            0 :                             state.dataHeatBal->HeatReclaimVS_Coil(heatingCoil.ReclaimHeatingSourceIndexNum);
    1127            0 :                         if (!allocated(HeatReclaim.HVACDesuperheaterReclaimedHeat)) {
    1128            0 :                             HeatReclaim.HVACDesuperheaterReclaimedHeat.allocate(state.dataHeatingCoils->NumDesuperheaterCoil);
    1129            0 :                             std::fill(HeatReclaim.HVACDesuperheaterReclaimedHeat.begin(), HeatReclaim.HVACDesuperheaterReclaimedHeat.end(), 0.0);
    1130              :                         }
    1131            0 :                         HeatReclaim.ReclaimEfficiencyTotal += heatingCoil.Efficiency;
    1132            0 :                         if (HeatReclaim.ReclaimEfficiencyTotal > 0.3) {
    1133            0 :                             ShowSevereError(
    1134              :                                 state,
    1135            0 :                                 format("{}, \"{}\" sum of heat reclaim recovery efficiencies from the same source coil: \"{} \" cannot be over 0.3",
    1136              :                                        HVAC::cAllCoilTypes(heatingCoil.HCoilType_Num),
    1137            0 :                                        heatingCoil.Name,
    1138            0 :                                        heatingCoil.ReclaimHeatingCoilName));
    1139              :                         }
    1140            0 :                         state.dataHeatingCoils->ValidSourceType(CoilNum) = true;
    1141              :                     }
    1142              :                 }
    1143            0 :             } else if (Util::SameString(Alphas(5), "Coil:Cooling:DX:TwoSpeed")) {
    1144            0 :                 heatingCoil.ReclaimHeatingSource = HeatObjTypes::COIL_DX_MULTISPEED;
    1145            0 :                 DXCoils::GetDXCoilIndex(state, Alphas(6), heatingCoil.ReclaimHeatingSourceIndexNum, DXCoilErrFlag, Alphas(5));
    1146            0 :                 if (heatingCoil.ReclaimHeatingSourceIndexNum > 0) {
    1147            0 :                     if (allocated(state.dataHeatBal->HeatReclaimDXCoil)) {
    1148              :                         DataHeatBalance::HeatReclaimDataBase &HeatReclaim =
    1149            0 :                             state.dataHeatBal->HeatReclaimDXCoil(heatingCoil.ReclaimHeatingSourceIndexNum);
    1150            0 :                         if (!allocated(HeatReclaim.HVACDesuperheaterReclaimedHeat)) {
    1151            0 :                             HeatReclaim.HVACDesuperheaterReclaimedHeat.allocate(state.dataHeatingCoils->NumDesuperheaterCoil);
    1152            0 :                             std::fill(HeatReclaim.HVACDesuperheaterReclaimedHeat.begin(), HeatReclaim.HVACDesuperheaterReclaimedHeat.end(), 0.0);
    1153              :                         }
    1154            0 :                         HeatReclaim.ReclaimEfficiencyTotal += heatingCoil.Efficiency;
    1155            0 :                         if (HeatReclaim.ReclaimEfficiencyTotal > 0.3) {
    1156            0 :                             ShowSevereError(
    1157              :                                 state,
    1158            0 :                                 format("{}, \"{}\" sum of heat reclaim recovery efficiencies from the same source coil: \"{} \" cannot be over 0.3",
    1159              :                                        HVAC::cAllCoilTypes(heatingCoil.HCoilType_Num),
    1160            0 :                                        heatingCoil.Name,
    1161            0 :                                        heatingCoil.ReclaimHeatingCoilName));
    1162              :                         }
    1163            0 :                         state.dataHeatingCoils->ValidSourceType(CoilNum) = true;
    1164              :                     }
    1165              :                 }
    1166            0 :             } else if (Util::SameString(Alphas(5), "Coil:Cooling:DX:TwoStageWithHumidityControlMode")) {
    1167            0 :                 heatingCoil.ReclaimHeatingSource = HeatObjTypes::COIL_DX_MULTIMODE;
    1168            0 :                 DXCoils::GetDXCoilIndex(state, Alphas(6), heatingCoil.ReclaimHeatingSourceIndexNum, DXCoilErrFlag, Alphas(5));
    1169            0 :                 if (heatingCoil.ReclaimHeatingSourceIndexNum > 0) {
    1170            0 :                     if (allocated(state.dataHeatBal->HeatReclaimDXCoil)) {
    1171              :                         DataHeatBalance::HeatReclaimDataBase &HeatReclaim =
    1172            0 :                             state.dataHeatBal->HeatReclaimDXCoil(heatingCoil.ReclaimHeatingSourceIndexNum);
    1173            0 :                         if (!allocated(HeatReclaim.HVACDesuperheaterReclaimedHeat)) {
    1174            0 :                             HeatReclaim.HVACDesuperheaterReclaimedHeat.allocate(state.dataHeatingCoils->NumDesuperheaterCoil);
    1175            0 :                             std::fill(HeatReclaim.HVACDesuperheaterReclaimedHeat.begin(), HeatReclaim.HVACDesuperheaterReclaimedHeat.end(), 0.0);
    1176              :                         }
    1177            0 :                         HeatReclaim.ReclaimEfficiencyTotal += heatingCoil.Efficiency;
    1178            0 :                         if (HeatReclaim.ReclaimEfficiencyTotal > 0.3) {
    1179            0 :                             ShowSevereError(
    1180              :                                 state,
    1181            0 :                                 format(R"({}, "{}" sum of heat reclaim recovery efficiencies from the same source coil: "{} " cannot be over 0.3)",
    1182              :                                        HVAC::cAllCoilTypes(heatingCoil.HCoilType_Num),
    1183            0 :                                        heatingCoil.Name,
    1184            0 :                                        heatingCoil.ReclaimHeatingCoilName));
    1185              :                         }
    1186            0 :                         state.dataHeatingCoils->ValidSourceType(CoilNum) = true;
    1187              :                     }
    1188              :                 }
    1189            0 :             } else if (Util::SameString(Alphas(5), "Coil:Cooling:DX")) {
    1190            0 :                 heatingCoil.ReclaimHeatingSource = HeatObjTypes::COIL_COOLING_DX_NEW;
    1191            0 :                 heatingCoil.ReclaimHeatingSourceIndexNum = CoilCoolingDX::factory(state, Alphas(6));
    1192            0 :                 if (heatingCoil.ReclaimHeatingSourceIndexNum < 0) {
    1193            0 :                     ShowSevereError(
    1194            0 :                         state, format("{}={}, could not find desuperheater coil {}={}", CurrentModuleObject, heatingCoil.Name, Alphas(5), Alphas(6)));
    1195            0 :                     state.dataHeatingCoils->InputErrorsFound = true;
    1196              :                 }
    1197              :                 DataHeatBalance::HeatReclaimDataBase &HeatReclaim =
    1198            0 :                     state.dataCoilCoolingDX->coilCoolingDXs[heatingCoil.ReclaimHeatingSourceIndexNum].reclaimHeat;
    1199            0 :                 if (!allocated(HeatReclaim.HVACDesuperheaterReclaimedHeat)) {
    1200            0 :                     HeatReclaim.HVACDesuperheaterReclaimedHeat.allocate(state.dataHeatingCoils->NumDesuperheaterCoil);
    1201            0 :                     std::fill(HeatReclaim.HVACDesuperheaterReclaimedHeat.begin(), HeatReclaim.HVACDesuperheaterReclaimedHeat.end(), 0.0);
    1202              :                 }
    1203            0 :                 HeatReclaim.ReclaimEfficiencyTotal += heatingCoil.Efficiency;
    1204            0 :                 if (HeatReclaim.ReclaimEfficiencyTotal > 0.3) {
    1205            0 :                     ShowSevereError(
    1206              :                         state,
    1207            0 :                         format("{}, \"{}\" sum of heat reclaim recovery efficiencies from the same source coil: \"{}\" cannot be over 0.3",
    1208              :                                HVAC::cAllCoilTypes(heatingCoil.HCoilType_Num),
    1209            0 :                                heatingCoil.Name,
    1210            0 :                                heatingCoil.ReclaimHeatingCoilName));
    1211              :                 }
    1212            0 :                 state.dataHeatingCoils->ValidSourceType(CoilNum) = true;
    1213              :             } else {
    1214            0 :                 ShowSevereError(
    1215              :                     state,
    1216            0 :                     format("{}, \"{}\" valid desuperheater heat source object type not found: {}", CurrentModuleObject, heatingCoil.Name, Alphas(5)));
    1217            0 :                 ShowContinueError(state, "Valid desuperheater heat source objects are:");
    1218            0 :                 ShowContinueError(state,
    1219              :                                   "Refrigeration:CompressorRack, Coil:Cooling:DX:SingleSpeed, Refrigeration:Condenser:AirCooled, "
    1220              :                                   "Refrigeration:Condenser:EvaporativeCooled, Refrigeration:Condenser:WaterCooled,Coil:Cooling:DX:TwoSpeed, and "
    1221              :                                   "Coil:Cooling:DX:TwoStageWithHumidityControlMode");
    1222            0 :                 state.dataHeatingCoils->InputErrorsFound = true;
    1223              :             }
    1224              : 
    1225            1 :             heatingCoil.ReclaimHeatingCoilName = Alphas(6);
    1226              : 
    1227            1 :             errFlag = false;
    1228            1 :             heatingCoil.TempSetPointNodeNum = GetOnlySingleNode(state,
    1229            1 :                                                                 Alphas(7),
    1230              :                                                                 errFlag,
    1231              :                                                                 DataLoopNode::ConnectionObjectType::CoilHeatingDesuperheater,
    1232            1 :                                                                 Alphas(1),
    1233              :                                                                 DataLoopNode::NodeFluidType::Air,
    1234              :                                                                 DataLoopNode::ConnectionType::Sensor,
    1235              :                                                                 NodeInputManager::CompFluidStream::Primary,
    1236              :                                                                 DataLoopNode::ObjectIsNotParent);
    1237            1 :             state.dataHeatingCoils->InputErrorsFound = errFlag || state.dataHeatingCoils->InputErrorsFound;
    1238              : 
    1239              :             // parasitic electric load associated with the desuperheater heating coil
    1240            1 :             heatingCoil.ParasiticElecLoad = Numbers(2);
    1241              : 
    1242            1 :             if (Numbers(2) < 0.0) {
    1243            0 :                 ShowSevereError(state, format("{}, \"{}\" parasitic electric load must be >= 0", CurrentModuleObject, heatingCoil.Name));
    1244            0 :                 state.dataHeatingCoils->InputErrorsFound = true;
    1245              :             }
    1246              : 
    1247              :             // Setup Report variables for the Desuperheater Heating Coils
    1248              :             // CurrentModuleObject = "Coil:Heating:Desuperheater"
    1249            2 :             SetupOutputVariable(state,
    1250              :                                 "Heating Coil Heating Energy",
    1251              :                                 Constant::Units::J,
    1252            1 :                                 heatingCoil.HeatingCoilLoad,
    1253              :                                 OutputProcessor::TimeStepType::System,
    1254              :                                 OutputProcessor::StoreType::Sum,
    1255            1 :                                 heatingCoil.Name,
    1256              :                                 Constant::eResource::EnergyTransfer,
    1257              :                                 OutputProcessor::Group::HVAC,
    1258              :                                 OutputProcessor::EndUseCat::HeatingCoils);
    1259            2 :             SetupOutputVariable(state,
    1260              :                                 "Heating Coil Heating Rate",
    1261              :                                 Constant::Units::W,
    1262            1 :                                 heatingCoil.HeatingCoilRate,
    1263              :                                 OutputProcessor::TimeStepType::System,
    1264              :                                 OutputProcessor::StoreType::Average,
    1265            1 :                                 heatingCoil.Name);
    1266            2 :             SetupOutputVariable(state,
    1267              :                                 "Heating Coil Electricity Energy",
    1268              :                                 Constant::Units::J,
    1269            1 :                                 heatingCoil.ElecUseLoad,
    1270              :                                 OutputProcessor::TimeStepType::System,
    1271              :                                 OutputProcessor::StoreType::Sum,
    1272            1 :                                 heatingCoil.Name,
    1273              :                                 Constant::eResource::Electricity,
    1274              :                                 OutputProcessor::Group::HVAC,
    1275              :                                 OutputProcessor::EndUseCat::Heating);
    1276            2 :             SetupOutputVariable(state,
    1277              :                                 "Heating Coil Electricity Rate",
    1278              :                                 Constant::Units::W,
    1279            1 :                                 heatingCoil.ElecUseRate,
    1280              :                                 OutputProcessor::TimeStepType::System,
    1281              :                                 OutputProcessor::StoreType::Average,
    1282            1 :                                 heatingCoil.Name);
    1283            2 :             SetupOutputVariable(state,
    1284              :                                 "Heating Coil Runtime Fraction",
    1285              :                                 Constant::Units::None,
    1286            1 :                                 heatingCoil.RTF,
    1287              :                                 OutputProcessor::TimeStepType::System,
    1288              :                                 OutputProcessor::StoreType::Average,
    1289            1 :                                 heatingCoil.Name);
    1290              :         }
    1291              : 
    1292          123 :         if (state.dataHeatingCoils->InputErrorsFound) {
    1293            2 :             ShowFatalError(state, format("{}Errors found in input.  Program terminates.", RoutineName));
    1294              :         }
    1295              : 
    1296          122 :         Alphas.deallocate();
    1297          122 :         cAlphaFields.deallocate();
    1298          122 :         cNumericFields.deallocate();
    1299          122 :         Numbers.deallocate();
    1300          122 :         lAlphaBlanks.deallocate();
    1301          122 :         lNumericBlanks.deallocate();
    1302          129 :     }
    1303              : 
    1304       233160 :     void InitHeatingCoil(EnergyPlusData &state, int const CoilNum, bool const FirstHVACIteration, Real64 const QCoilRequired)
    1305              :     {
    1306              : 
    1307              :         // SUBROUTINE INFORMATION:
    1308              :         //       AUTHOR         Richard J. Liesen
    1309              :         //       DATE WRITTEN   May 2000
    1310              :         //       MODIFIED       B. Griffith, May 2009 added EMS setpoint check
    1311              : 
    1312              :         // PURPOSE OF THIS SUBROUTINE:
    1313              :         // This subroutine is for initializations of the HeatingCoil Components.
    1314              : 
    1315              :         // METHODOLOGY EMPLOYED:
    1316              :         // Uses the status flags to trigger initializations.
    1317              : 
    1318       233160 :         auto &heatingCoil = state.dataHeatingCoils->HeatingCoil(CoilNum);
    1319              : 
    1320       233160 :         if (state.dataHeatingCoils->MyOneTimeFlag) {
    1321              :             // initialize the environment and sizing flags
    1322           94 :             Real64 numHeatingCoils = state.dataHeatingCoils->NumHeatingCoils;
    1323           94 :             state.dataHeatingCoils->MyEnvrnFlag.allocate(numHeatingCoils);
    1324           94 :             state.dataHeatingCoils->MySizeFlag.allocate(numHeatingCoils);
    1325           94 :             state.dataHeatingCoils->ShowSingleWarning.allocate(numHeatingCoils);
    1326           94 :             state.dataHeatingCoils->MySPTestFlag.allocate(numHeatingCoils);
    1327           94 :             state.dataHeatingCoils->MyEnvrnFlag = true;
    1328           94 :             state.dataHeatingCoils->MySizeFlag = true;
    1329           94 :             state.dataHeatingCoils->ShowSingleWarning = true;
    1330           94 :             state.dataHeatingCoils->MyOneTimeFlag = false;
    1331           94 :             state.dataHeatingCoils->MySPTestFlag = true;
    1332              :         }
    1333              : 
    1334       233160 :         if (!state.dataGlobal->SysSizingCalc && state.dataHeatingCoils->MySizeFlag(CoilNum)) {
    1335              :             // for each coil, do the sizing once.
    1336           98 :             SizeHeatingCoil(state, CoilNum);
    1337              : 
    1338           98 :             state.dataHeatingCoils->MySizeFlag(CoilNum) = false;
    1339              :         }
    1340              : 
    1341              :         // Do the following initializations (every time step): This should be the info from
    1342              :         // the previous components outlets or the node data in this section.
    1343              :         // First set the conditions for the air into the coil model
    1344       233160 :         int AirOutletNodeNum = heatingCoil.AirOutletNodeNum;
    1345       233160 :         int ControlNodeNum = heatingCoil.TempSetPointNodeNum;
    1346       233160 :         auto const &airInletNode = state.dataLoopNodes->Node(heatingCoil.AirInletNodeNum);
    1347       233160 :         auto const &airOutletNode = state.dataLoopNodes->Node(AirOutletNodeNum);
    1348       233160 :         heatingCoil.InletAirMassFlowRate = airInletNode.MassFlowRate;
    1349       233160 :         heatingCoil.InletAirTemp = airInletNode.Temp;
    1350       233160 :         heatingCoil.InletAirHumRat = airInletNode.HumRat;
    1351       233160 :         heatingCoil.InletAirEnthalpy = airInletNode.Enthalpy;
    1352              : 
    1353              :         // Set the reporting variables to zero at each timestep.
    1354       233160 :         heatingCoil.HeatingCoilLoad = 0.0;
    1355       233160 :         heatingCoil.FuelUseLoad = 0.0;
    1356       233160 :         heatingCoil.ElecUseLoad = 0.0;
    1357       233160 :         heatingCoil.RTF = 0.0;
    1358              : 
    1359              :         // If a temperature setpoint controlled coil must set the desired outlet temp everytime
    1360       233160 :         if (ControlNodeNum == 0) {
    1361       167841 :             heatingCoil.DesiredOutletTemp = 0.0;
    1362              :         } else {
    1363        65319 :             auto const &controlNode = state.dataLoopNodes->Node(ControlNodeNum);
    1364        65319 :             heatingCoil.DesiredOutletTemp =
    1365        65319 :                 controlNode.TempSetPoint - ((ControlNodeNum == AirOutletNodeNum) ? 0 : (controlNode.Temp - airOutletNode.Temp));
    1366              :         }
    1367              : 
    1368        65486 :         if (QCoilRequired == DataLoopNode::SensedLoadFlagValue && state.dataHeatingCoils->MySPTestFlag(CoilNum) &&
    1369       298646 :             heatingCoil.HCoilType_Num != HVAC::Coil_HeatingElectric_MultiStage && heatingCoil.HCoilType_Num != HVAC::Coil_HeatingGas_MultiStage) {
    1370              : 
    1371              :             //   If the coil is temperature controlled (QCoilReq == -999.0), both a control node and setpoint are required.
    1372           77 :             if (!state.dataGlobal->SysSizingCalc && state.dataHVACGlobal->DoSetPointTest) {
    1373              :                 //     3 possibilities here:
    1374              :                 //     1) TempSetPointNodeNum .GT. 0 and TempSetPoint /= SensedNodeFlagValue, this is correct
    1375              :                 //     2) TempSetPointNodeNum .EQ. 0, this is not correct, control node is required
    1376              :                 //     3) TempSetPointNodeNum .GT. 0 and TempSetPoint == SensedNodeFlagValue, this is not correct, missing temperature setpoint
    1377              :                 //     test 2) here (fatal message)
    1378           15 :                 if (ControlNodeNum == 0) {
    1379            0 :                     ShowSevereError(state, format("{} \"{}\"", HVAC::cAllCoilTypes(heatingCoil.HCoilType_Num), heatingCoil.Name));
    1380            0 :                     ShowContinueError(state, "... Missing control node for heating coil.");
    1381            0 :                     ShowContinueError(state, "... enter a control node name in the coil temperature setpoint node field for this heating coil.");
    1382            0 :                     ShowContinueError(state, "... use a Setpoint Manager to establish a setpoint at the coil temperature setpoint node.");
    1383            0 :                     state.dataHeatingCoils->HeatingCoilFatalError = true;
    1384              :                     //     test 3) here (fatal message)
    1385              :                 } else { // IF(ControlNode .GT. 0)THEN
    1386           15 :                     auto const &controlNode = state.dataLoopNodes->Node(ControlNodeNum);
    1387           15 :                     if (controlNode.TempSetPoint == DataLoopNode::SensedNodeFlagValue) {
    1388            0 :                         if (!state.dataGlobal->AnyEnergyManagementSystemInModel) {
    1389            0 :                             ShowSevereError(state, format("{} \"{}\"", HVAC::cAllCoilTypes(heatingCoil.HCoilType_Num), heatingCoil.Name));
    1390            0 :                             ShowContinueError(state, "... Missing temperature setpoint for heating coil.");
    1391            0 :                             ShowContinueError(state, "... use a Setpoint Manager to establish a setpoint at the coil temperature setpoint node.");
    1392            0 :                             state.dataHeatingCoils->HeatingCoilFatalError = true;
    1393              :                         } else {
    1394            0 :                             EMSManager::CheckIfNodeSetPointManagedByEMS(
    1395            0 :                                 state, ControlNodeNum, HVAC::CtrlVarType::Temp, state.dataHeatingCoils->HeatingCoilFatalError);
    1396            0 :                             if (state.dataHeatingCoils->HeatingCoilFatalError) {
    1397            0 :                                 ShowSevereError(state, format("{} \"{}\"", HVAC::cAllCoilTypes(heatingCoil.HCoilType_Num), heatingCoil.Name));
    1398            0 :                                 ShowContinueError(state, "... Missing temperature setpoint for heating coil.");
    1399            0 :                                 ShowContinueError(state, "... use a Setpoint Manager to establish a setpoint at the coil temperature setpoint node.");
    1400            0 :                                 ShowContinueError(state, "... or use an EMS Actuator to establish a setpoint at the coil temperature setpoint node.");
    1401              :                             }
    1402              :                         }
    1403              :                     }
    1404              :                 }
    1405           15 :                 state.dataHeatingCoils->MySPTestFlag(CoilNum) = false;
    1406              :             }
    1407       233083 :         } else if (state.dataHeatingCoils->MySPTestFlag(CoilNum)) {
    1408              :             //  If QCoilReq /= SensedLoadFlagValue, the coil is load controlled and does not require a control node
    1409              :             //   4 possibilities here:
    1410              :             //   1) TempSetPointNodeNum .EQ. 0 and TempSetPoint == SensedNodeFlagValue, this is correct
    1411              :             //   2) TempSetPointNodeNum .EQ. 0 and TempSetPoint /= SensedNodeFlagValue, this may be correct,
    1412              :             //      (if no control node specified and SP on heating coil outlet do not show warning, other SP managers may be using SP)
    1413              :             //   3) TempSetPointNodeNum .GT. 0 and TempSetPoint == SensedNodeFlagValue, control node not required if load based control
    1414              :             //   4) TempSetPointNodeNum .GT. 0 and TempSetPoint /= SensedNodeFlagValue, control node not required if load based control
    1415              :             //   test 3) and 4) here (warning only)
    1416          106 :             if (ControlNodeNum > 0) {
    1417            4 :                 ShowWarningError(state, format("{} \"{}\"", HVAC::cAllCoilTypes(heatingCoil.HCoilType_Num), heatingCoil.Name));
    1418            8 :                 ShowContinueError(state, " The \"Temperature Setpoint Node Name\" input is not required for this heating coil.");
    1419           12 :                 ShowContinueError(state, " Leaving the input field \"Temperature Setpoint Node Name\" blank will eliminate this warning.");
    1420              :             }
    1421          106 :             state.dataHeatingCoils->MySPTestFlag(CoilNum) = false;
    1422              :         }
    1423              : 
    1424              :         // delay fatal error until all coils are called
    1425       233160 :         if (!FirstHVACIteration && state.dataHeatingCoils->HeatingCoilFatalError) {
    1426            0 :             ShowFatalError(state, "... errors found in heating coil input.");
    1427              :         }
    1428              : 
    1429              :         // Find the heating source index for the desuperheater heating coil if not already found. This occurs when zone heating
    1430              :         // equip. exists. (when zone equipment heating coils are included in the input, the air loop DX equipment has not yet been read)
    1431              :         // Issue a single warning if the coil is not found and continue the simulation
    1432       233160 :         if (!state.dataHeatingCoils->ValidSourceType(CoilNum) && (heatingCoil.HCoilType_Num == HVAC::Coil_HeatingDesuperheater) &&
    1433            0 :             state.dataHeatingCoils->ShowSingleWarning(CoilNum)) {
    1434            0 :             ++state.dataHeatingCoils->ValidSourceTypeCounter;
    1435            0 :             switch (heatingCoil.ReclaimHeatingSource) {
    1436            0 :             case HeatObjTypes::COMPRESSORRACK_REFRIGERATEDCASE: {
    1437            0 :                 for (int RackNum = 1; RackNum <= state.dataRefrigCase->NumRefrigeratedRacks; ++RackNum) {
    1438            0 :                     if (!Util::SameString(state.dataHeatBal->HeatReclaimRefrigeratedRack(RackNum).Name, heatingCoil.ReclaimHeatingCoilName)) {
    1439            0 :                         continue;
    1440              :                     }
    1441            0 :                     heatingCoil.ReclaimHeatingSourceIndexNum = RackNum;
    1442            0 :                     if (allocated(state.dataHeatBal->HeatReclaimRefrigeratedRack)) {
    1443              :                         DataHeatBalance::HeatReclaimDataBase &HeatReclaim =
    1444            0 :                             state.dataHeatBal->HeatReclaimRefrigeratedRack(heatingCoil.ReclaimHeatingSourceIndexNum);
    1445            0 :                         if (!allocated(HeatReclaim.HVACDesuperheaterReclaimedHeat)) {
    1446            0 :                             HeatReclaim.HVACDesuperheaterReclaimedHeat.allocate(state.dataHeatingCoils->NumDesuperheaterCoil);
    1447            0 :                             std::fill(HeatReclaim.HVACDesuperheaterReclaimedHeat.begin(), HeatReclaim.HVACDesuperheaterReclaimedHeat.end(), 0.0);
    1448            0 :                             HeatReclaim.ReclaimEfficiencyTotal += heatingCoil.Efficiency;
    1449            0 :                             if (HeatReclaim.ReclaimEfficiencyTotal > 0.3) {
    1450            0 :                                 ShowSevereError(
    1451              :                                     state,
    1452            0 :                                     format(R"({}, "{}" sum of heat reclaim recovery efficiencies from the same source coil: "{}" cannot be over 0.3)",
    1453              :                                            HVAC::cAllCoilTypes(heatingCoil.HCoilType_Num),
    1454            0 :                                            heatingCoil.Name,
    1455            0 :                                            heatingCoil.ReclaimHeatingCoilName));
    1456              :                             }
    1457              :                         }
    1458            0 :                         state.dataHeatingCoils->ValidSourceType(CoilNum) = true;
    1459              :                     }
    1460            0 :                     break;
    1461              :                 }
    1462            0 :             } break;
    1463            0 :             case HeatObjTypes::CONDENSER_REFRIGERATION: {
    1464            0 :                 for (int CondNum = 1; CondNum <= state.dataRefrigCase->NumRefrigCondensers; ++CondNum) {
    1465            0 :                     if (!Util::SameString(state.dataHeatBal->HeatReclaimRefrigCondenser(CondNum).Name, heatingCoil.ReclaimHeatingCoilName)) {
    1466            0 :                         continue;
    1467              :                     }
    1468            0 :                     heatingCoil.ReclaimHeatingSourceIndexNum = CondNum;
    1469            0 :                     if (allocated(state.dataHeatBal->HeatReclaimRefrigCondenser)) {
    1470              :                         DataHeatBalance::HeatReclaimDataBase &HeatReclaim =
    1471            0 :                             state.dataHeatBal->HeatReclaimRefrigCondenser(heatingCoil.ReclaimHeatingSourceIndexNum);
    1472            0 :                         if (!allocated(HeatReclaim.HVACDesuperheaterReclaimedHeat)) {
    1473            0 :                             HeatReclaim.HVACDesuperheaterReclaimedHeat.allocate(state.dataHeatingCoils->NumDesuperheaterCoil);
    1474            0 :                             std::fill(HeatReclaim.HVACDesuperheaterReclaimedHeat.begin(), HeatReclaim.HVACDesuperheaterReclaimedHeat.end(), 0.0);
    1475            0 :                             HeatReclaim.ReclaimEfficiencyTotal += heatingCoil.Efficiency;
    1476            0 :                             if (HeatReclaim.ReclaimEfficiencyTotal > 0.9) {
    1477            0 :                                 ShowSevereError(
    1478              :                                     state,
    1479            0 :                                     format(R"({}, "{}" sum of heat reclaim recovery efficiencies from the same source coil: "{}" cannot be over 0.9)",
    1480              :                                            HVAC::cAllCoilTypes(heatingCoil.HCoilType_Num),
    1481            0 :                                            heatingCoil.Name,
    1482            0 :                                            heatingCoil.ReclaimHeatingCoilName));
    1483              :                             }
    1484              :                         }
    1485            0 :                         state.dataHeatingCoils->ValidSourceType(CoilNum) = true;
    1486              :                     }
    1487            0 :                     break;
    1488              :                 }
    1489            0 :             } break;
    1490            0 :             case HeatObjTypes::COIL_DX_COOLING:
    1491              :             case HeatObjTypes::COIL_DX_MULTISPEED:
    1492              :             case HeatObjTypes::COIL_DX_MULTIMODE: {
    1493            0 :                 for (int DXCoilNum = 1; DXCoilNum <= state.dataDXCoils->NumDXCoils; ++DXCoilNum) {
    1494            0 :                     if (!Util::SameString(state.dataHeatBal->HeatReclaimDXCoil(DXCoilNum).Name, heatingCoil.ReclaimHeatingCoilName)) {
    1495            0 :                         continue;
    1496              :                     }
    1497            0 :                     heatingCoil.ReclaimHeatingSourceIndexNum = DXCoilNum;
    1498            0 :                     if (allocated(state.dataHeatBal->HeatReclaimDXCoil)) {
    1499              :                         DataHeatBalance::HeatReclaimDataBase &HeatReclaim =
    1500            0 :                             state.dataHeatBal->HeatReclaimDXCoil(heatingCoil.ReclaimHeatingSourceIndexNum);
    1501            0 :                         if (!allocated(HeatReclaim.HVACDesuperheaterReclaimedHeat)) {
    1502            0 :                             HeatReclaim.HVACDesuperheaterReclaimedHeat.allocate(state.dataHeatingCoils->NumDesuperheaterCoil);
    1503            0 :                             std::fill(HeatReclaim.HVACDesuperheaterReclaimedHeat.begin(), HeatReclaim.HVACDesuperheaterReclaimedHeat.end(), 0.0);
    1504            0 :                             HeatReclaim.ReclaimEfficiencyTotal += heatingCoil.Efficiency;
    1505            0 :                             if (HeatReclaim.ReclaimEfficiencyTotal > 0.3) {
    1506            0 :                                 ShowSevereError(
    1507              :                                     state,
    1508            0 :                                     format(R"({}, "{}" sum of heat reclaim recovery efficiencies from the same source coil: "{}" cannot be over 0.3)",
    1509              :                                            HVAC::cAllCoilTypes(heatingCoil.HCoilType_Num),
    1510            0 :                                            heatingCoil.Name,
    1511            0 :                                            heatingCoil.ReclaimHeatingCoilName));
    1512              :                             }
    1513              :                         }
    1514            0 :                         state.dataHeatingCoils->ValidSourceType(CoilNum) = true;
    1515              :                     }
    1516            0 :                     break;
    1517              :                 }
    1518            0 :             } break;
    1519            0 :             case HeatObjTypes::COIL_DX_VARIABLE_COOLING: {
    1520            0 :                 for (int DXCoilNum = 1; DXCoilNum <= state.dataVariableSpeedCoils->NumVarSpeedCoils; ++DXCoilNum) {
    1521            0 :                     if (!Util::SameString(state.dataHeatBal->HeatReclaimVS_Coil(DXCoilNum).Name, heatingCoil.ReclaimHeatingCoilName)) {
    1522            0 :                         continue;
    1523              :                     }
    1524            0 :                     heatingCoil.ReclaimHeatingSourceIndexNum = DXCoilNum;
    1525            0 :                     if (allocated(state.dataHeatBal->HeatReclaimVS_Coil)) {
    1526              :                         DataHeatBalance::HeatReclaimDataBase &HeatReclaim =
    1527            0 :                             state.dataHeatBal->HeatReclaimVS_Coil(heatingCoil.ReclaimHeatingSourceIndexNum);
    1528            0 :                         if (!allocated(HeatReclaim.HVACDesuperheaterReclaimedHeat)) {
    1529            0 :                             HeatReclaim.HVACDesuperheaterReclaimedHeat.allocate(state.dataHeatingCoils->NumDesuperheaterCoil);
    1530            0 :                             std::fill(HeatReclaim.HVACDesuperheaterReclaimedHeat.begin(), HeatReclaim.HVACDesuperheaterReclaimedHeat.end(), 0.0);
    1531            0 :                             HeatReclaim.ReclaimEfficiencyTotal += heatingCoil.Efficiency;
    1532            0 :                             if (HeatReclaim.ReclaimEfficiencyTotal > 0.3) {
    1533            0 :                                 ShowSevereError(
    1534              :                                     state,
    1535            0 :                                     format(R"({}, "{}" sum of heat reclaim recovery efficiencies from the same source coil: "{}" cannot be over 0.3)",
    1536              :                                            HVAC::cAllCoilTypes(heatingCoil.HCoilType_Num),
    1537            0 :                                            heatingCoil.Name,
    1538            0 :                                            heatingCoil.ReclaimHeatingCoilName));
    1539              :                             }
    1540              :                         }
    1541            0 :                         state.dataHeatingCoils->ValidSourceType(CoilNum) = true;
    1542              :                     }
    1543            0 :                     break;
    1544              :                 }
    1545              :             case HeatObjTypes::COIL_COOLING_DX_NEW:
    1546              :                 DataHeatBalance::HeatReclaimDataBase &HeatReclaim =
    1547            0 :                     state.dataCoilCoolingDX->coilCoolingDXs[heatingCoil.ReclaimHeatingSourceIndexNum].reclaimHeat;
    1548            0 :                 if (!allocated(HeatReclaim.HVACDesuperheaterReclaimedHeat)) {
    1549            0 :                     HeatReclaim.HVACDesuperheaterReclaimedHeat.allocate(state.dataHeatingCoils->NumDesuperheaterCoil);
    1550            0 :                     std::fill(HeatReclaim.HVACDesuperheaterReclaimedHeat.begin(), HeatReclaim.HVACDesuperheaterReclaimedHeat.end(), 0.0);
    1551            0 :                     HeatReclaim.ReclaimEfficiencyTotal += heatingCoil.Efficiency;
    1552            0 :                     if (HeatReclaim.ReclaimEfficiencyTotal > 0.3) {
    1553            0 :                         ShowSevereError(
    1554              :                             state,
    1555            0 :                             format("{}, \"{}\" sum of heat reclaim recovery efficiencies from the same source coil: \"{}\" cannot be over 0.3",
    1556              :                                    HVAC::cAllCoilTypes(heatingCoil.HCoilType_Num),
    1557            0 :                                    heatingCoil.Name,
    1558            0 :                                    heatingCoil.ReclaimHeatingCoilName));
    1559              :                     }
    1560              :                 }
    1561            0 :                 state.dataHeatingCoils->ValidSourceType(CoilNum) = true;
    1562            0 :                 break;
    1563              :             } break;
    1564            0 :             default:
    1565            0 :                 break;
    1566              :             }
    1567            0 :             if ((state.dataHeatingCoils->ValidSourceTypeCounter > state.dataHeatingCoils->NumDesuperheaterCoil * 2) &&
    1568            0 :                 state.dataHeatingCoils->ShowSingleWarning(CoilNum) && !state.dataHeatingCoils->ValidSourceType(CoilNum)) {
    1569            0 :                 ShowWarningError(state,
    1570            0 :                                  format("Coil:Heating:Desuperheater, \"{}\" desuperheater heat source object name not found: {}",
    1571            0 :                                         heatingCoil.Name,
    1572            0 :                                         heatingCoil.ReclaimHeatingCoilName));
    1573            0 :                 ShowContinueError(state, " Desuperheater heating coil is not modeled and simulation continues.");
    1574            0 :                 state.dataHeatingCoils->ShowSingleWarning(CoilNum) = false;
    1575              :             }
    1576              :         }
    1577       233160 :     }
    1578              : 
    1579           98 :     void SizeHeatingCoil(EnergyPlusData &state, int const CoilNum)
    1580              :     {
    1581              : 
    1582              :         // SUBROUTINE INFORMATION:
    1583              :         //       AUTHOR         Fred Buhl
    1584              :         //       DATE WRITTEN   January 2002
    1585              :         //       MODIFIED       August 2013 Daeho Kang, add component sizing table entries
    1586              :         //       RE-ENGINEERED  Mar 2014 FSEC, moved calculations to common routine in BaseSizer
    1587              : 
    1588              :         // PURPOSE OF THIS SUBROUTINE:
    1589              :         // This subroutine is for sizing Heating Coil Components for which nominal capcities have not been
    1590              :         // specified in the input.
    1591              : 
    1592              :         // METHODOLOGY EMPLOYED:
    1593              :         // Obtains heating capacities from the zone or system sizing arrays or parent object as necessary.
    1594              :         // heating coil or other routine sets up any required data variables (e.g., DataCoilIsSuppHeater, TermUnitPIU, etc.),
    1595              :         // sizing variable (e.g., HeatingCoil( CoilNum ).NominalCapacity in this routine since it can be multi-staged and new routine
    1596              :         // currently only handles single values) and associated string representing that sizing variable.
    1597              :         // Sizer functions handles the actual sizing and reporting.
    1598              : 
    1599              :         // SUBROUTINE PARAMETER DEFINITIONS:
    1600              :         static constexpr std::string_view RoutineName("SizeHeatingCoil: "); // include trailing blank space
    1601              : 
    1602              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    1603           98 :         std::string CompName;       // component name
    1604           98 :         std::string CompType;       // component type
    1605           98 :         std::string SizingString;   // input field sizing description (e.g., Nominal Capacity)
    1606           98 :         bool bPRINT = true;         // TRUE if sizing is reported to output (eio)
    1607              :         Real64 NominalCapacityDes;  // Autosized nominal capacity for reporting
    1608              :         Real64 NominalCapacityUser; // Hardsized nominal capacity for reporting
    1609              :         Real64 TempCap;             // autosized capacity of heating coil [W]
    1610           98 :         int FieldNum = 2;           // IDD numeric field number where input field description is found
    1611           98 :         int NumCoilsSized = 0;      // counter used to deallocate temporary string array after all coils have been sized
    1612              : 
    1613           98 :         auto &heatingCoil = state.dataHeatingCoils->HeatingCoil(CoilNum);
    1614              : 
    1615           98 :         if (heatingCoil.HCoilType_Num == HVAC::Coil_HeatingElectric_MultiStage) {
    1616            9 :             FieldNum = 1 + (heatingCoil.NumOfStages * 2);
    1617            9 :             TempCap = heatingCoil.MSNominalCapacity(heatingCoil.NumOfStages);
    1618           89 :         } else if (heatingCoil.HCoilType_Num == HVAC::Coil_HeatingGas_MultiStage) {
    1619            3 :             FieldNum = 1 + (heatingCoil.NumOfStages * 3);
    1620            3 :             TempCap = heatingCoil.MSNominalCapacity(heatingCoil.NumOfStages);
    1621           86 :         } else if (heatingCoil.HCoilType_Num == HVAC::Coil_HeatingDesuperheater) {
    1622            1 :             return; // no autosizable inputs for desupterheater
    1623              :         } else {
    1624           85 :             FieldNum = 2;
    1625           85 :             TempCap = heatingCoil.NominalCapacity;
    1626              :         }
    1627           97 :         SizingString = state.dataHeatingCoils->HeatingCoilNumericFields(CoilNum).FieldNames(FieldNum) + " [W]";
    1628           97 :         CompType = "Coil:" + heatingCoil.HeatingCoilType + ':' + heatingCoil.HeatingCoilModel;
    1629           97 :         CompName = heatingCoil.Name;
    1630           97 :         state.dataSize->DataCoilIsSuppHeater = state.dataHeatingCoils->CoilIsSuppHeater; // set global instead of using optional argument
    1631           97 :         state.dataSize->DataCoolCoilCap =
    1632              :             0.0; // global only used for heat pump heating coils, non-HP heating coils are sized with other global variables
    1633              : 
    1634           97 :         if (TempCap == DataSizing::AutoSize) {
    1635           42 :             if (heatingCoil.DesiccantRegenerationCoil) {
    1636            3 :                 state.dataSize->DataDesicRegCoil = true;
    1637            3 :                 bPRINT = false;
    1638            3 :                 state.dataSize->DataDesicDehumNum = heatingCoil.DesiccantDehumNum;
    1639            3 :                 HeatingCoilDesAirInletTempSizer sizerHeatingDesInletTemp;
    1640            3 :                 bool ErrorsFound = false;
    1641            3 :                 sizerHeatingDesInletTemp.initializeWithinEP(state, CompType, CompName, bPRINT, RoutineName);
    1642            3 :                 state.dataSize->DataDesInletAirTemp = sizerHeatingDesInletTemp.size(state, DataSizing::AutoSize, ErrorsFound);
    1643              : 
    1644            3 :                 HeatingCoilDesAirOutletTempSizer sizerHeatingDesOutletTemp;
    1645            3 :                 ErrorsFound = false;
    1646            3 :                 sizerHeatingDesOutletTemp.initializeWithinEP(state, CompType, CompName, bPRINT, RoutineName);
    1647            3 :                 state.dataSize->DataDesOutletAirTemp = sizerHeatingDesOutletTemp.size(state, DataSizing::AutoSize, ErrorsFound);
    1648              : 
    1649            3 :                 if (state.dataSize->CurOASysNum > 0) {
    1650            1 :                     auto &OASysEqSizing(state.dataSize->OASysEqSizing(state.dataSize->CurOASysNum));
    1651            1 :                     OASysEqSizing.AirFlow = true;
    1652            1 :                     OASysEqSizing.AirVolFlow = state.dataSize->FinalSysSizing(state.dataSize->CurSysNum).DesOutAirVolFlow;
    1653              :                 }
    1654            3 :                 state.dataSize->DataDesicDehumNum = 0;
    1655            3 :                 bPRINT = true;
    1656            3 :             }
    1657              :         }
    1658           97 :         bool errorsFound = false;
    1659           97 :         HeatingCapacitySizer sizerHeatingCapacity;
    1660           97 :         sizerHeatingCapacity.overrideSizingString(SizingString);
    1661           97 :         sizerHeatingCapacity.initializeWithinEP(state, CompType, CompName, bPRINT, RoutineName);
    1662           97 :         TempCap = sizerHeatingCapacity.size(state, TempCap, errorsFound);
    1663           97 :         state.dataSize->DataCoilIsSuppHeater = false; // reset global to false so other heating coils are not affected
    1664           97 :         state.dataSize->DataDesicRegCoil = false;     // reset global to false so other heating coils are not affected
    1665           97 :         state.dataSize->DataDesInletAirTemp = 0.0;    // reset global data to zero so other heating coils are not
    1666           97 :         state.dataSize->DataDesOutletAirTemp = 0.0;   // reset global data to zero so other heating coils are not affected
    1667              : 
    1668           97 :         if (heatingCoil.HCoilType_Num == HVAC::Coil_HeatingElectric_MultiStage || heatingCoil.HCoilType_Num == HVAC::Coil_HeatingGas_MultiStage) {
    1669           12 :             heatingCoil.MSNominalCapacity(heatingCoil.NumOfStages) = TempCap;
    1670           12 :             bool IsAutoSize = false;
    1671              :             int NumOfStages; // total number of stages of multi-stage heating coil
    1672           12 :             if (any_eq(heatingCoil.MSNominalCapacity, DataSizing::AutoSize)) {
    1673            3 :                 IsAutoSize = true;
    1674              :             }
    1675           12 :             if (IsAutoSize) {
    1676            3 :                 NumOfStages = heatingCoil.NumOfStages;
    1677            6 :                 for (int StageNum = NumOfStages - 1; StageNum >= 1; --StageNum) {
    1678            3 :                     bool ThisStageAutoSize = false;
    1679            3 :                     FieldNum = 1 + StageNum * ((heatingCoil.HCoilType_Num == HVAC::Coil_HeatingElectric_MultiStage) ? 2 : 3);
    1680            3 :                     SizingString = state.dataHeatingCoils->HeatingCoilNumericFields(CoilNum).FieldNames(FieldNum) + " [W]";
    1681            3 :                     if (heatingCoil.MSNominalCapacity(StageNum) == DataSizing::AutoSize) {
    1682            3 :                         ThisStageAutoSize = true;
    1683              :                     }
    1684            3 :                     NominalCapacityDes = TempCap * StageNum / NumOfStages;
    1685            3 :                     if (ThisStageAutoSize) {
    1686            3 :                         heatingCoil.MSNominalCapacity(StageNum) = NominalCapacityDes;
    1687            3 :                         BaseSizer::reportSizerOutput(state, CompType, CompName, "Design Size " + SizingString, NominalCapacityDes);
    1688              :                     } else {
    1689            0 :                         if (heatingCoil.MSNominalCapacity(StageNum) > 0.0 && NominalCapacityDes > 0.0) {
    1690            0 :                             NominalCapacityUser = TempCap * StageNum / NumOfStages; // HeatingCoil( CoilNum ).MSNominalCapacity( StageNum );
    1691            0 :                             BaseSizer::reportSizerOutput(state,
    1692              :                                                          CompType,
    1693              :                                                          CompName,
    1694            0 :                                                          "Design Size " + SizingString,
    1695              :                                                          NominalCapacityDes,
    1696            0 :                                                          "User-Specified " + SizingString,
    1697              :                                                          NominalCapacityUser);
    1698            0 :                             if (state.dataGlobal->DisplayExtraWarnings) {
    1699            0 :                                 if ((std::abs(NominalCapacityDes - NominalCapacityUser) / NominalCapacityUser) >
    1700            0 :                                     state.dataSize->AutoVsHardSizingThreshold) {
    1701            0 :                                     ShowMessage(state,
    1702            0 :                                                 format("SizeHeatingCoil: Potential issue with equipment sizing for {}, {}", CompType, CompName));
    1703            0 :                                     ShowContinueError(state, format("User-Specified Nominal Capacity of {:.2R} [W]", NominalCapacityUser));
    1704            0 :                                     ShowContinueError(state, format("differs from Design Size Nominal Capacity of {:.2R} [W]", NominalCapacityDes));
    1705            0 :                                     ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
    1706            0 :                                     ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
    1707              :                                 }
    1708              :                             }
    1709              :                         }
    1710              :                     }
    1711              :                 }
    1712              :             } else { // No autosize
    1713            9 :                 NumOfStages = heatingCoil.NumOfStages;
    1714           17 :                 for (int StageNum = NumOfStages - 1; StageNum >= 1; --StageNum) {
    1715            8 :                     if (heatingCoil.MSNominalCapacity(StageNum) > 0.0) {
    1716           24 :                         BaseSizer::reportSizerOutput(
    1717           16 :                             state, CompType, CompName, "User-Specified " + SizingString, heatingCoil.MSNominalCapacity(StageNum));
    1718              :                     }
    1719              :                 }
    1720              :             }
    1721              :             // Ensure capacity at lower Stage must be lower or equal to the capacity at higher Stage.
    1722           23 :             for (int StageNum = 1; StageNum <= heatingCoil.NumOfStages - 1; ++StageNum) {
    1723           11 :                 if (heatingCoil.MSNominalCapacity(StageNum) > heatingCoil.MSNominalCapacity(StageNum + 1)) {
    1724            0 :                     ShowSevereError(state,
    1725            0 :                                     format("SizeHeatingCoil: {} {}, Stage {} Nominal Capacity ({:.2R} W) must be less than or equal to Stage {} "
    1726              :                                            "Nominal Capacity ({:.2R} W).",
    1727            0 :                                            heatingCoil.HeatingCoilType,
    1728            0 :                                            heatingCoil.Name,
    1729              :                                            StageNum,
    1730              :                                            heatingCoil.MSNominalCapacity(StageNum),
    1731            0 :                                            StageNum + 1,
    1732              :                                            heatingCoil.MSNominalCapacity(StageNum + 1)));
    1733            0 :                     ShowFatalError(state, "Preceding conditions cause termination.");
    1734              :                 }
    1735              :             }
    1736           12 :         } else { // not a multi-speed coil
    1737           85 :             heatingCoil.NominalCapacity = TempCap;
    1738              :         }
    1739              : 
    1740           97 :         if (++NumCoilsSized == state.dataHeatingCoils->NumHeatingCoils) {
    1741           44 :             state.dataHeatingCoils->HeatingCoilNumericFields.deallocate(); // remove temporary array for field names at end of sizing
    1742              :         }
    1743              : 
    1744              :         // create predefined report entries
    1745           97 :         switch (heatingCoil.HCoilType_Num) {
    1746           39 :         case HVAC::Coil_HeatingElectric: {
    1747           39 :             OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchHeatCoilType, heatingCoil.Name, "Coil:Heating:Electric");
    1748           78 :             OutputReportPredefined::PreDefTableEntry(
    1749           39 :                 state, state.dataOutRptPredefined->pdchHeatCoilNomCap, heatingCoil.Name, heatingCoil.NominalCapacity);
    1750           39 :             OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchHeatCoilNomEff, heatingCoil.Name, heatingCoil.Efficiency);
    1751           39 :         } break;
    1752            9 :         case HVAC::Coil_HeatingElectric_MultiStage: {
    1753           18 :             OutputReportPredefined::PreDefTableEntry(
    1754            9 :                 state, state.dataOutRptPredefined->pdchHeatCoilType, heatingCoil.Name, "Coil:Heating:Electric:MultiStage");
    1755           18 :             OutputReportPredefined::PreDefTableEntry(
    1756            9 :                 state, state.dataOutRptPredefined->pdchHeatCoilNomCap, heatingCoil.Name, heatingCoil.MSNominalCapacity(heatingCoil.NumOfStages));
    1757           18 :             OutputReportPredefined::PreDefTableEntry(
    1758            9 :                 state, state.dataOutRptPredefined->pdchHeatCoilNomEff, heatingCoil.Name, heatingCoil.MSEfficiency(heatingCoil.NumOfStages));
    1759            9 :         } break;
    1760           46 :         case HVAC::Coil_HeatingGasOrOtherFuel: {
    1761           46 :             OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchHeatCoilType, heatingCoil.Name, "Coil:Heating:Fuel");
    1762           92 :             OutputReportPredefined::PreDefTableEntry(
    1763           46 :                 state, state.dataOutRptPredefined->pdchHeatCoilNomCap, heatingCoil.Name, heatingCoil.NominalCapacity);
    1764           46 :             OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchHeatCoilNomEff, heatingCoil.Name, heatingCoil.Efficiency);
    1765           46 :         } break;
    1766            3 :         case HVAC::Coil_HeatingGas_MultiStage: {
    1767            6 :             OutputReportPredefined::PreDefTableEntry(
    1768            3 :                 state, state.dataOutRptPredefined->pdchHeatCoilType, heatingCoil.Name, "Coil:Heating:Gas:MultiStage");
    1769            6 :             OutputReportPredefined::PreDefTableEntry(
    1770            3 :                 state, state.dataOutRptPredefined->pdchHeatCoilNomCap, heatingCoil.Name, heatingCoil.MSNominalCapacity(heatingCoil.NumOfStages));
    1771            6 :             OutputReportPredefined::PreDefTableEntry(
    1772            3 :                 state, state.dataOutRptPredefined->pdchHeatCoilNomEff, heatingCoil.Name, heatingCoil.MSEfficiency(heatingCoil.NumOfStages));
    1773            3 :         } break;
    1774            0 :         case HVAC::Coil_HeatingDesuperheater: {
    1775            0 :             OutputReportPredefined::PreDefTableEntry(
    1776            0 :                 state, state.dataOutRptPredefined->pdchHeatCoilType, heatingCoil.Name, "Coil:Heating:Desuperheater");
    1777            0 :             OutputReportPredefined::PreDefTableEntry(
    1778            0 :                 state, state.dataOutRptPredefined->pdchHeatCoilNomCap, heatingCoil.Name, heatingCoil.NominalCapacity);
    1779            0 :             OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchHeatCoilNomEff, heatingCoil.Name, heatingCoil.Efficiency);
    1780            0 :         } break;
    1781            0 :         default:
    1782            0 :             break;
    1783              :         }
    1784              : 
    1785              :         // std 229 heating coils existing table adding new variables:
    1786              :         // pdchHeatCoilUsedAsSupHeat is now reported at coil selection report
    1787              :         // pdchHeatCoilAirloopName is now reported at coil selection report
    1788              :         // std 229 Coil Connections New table: now all reported at coil selection report
    1789          100 :     }
    1790              : 
    1791        73698 :     void CalcElectricHeatingCoil(EnergyPlusData &state,
    1792              :                                  int const CoilNum, // index to heating coil
    1793              :                                  Real64 &QCoilReq,
    1794              :                                  Real64 &QCoilActual,       // coil load actually delivered (W)
    1795              :                                  HVAC::FanOp const fanOp,   // fan operating mode
    1796              :                                  Real64 const PartLoadRatio // part-load ratio of heating coil
    1797              :     )
    1798              :     {
    1799              :         // SUBROUTINE INFORMATION:
    1800              :         //       AUTHOR         Rich Liesen
    1801              :         //       DATE WRITTEN   May 2000
    1802              :         //       MODIFIED       Jul. 2016, R. Zhang, Applied the coil supply air temperature sensor offset
    1803              : 
    1804              :         // PURPOSE OF THIS SUBROUTINE:
    1805              :         // Simulates a simple Electric heating coil with an efficiency
    1806              : 
    1807              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    1808              :         Real64 AirMassFlow; // [kg/sec]
    1809              :         Real64 TempAirOut;  // [C]
    1810              :         Real64 HeatingCoilLoad;
    1811              :         Real64 QCoilCap;
    1812              : 
    1813        73698 :         auto &heatingCoil = state.dataHeatingCoils->HeatingCoil(CoilNum);
    1814              : 
    1815        73698 :         Real64 Effic = heatingCoil.Efficiency;
    1816        73698 :         Real64 TempAirIn = heatingCoil.InletAirTemp;
    1817        73698 :         Real64 Win = heatingCoil.InletAirHumRat;
    1818        73698 :         Real64 TempSetPoint = heatingCoil.DesiredOutletTemp;
    1819              : 
    1820              :         // If there is a fault of coil SAT Sensor
    1821        73698 :         if (heatingCoil.FaultyCoilSATFlag && (!state.dataGlobal->WarmupFlag) && (!state.dataGlobal->DoingSizing) &&
    1822            0 :             (!state.dataGlobal->KickOffSimulation)) {
    1823              :             // calculate the sensor offset using fault information
    1824            0 :             int FaultIndex = heatingCoil.FaultyCoilSATIndex;
    1825            0 :             heatingCoil.FaultyCoilSATOffset = state.dataFaultsMgr->FaultsCoilSATSensor(FaultIndex).CalFaultOffsetAct(state);
    1826              :             // update the TempSetPoint
    1827            0 :             TempSetPoint -= heatingCoil.FaultyCoilSATOffset;
    1828              :         }
    1829              : 
    1830              :         //  adjust mass flow rates for cycling fan cycling coil operation
    1831        73698 :         if (fanOp == HVAC::FanOp::Cycling) {
    1832        61853 :             if (PartLoadRatio > 0.0) {
    1833        61465 :                 AirMassFlow = heatingCoil.InletAirMassFlowRate / PartLoadRatio;
    1834        61465 :                 QCoilReq /= PartLoadRatio;
    1835              :             } else {
    1836          388 :                 AirMassFlow = 0.0;
    1837              :             }
    1838              :         } else {
    1839        11845 :             AirMassFlow = heatingCoil.InletAirMassFlowRate;
    1840              :         }
    1841              : 
    1842        73698 :         Real64 CapacitanceAir = Psychrometrics::PsyCpAirFnW(Win) * AirMassFlow;
    1843              : 
    1844              :         // If the coil is operating there should be some heating capacitance
    1845              :         //  across the coil, so do the simulation. If not set outlet to inlet and no load.
    1846              :         //  Also the coil has to be scheduled to be available.
    1847              : 
    1848              :         // Control output to meet load QCoilReq (QCoilReq is passed in if load controlled, otherwise QCoilReq=-999)
    1849        73698 :         if ((AirMassFlow > 0.0 && heatingCoil.NominalCapacity > 0.0) && (heatingCoil.availSched->getCurrentVal() > 0.0) && (QCoilReq > 0.0)) {
    1850              : 
    1851              :             // check to see if the Required heating capacity is greater than the user specified capacity.
    1852         3697 :             if (QCoilReq > heatingCoil.NominalCapacity) {
    1853            2 :                 QCoilCap = heatingCoil.NominalCapacity;
    1854              :             } else {
    1855         3695 :                 QCoilCap = QCoilReq;
    1856              :             }
    1857              : 
    1858         3697 :             TempAirOut = TempAirIn + QCoilCap / CapacitanceAir;
    1859         3697 :             HeatingCoilLoad = QCoilCap;
    1860              : 
    1861              :             // The HeatingCoilLoad is the change in the enthalpy of the Heating
    1862         3697 :             heatingCoil.ElecUseLoad = HeatingCoilLoad / Effic;
    1863              : 
    1864              :             // Control coil output to meet a setpoint temperature.
    1865        50320 :         } else if ((AirMassFlow > 0.0 && heatingCoil.NominalCapacity > 0.0) && (heatingCoil.availSched->getCurrentVal() > 0.0) &&
    1866       120321 :                    (QCoilReq == DataLoopNode::SensedLoadFlagValue) && (std::abs(TempSetPoint - TempAirIn) > HVAC::TempControlTol)) {
    1867              : 
    1868         1926 :             QCoilCap = CapacitanceAir * (TempSetPoint - TempAirIn);
    1869              :             // check to see if setpoint above enetering temperature. If not, set
    1870              :             // output to zero.
    1871         1926 :             if (QCoilCap <= 0.0) {
    1872          129 :                 QCoilCap = 0.0;
    1873          129 :                 TempAirOut = TempAirIn;
    1874              :                 // check to see if the Required heating capacity is greater than the user
    1875              :                 // specified capacity.
    1876         1797 :             } else if (QCoilCap > heatingCoil.NominalCapacity) {
    1877          100 :                 QCoilCap = heatingCoil.NominalCapacity;
    1878          100 :                 TempAirOut = TempAirIn + QCoilCap / CapacitanceAir;
    1879              :             } else {
    1880         1697 :                 TempAirOut = TempSetPoint;
    1881              :             }
    1882              : 
    1883         1926 :             HeatingCoilLoad = QCoilCap;
    1884              : 
    1885              :             // The HeatingCoilLoad is the change in the enthalpy of the Heating
    1886         1926 :             heatingCoil.ElecUseLoad = HeatingCoilLoad / Effic;
    1887              : 
    1888              :         } else { // If not running Conditions do not change across coil from inlet to outlet
    1889              : 
    1890        68075 :             TempAirOut = TempAirIn;
    1891        68075 :             HeatingCoilLoad = 0.0;
    1892        68075 :             heatingCoil.ElecUseLoad = 0.0;
    1893              :         }
    1894              : 
    1895        73698 :         if (fanOp == HVAC::FanOp::Cycling) {
    1896        61853 :             heatingCoil.ElecUseLoad *= PartLoadRatio;
    1897        61853 :             HeatingCoilLoad *= PartLoadRatio;
    1898              :         }
    1899              : 
    1900        73698 :         heatingCoil.HeatingCoilLoad = HeatingCoilLoad;
    1901              : 
    1902              :         // Set the outlet conditions
    1903        73698 :         heatingCoil.OutletAirTemp = TempAirOut;
    1904              : 
    1905              :         // This HeatingCoil does not change the moisture or Mass Flow across the component
    1906        73698 :         heatingCoil.OutletAirHumRat = heatingCoil.InletAirHumRat;
    1907        73698 :         heatingCoil.OutletAirMassFlowRate = heatingCoil.InletAirMassFlowRate;
    1908              :         // Set the outlet enthalpys for air and Heating
    1909        73698 :         heatingCoil.OutletAirEnthalpy = Psychrometrics::PsyHFnTdbW(heatingCoil.OutletAirTemp, heatingCoil.OutletAirHumRat);
    1910              : 
    1911        73698 :         QCoilActual = HeatingCoilLoad;
    1912        73698 :         if (std::abs(heatingCoil.NominalCapacity) < 1.e-8) {
    1913           21 :             if (heatingCoil.AirLoopNum > 0) {
    1914            0 :                 state.dataAirLoop->AirLoopAFNInfo(heatingCoil.AirLoopNum).AFNLoopHeatingCoilMaxRTF =
    1915            0 :                     max(state.dataAirLoop->AirLoopAFNInfo(heatingCoil.AirLoopNum).AFNLoopHeatingCoilMaxRTF, 0.0);
    1916              :             }
    1917              :         } else {
    1918        73677 :             if (heatingCoil.AirLoopNum > 0) {
    1919        61404 :                 state.dataAirLoop->AirLoopAFNInfo(heatingCoil.AirLoopNum).AFNLoopHeatingCoilMaxRTF =
    1920        61404 :                     max(state.dataAirLoop->AirLoopAFNInfo(heatingCoil.AirLoopNum).AFNLoopHeatingCoilMaxRTF,
    1921        61404 :                         HeatingCoilLoad / heatingCoil.NominalCapacity);
    1922              :             }
    1923              :         }
    1924              : 
    1925              :         // set outlet node temp so parent objects can call calc directly without have to simulate entire model
    1926        73698 :         state.dataLoopNodes->Node(heatingCoil.AirOutletNodeNum).Temp = heatingCoil.OutletAirTemp;
    1927        73698 :     }
    1928              : 
    1929          247 :     void CalcMultiStageElectricHeatingCoil(EnergyPlusData &state,
    1930              :                                            int const CoilNum,       // the number of the electric heating coil to be simulated
    1931              :                                            Real64 const SpeedRatio, // SpeedRatio varies between 1.0 (maximum speed) and 0.0 (minimum speed)
    1932              :                                            Real64 const CycRatio,   // cycling part load ratio
    1933              :                                            int const StageNum,      // Stage number
    1934              :                                            HVAC::FanOp const fanOp, // Fan operation mode
    1935              :                                            Real64 &QCoilActual,     // coil load actually delivered (W)
    1936              :                                            bool const SuppHeat)
    1937              :     {
    1938              : 
    1939              :         // SUBROUTINE INFORMATION:
    1940              :         //       AUTHOR         Chandan Sharma, FSEC
    1941              :         //       DATE WRITTEN   January 2013
    1942              : 
    1943              :         // PURPOSE OF THIS SUBROUTINE:
    1944              :         // Calculates the air-side performance and electrical energy use of multistage electric heating coil.
    1945              : 
    1946              :         // METHODOLOGY EMPLOYED:
    1947              :         // Uses the same methodology as the single stage electric heating unit model (SUBROUTINE CalcelectricHeatingCoil).
    1948              :         // In addition it assumes that the unit performance is obtained by interpolating between
    1949              :         // the performance at high stage and that at low stage. If the output needed is below
    1950              :         // that produced at low stage, the coil cycles between off and low stage.
    1951              : 
    1952              :         // SUBROUTINE PARAMETER DEFINITIONS:
    1953              :         static constexpr std::string_view RoutineName = "CalcMultiStageElectricHeatingCoil";
    1954              :         static constexpr std::string_view RoutineNameAverageLoad = "CalcMultiStageElectricHeatingCoil:Averageload";
    1955              :         static constexpr std::string_view RoutineNameFullLoad = "CalcMultiStageElectricHeatingCoil:fullload";
    1956              : 
    1957              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    1958              :         Real64 OutletAirEnthalpy;    // outlet air enthalpy [J/kg]
    1959              :         Real64 OutletAirHumRat;      // outlet air humidity ratio [kg/kg]
    1960              :         Real64 TotCapHS;             // total capacity at high stage [W]
    1961              :         Real64 TotCapLS;             // total capacity at low stage [W]
    1962              :         Real64 TotCap;               // total capacity at current stage [W]
    1963              :         Real64 EffHS;                // total capacity at high stage [W]
    1964              :         Real64 EffLS;                // total capacity at low stage [W]
    1965              :         int StageNumHS;              // High stage number
    1966              :         int StageNumLS;              // Low stage number
    1967              :         Real64 FullLoadOutAirEnth;   // Outlet full load enthalpy
    1968              :         Real64 FullLoadOutAirHumRat; // Outlet humidity ratio at full load
    1969              :         Real64 FullLoadOutAirTemp;   // Outlet temperature at full load
    1970              :         Real64 FullLoadOutAirRH;     // Outler relative humidity at full load
    1971              :         Real64 OutletAirTemp;        // Supply ari temperature
    1972              :         Real64 LSElecHeatingPower;   // Full load power at low stage
    1973              :         Real64 HSElecHeatingPower;   // Full load power at high stage
    1974              :         Real64 PartLoadRat;          // part load ratio
    1975              : 
    1976          247 :         auto &heatingCoil = state.dataHeatingCoils->HeatingCoil(CoilNum);
    1977          247 :         if (StageNum > 1) {
    1978           87 :             StageNumLS = StageNum - 1;
    1979           87 :             StageNumHS = StageNum;
    1980           87 :             if (StageNum > heatingCoil.NumOfStages) {
    1981            0 :                 StageNumLS = heatingCoil.NumOfStages - 1;
    1982            0 :                 StageNumHS = heatingCoil.NumOfStages;
    1983              :             }
    1984              :         } else {
    1985          160 :             StageNumLS = 1;
    1986          160 :             StageNumHS = 1;
    1987              :         }
    1988              : 
    1989          247 :         Real64 AirMassFlow = heatingCoil.InletAirMassFlowRate;
    1990          247 :         Real64 InletAirDryBulbTemp = heatingCoil.InletAirTemp;
    1991          247 :         Real64 InletAirEnthalpy = heatingCoil.InletAirEnthalpy;
    1992          247 :         Real64 InletAirHumRat = heatingCoil.InletAirHumRat;
    1993              : 
    1994          247 :         Real64 OutdoorPressure = state.dataEnvrn->OutBaroPress;
    1995              : 
    1996          247 :         if ((AirMassFlow > 0.0) && (heatingCoil.availSched->getCurrentVal() > 0.0) && ((CycRatio > 0.0) || (SpeedRatio > 0.0))) {
    1997              : 
    1998          137 :             if (StageNum > 1) {
    1999              : 
    2000           85 :                 TotCapLS = heatingCoil.MSNominalCapacity(StageNumLS);
    2001           85 :                 TotCapHS = heatingCoil.MSNominalCapacity(StageNumHS);
    2002              : 
    2003           85 :                 EffLS = heatingCoil.MSEfficiency(StageNumLS);
    2004           85 :                 EffHS = heatingCoil.MSEfficiency(StageNumHS);
    2005              : 
    2006              :                 // Get full load output and power
    2007           85 :                 LSElecHeatingPower = TotCapLS / EffLS;
    2008           85 :                 HSElecHeatingPower = TotCapHS / EffHS;
    2009           85 :                 OutletAirHumRat = InletAirHumRat;
    2010              : 
    2011              :                 // if cycling fan, send coil part-load fraction to on/off fan via HVACDataGlobals
    2012              :                 // IF (FanOpMode .EQ. FanOp::Cycling) OnOffFanPartLoadFraction = 1.0d0
    2013              : 
    2014              :                 // Power calculation
    2015           85 :                 heatingCoil.ElecUseLoad = SpeedRatio * HSElecHeatingPower + (1.0 - SpeedRatio) * LSElecHeatingPower;
    2016              : 
    2017           85 :                 heatingCoil.HeatingCoilLoad = TotCapHS * SpeedRatio + TotCapLS * (1.0 - SpeedRatio);
    2018              : 
    2019           85 :                 OutletAirEnthalpy = InletAirEnthalpy + heatingCoil.HeatingCoilLoad / heatingCoil.InletAirMassFlowRate;
    2020           85 :                 OutletAirTemp = Psychrometrics::PsyTdbFnHW(OutletAirEnthalpy, OutletAirHumRat);
    2021           85 :                 FullLoadOutAirRH = Psychrometrics::PsyRhFnTdbWPb(state, OutletAirTemp, OutletAirHumRat, OutdoorPressure, RoutineNameAverageLoad);
    2022              : 
    2023           85 :                 if (FullLoadOutAirRH > 1.0) { // Limit to saturated conditions at FullLoadOutAirEnth
    2024            0 :                     OutletAirTemp = Psychrometrics::PsyTsatFnHPb(state, OutletAirEnthalpy, OutdoorPressure, RoutineName);
    2025            0 :                     OutletAirHumRat = Psychrometrics::PsyWFnTdbH(state, OutletAirTemp, OutletAirEnthalpy, RoutineName);
    2026              :                 }
    2027              : 
    2028           85 :                 heatingCoil.OutletAirTemp = OutletAirTemp;
    2029           85 :                 heatingCoil.OutletAirHumRat = OutletAirHumRat;
    2030           85 :                 heatingCoil.OutletAirEnthalpy = OutletAirEnthalpy;
    2031           85 :                 heatingCoil.OutletAirMassFlowRate = heatingCoil.InletAirMassFlowRate;
    2032              : 
    2033              :                 // Stage 1
    2034           52 :             } else if (CycRatio > 0.0) {
    2035              : 
    2036           50 :                 PartLoadRat = min(1.0, CycRatio);
    2037              : 
    2038              :                 // for cycling fan, reset mass flow to full on rate
    2039           50 :                 if (fanOp == HVAC::FanOp::Cycling) {
    2040           20 :                     AirMassFlow /= PartLoadRat;
    2041           30 :                 } else if (fanOp == HVAC::FanOp::Continuous) {
    2042           30 :                     if (!SuppHeat) {
    2043           24 :                         AirMassFlow = state.dataHVACGlobal->MSHPMassFlowRateLow;
    2044              :                     }
    2045              :                 }
    2046              : 
    2047           50 :                 TotCap = heatingCoil.MSNominalCapacity(StageNumLS);
    2048              : 
    2049              :                 // Calculate full load outlet conditions
    2050           50 :                 FullLoadOutAirEnth = InletAirEnthalpy + TotCap / AirMassFlow;
    2051           50 :                 FullLoadOutAirHumRat = InletAirHumRat;
    2052           50 :                 FullLoadOutAirTemp = Psychrometrics::PsyTdbFnHW(FullLoadOutAirEnth, FullLoadOutAirHumRat);
    2053              :                 FullLoadOutAirRH =
    2054           50 :                     Psychrometrics::PsyRhFnTdbWPb(state, FullLoadOutAirTemp, FullLoadOutAirHumRat, OutdoorPressure, RoutineNameFullLoad);
    2055              : 
    2056           50 :                 if (FullLoadOutAirRH > 1.0) { // Limit to saturated conditions at FullLoadOutAirEnth
    2057            0 :                     FullLoadOutAirTemp = Psychrometrics::PsyTsatFnHPb(state, FullLoadOutAirEnth, OutdoorPressure, RoutineName);
    2058              :                     //  Eventually inlet air conditions will be used in electric Coil, these lines are commented out and marked with this comment
    2059              :                     //  line FullLoadOutAirTemp = PsyTsatFnHPb(FullLoadOutAirEnth,InletAirPressure)
    2060            0 :                     FullLoadOutAirHumRat = Psychrometrics::PsyWFnTdbH(state, FullLoadOutAirTemp, FullLoadOutAirEnth, RoutineName);
    2061              :                 }
    2062              : 
    2063              :                 // Set outlet conditions from the full load calculation
    2064           50 :                 if (fanOp == HVAC::FanOp::Cycling) {
    2065           20 :                     OutletAirEnthalpy = FullLoadOutAirEnth;
    2066           20 :                     OutletAirHumRat = FullLoadOutAirHumRat;
    2067           20 :                     OutletAirTemp = FullLoadOutAirTemp;
    2068              :                 } else {
    2069           30 :                     OutletAirEnthalpy = PartLoadRat * FullLoadOutAirEnth + (1.0 - PartLoadRat) * InletAirEnthalpy;
    2070           30 :                     OutletAirHumRat = PartLoadRat * FullLoadOutAirHumRat + (1.0 - PartLoadRat) * InletAirHumRat;
    2071           30 :                     OutletAirTemp = PartLoadRat * FullLoadOutAirTemp + (1.0 - PartLoadRat) * InletAirDryBulbTemp;
    2072              :                 }
    2073              : 
    2074           50 :                 EffLS = heatingCoil.MSEfficiency(StageNumLS);
    2075              : 
    2076              :                 //    HeatingCoil(CoilNum)%HeatingCoilLoad = TotCap
    2077              :                 //   This would require a CR to change
    2078           50 :                 heatingCoil.HeatingCoilLoad = TotCap * PartLoadRat;
    2079              : 
    2080           50 :                 heatingCoil.ElecUseLoad = heatingCoil.HeatingCoilLoad / EffLS;
    2081              : 
    2082           50 :                 heatingCoil.OutletAirTemp = OutletAirTemp;
    2083           50 :                 heatingCoil.OutletAirHumRat = OutletAirHumRat;
    2084           50 :                 heatingCoil.OutletAirEnthalpy = OutletAirEnthalpy;
    2085           50 :                 heatingCoil.OutletAirMassFlowRate = heatingCoil.InletAirMassFlowRate;
    2086              :                 // this would require a CR to correct (i.e., calculate outputs when coil is off)
    2087              :                 //  ELSE
    2088              :                 //    ! electric coil is off; just pass through conditions
    2089              :                 //    HeatingCoil(CoilNum)%OutletAirEnthalpy = HeatingCoil(CoilNum)%InletAirEnthalpy
    2090              :                 //    HeatingCoil(CoilNum)%OutletAirHumRat   = HeatingCoil(CoilNum)%InletAirHumRat
    2091              :                 //    HeatingCoil(CoilNum)%OutletAirTemp     = HeatingCoil(CoilNum)%InletAirTemp
    2092              :                 //    HeatingCoil(CoilNum)%OutletAirMassFlowRate = HeatingCoil(CoilNum)%InletAirMassFlowRate
    2093              :                 //    HeatingCoil(CoilNum)%ElecUseLoad      = 0.0
    2094              :                 //    HeatingCoil(CoilNum)%HeatingCoilLoad  = 0.0
    2095              :                 //    ElecHeatingCoilPower                  = 0.0
    2096              :             }
    2097              : 
    2098              :         } else {
    2099              : 
    2100              :             // electric coil is off; just pass through conditions
    2101          110 :             heatingCoil.OutletAirEnthalpy = heatingCoil.InletAirEnthalpy;
    2102          110 :             heatingCoil.OutletAirHumRat = heatingCoil.InletAirHumRat;
    2103          110 :             heatingCoil.OutletAirTemp = heatingCoil.InletAirTemp;
    2104          110 :             heatingCoil.OutletAirMassFlowRate = heatingCoil.InletAirMassFlowRate;
    2105              : 
    2106              :             // some of these are reset in Init, can be removed to speed up code
    2107          110 :             heatingCoil.ElecUseLoad = 0.0;
    2108          110 :             heatingCoil.HeatingCoilLoad = 0.0;
    2109              : 
    2110              :         } // end of on/off if - else
    2111              : 
    2112              :         // set outlet node temp so parent objects can call calc directly without have to simulate entire model
    2113          247 :         state.dataLoopNodes->Node(heatingCoil.AirOutletNodeNum).Temp = heatingCoil.OutletAirTemp;
    2114              : 
    2115          247 :         QCoilActual = heatingCoil.HeatingCoilLoad;
    2116          247 :     }
    2117              : 
    2118       159191 :     void CalcFuelHeatingCoil(EnergyPlusData &state,
    2119              :                              int const CoilNum, // index to heating coil
    2120              :                              Real64 const QCoilReq,
    2121              :                              Real64 &QCoilActual,                        // coil load actually delivered (W)
    2122              :                              HVAC::FanOp const fanOp,                    // fan operating mode
    2123              :                              [[maybe_unused]] Real64 const PartLoadRatio // part-load ratio of heating coil
    2124              :     )
    2125              :     {
    2126              :         // SUBROUTINE INFORMATION:
    2127              :         //       AUTHOR         Rich Liesen
    2128              :         //       DATE WRITTEN   May 2000
    2129              :         //       MODIFIED       Jul. 2016, R. Zhang, Applied the coil supply air temperature sensor offset
    2130              : 
    2131              :         // PURPOSE OF THIS SUBROUTINE:
    2132              :         // Simulates a simple Gas heating coil with a burner efficiency
    2133              : 
    2134              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    2135              :         Real64 TempAirOut; // [C]
    2136              :         Real64 HeatingCoilLoad;
    2137              :         Real64 QCoilCap;
    2138              :         Real64 PartLoadRat;
    2139              :         Real64 PLF;
    2140              : 
    2141       159191 :         auto &heatingCoil = state.dataHeatingCoils->HeatingCoil(CoilNum);
    2142              : 
    2143       159191 :         Real64 Effic = heatingCoil.Efficiency;
    2144       159191 :         Real64 TempAirIn = heatingCoil.InletAirTemp;
    2145       159191 :         Real64 Win = heatingCoil.InletAirHumRat;
    2146       159191 :         Real64 TempSetPoint = heatingCoil.DesiredOutletTemp;
    2147       159191 :         Real64 AirMassFlow = heatingCoil.InletAirMassFlowRate;
    2148              : 
    2149       159191 :         Real64 CapacitanceAir = Psychrometrics::PsyCpAirFnW(Win) * AirMassFlow;
    2150              : 
    2151              :         // If there is a fault of coil SAT Sensor
    2152       159191 :         if (heatingCoil.FaultyCoilSATFlag && (!state.dataGlobal->WarmupFlag) && (!state.dataGlobal->DoingSizing) &&
    2153            0 :             (!state.dataGlobal->KickOffSimulation)) {
    2154              :             // calculate the sensor offset using fault information
    2155            0 :             int FaultIndex = heatingCoil.FaultyCoilSATIndex;
    2156            0 :             heatingCoil.FaultyCoilSATOffset = state.dataFaultsMgr->FaultsCoilSATSensor(FaultIndex).CalFaultOffsetAct(state);
    2157              :             // update the TempSetPoint
    2158            0 :             TempSetPoint -= heatingCoil.FaultyCoilSATOffset;
    2159              :         }
    2160              : 
    2161              :         // If the coil is operating there should be some heating capacitance
    2162              :         //  across the coil, so do the simulation. If not set outlet to inlet and no load.
    2163              :         //  Also the coil has to be scheduled to be available.
    2164              : 
    2165              :         // Control output to meet load QCoilReq (QCoilReq is passed in if load controlled, otherwise QCoilReq=-999)
    2166       159191 :         if ((AirMassFlow > 0.0 && heatingCoil.NominalCapacity > 0.0) && (heatingCoil.availSched->getCurrentVal() > 0.0) && (QCoilReq > 0.0)) {
    2167              : 
    2168              :             // check to see if the Required heating capacity is greater than the user specified capacity.
    2169        12652 :             if (QCoilReq > heatingCoil.NominalCapacity) {
    2170         2680 :                 QCoilCap = heatingCoil.NominalCapacity;
    2171              :             } else {
    2172         9972 :                 QCoilCap = QCoilReq;
    2173              :             }
    2174              : 
    2175        12652 :             TempAirOut = TempAirIn + QCoilCap / CapacitanceAir;
    2176        12652 :             HeatingCoilLoad = QCoilCap;
    2177              : 
    2178        12652 :             PartLoadRat = HeatingCoilLoad / heatingCoil.NominalCapacity;
    2179              : 
    2180              :             // The HeatingCoilLoad is the change in the enthalpy of the Heating
    2181        12652 :             heatingCoil.FuelUseLoad = HeatingCoilLoad / Effic;
    2182        12652 :             heatingCoil.ElecUseLoad = heatingCoil.ParasiticElecLoad * PartLoadRat;
    2183        12652 :             heatingCoil.ParasiticFuelRate = heatingCoil.ParasiticFuelCapacity * (1.0 - PartLoadRat);
    2184              : 
    2185              :             // Control coil output to meet a setpoint temperature.
    2186       112994 :         } else if ((AirMassFlow > 0.0 && heatingCoil.NominalCapacity > 0.0) && (heatingCoil.availSched->getCurrentVal() > 0.0) &&
    2187       259533 :                    (QCoilReq == DataLoopNode::SensedLoadFlagValue) && (std::abs(TempSetPoint - TempAirIn) > HVAC::TempControlTol)) {
    2188              : 
    2189        15405 :             QCoilCap = CapacitanceAir * (TempSetPoint - TempAirIn);
    2190              :             // check to see if setpoint above entering temperature. If not, set
    2191              :             // output to zero.
    2192        15405 :             if (QCoilCap <= 0.0) {
    2193           43 :                 QCoilCap = 0.0;
    2194           43 :                 TempAirOut = TempAirIn;
    2195              :                 // check to see if the Required heating capacity is greater than the user
    2196              :                 // specified capacity.
    2197        15362 :             } else if (QCoilCap > heatingCoil.NominalCapacity) {
    2198        10429 :                 QCoilCap = heatingCoil.NominalCapacity;
    2199        10429 :                 TempAirOut = TempAirIn + QCoilCap / CapacitanceAir;
    2200              :             } else {
    2201         4933 :                 TempAirOut = TempSetPoint;
    2202              :             }
    2203              : 
    2204        15405 :             HeatingCoilLoad = QCoilCap;
    2205              : 
    2206        15405 :             PartLoadRat = HeatingCoilLoad / heatingCoil.NominalCapacity;
    2207              : 
    2208              :             // The HeatingCoilLoad is the change in the enthalpy of the Heating
    2209        15405 :             heatingCoil.FuelUseLoad = HeatingCoilLoad / Effic;
    2210        15405 :             heatingCoil.ElecUseLoad = heatingCoil.ParasiticElecLoad * PartLoadRat;
    2211        15405 :             heatingCoil.ParasiticFuelRate = heatingCoil.ParasiticFuelCapacity * (1.0 - PartLoadRat);
    2212              : 
    2213              :         } else { // If not running Conditions do not change across coil from inlet to outlet
    2214              : 
    2215       131134 :             TempAirOut = TempAirIn;
    2216       131134 :             HeatingCoilLoad = 0.0;
    2217       131134 :             PartLoadRat = 0.0;
    2218       131134 :             heatingCoil.FuelUseLoad = 0.0;
    2219       131134 :             heatingCoil.ElecUseLoad = 0.0;
    2220       131134 :             heatingCoil.ParasiticFuelRate = heatingCoil.ParasiticFuelCapacity;
    2221              :         }
    2222              : 
    2223       159191 :         heatingCoil.RTF = PartLoadRat;
    2224              : 
    2225              :         // If the PLF curve is defined the gas usage needs to be modified
    2226       159191 :         if (heatingCoil.PLFCurveIndex > 0) {
    2227           90 :             if (PartLoadRat == 0) {
    2228           90 :                 heatingCoil.FuelUseLoad = 0.0;
    2229              :             } else {
    2230            0 :                 PLF = Curve::CurveValue(state, heatingCoil.PLFCurveIndex, PartLoadRat);
    2231            0 :                 if (PLF < 0.7) {
    2232            0 :                     if (heatingCoil.PLFErrorCount < 1) {
    2233            0 :                         ++heatingCoil.PLFErrorCount;
    2234            0 :                         ShowWarningError(state,
    2235            0 :                                          format("CalcFuelHeatingCoil: {}=\"{}\", PLF curve values",
    2236              :                                                 HVAC::cAllCoilTypes(heatingCoil.HCoilType_Num),
    2237            0 :                                                 heatingCoil.Name));
    2238            0 :                         ShowContinueError(state, format("The PLF curve value = {:.5T} for part-load ratio = {:.5T}", PLF, PartLoadRat));
    2239            0 :                         ShowContinueError(state, "PLF curve values must be >= 0.7. PLF has been reset to 0.7 and the simulation continues...");
    2240            0 :                         ShowContinueError(state, "Check the IO reference manual for PLF curve guidance [Coil:Heating:Fuel].");
    2241              :                     } else {
    2242            0 :                         ShowRecurringWarningErrorAtEnd(
    2243            0 :                             state, heatingCoil.Name + ", Heating coil PLF curve < 0.7 warning continues... ", heatingCoil.PLFErrorIndex, PLF, PLF);
    2244              :                     }
    2245            0 :                     PLF = 0.7;
    2246              :                 }
    2247              :                 // Modify the Gas Coil Consumption and parasitic loads based on PLF curve
    2248            0 :                 heatingCoil.RTF = PartLoadRat / PLF;
    2249            0 :                 if (heatingCoil.RTF > 1.0 && std::abs(heatingCoil.RTF - 1.0) > 0.001) {
    2250            0 :                     if (heatingCoil.RTFErrorCount < 1) {
    2251            0 :                         ++heatingCoil.RTFErrorCount;
    2252            0 :                         ShowWarningError(state,
    2253            0 :                                          format("CalcFuelHeatingCoil: {}=\"{}\", runtime fraction",
    2254              :                                                 HVAC::cAllCoilTypes(heatingCoil.HCoilType_Num),
    2255            0 :                                                 heatingCoil.Name));
    2256            0 :                         ShowContinueError(state, format("The runtime fraction exceeded 1.0. [{:.4T}].", heatingCoil.RTF));
    2257            0 :                         ShowContinueError(state, "Runtime fraction is set to 1.0 and the simulation continues...");
    2258            0 :                         ShowContinueError(state, "Check the IO reference manual for PLF curve guidance [Coil:Heating:Fuel].");
    2259              :                     } else {
    2260            0 :                         ShowRecurringWarningErrorAtEnd(state,
    2261            0 :                                                        format("{}, Heating coil runtime fraction > 1.0 warning continues... ", heatingCoil.Name),
    2262            0 :                                                        heatingCoil.RTFErrorIndex,
    2263            0 :                                                        heatingCoil.RTF,
    2264            0 :                                                        heatingCoil.RTF);
    2265              :                     }
    2266            0 :                     heatingCoil.RTF = 1.0; // Reset coil runtime fraction to 1.0
    2267            0 :                 } else if (heatingCoil.RTF > 1.0) {
    2268            0 :                     heatingCoil.RTF = 1.0; // Reset coil runtime fraction to 1.0
    2269              :                 }
    2270            0 :                 heatingCoil.ElecUseLoad = heatingCoil.ParasiticElecLoad * heatingCoil.RTF;
    2271            0 :                 heatingCoil.FuelUseLoad = heatingCoil.NominalCapacity / Effic * heatingCoil.RTF;
    2272            0 :                 heatingCoil.ParasiticFuelRate = heatingCoil.ParasiticFuelCapacity * (1.0 - heatingCoil.RTF);
    2273              :                 // Fan power will also be modified by the heating coil's part load fraction
    2274              :                 // OnOffFanPartLoadFraction passed to fan via DataHVACGlobals (cycling fan only)
    2275            0 :                 if (fanOp == HVAC::FanOp::Cycling) {
    2276            0 :                     state.dataHVACGlobal->OnOffFanPartLoadFraction = PLF;
    2277              :                 }
    2278              :             }
    2279              :         }
    2280              : 
    2281              :         // Set the outlet conditions
    2282       159191 :         heatingCoil.HeatingCoilLoad = HeatingCoilLoad;
    2283       159191 :         heatingCoil.OutletAirTemp = TempAirOut;
    2284              : 
    2285              :         // This HeatingCoil does not change the moisture or Mass Flow across the component
    2286       159191 :         heatingCoil.OutletAirHumRat = heatingCoil.InletAirHumRat;
    2287       159191 :         heatingCoil.OutletAirMassFlowRate = heatingCoil.InletAirMassFlowRate;
    2288              :         // Set the outlet enthalpys for air and Heating
    2289       159191 :         heatingCoil.OutletAirEnthalpy = Psychrometrics::PsyHFnTdbW(heatingCoil.OutletAirTemp, heatingCoil.OutletAirHumRat);
    2290              : 
    2291       159191 :         QCoilActual = HeatingCoilLoad;
    2292       159191 :         if (heatingCoil.AirLoopNum > 0) {
    2293            0 :             state.dataAirLoop->AirLoopAFNInfo(heatingCoil.AirLoopNum).AFNLoopHeatingCoilMaxRTF =
    2294            0 :                 max(state.dataAirLoop->AirLoopAFNInfo(heatingCoil.AirLoopNum).AFNLoopHeatingCoilMaxRTF, heatingCoil.RTF);
    2295              :         }
    2296       159191 :         state.dataHVACGlobal->ElecHeatingCoilPower = heatingCoil.ElecUseLoad;
    2297              : 
    2298              :         // set outlet node temp so parent objects can call calc directly without have to simulate entire model
    2299       159191 :         state.dataLoopNodes->Node(heatingCoil.AirOutletNodeNum).Temp = heatingCoil.OutletAirTemp;
    2300       159191 :     }
    2301              : 
    2302           65 :     void CalcMultiStageGasHeatingCoil(EnergyPlusData &state,
    2303              :                                       int const CoilNum,       // the number of the Gas heating coil to be simulated
    2304              :                                       Real64 const SpeedRatio, // SpeedRatio varies between 1.0 (maximum speed) and 0.0 (minimum speed)
    2305              :                                       Real64 const CycRatio,   // cycling part load ratio
    2306              :                                       int const StageNum,      // Speed number
    2307              :                                       HVAC::FanOp const fanOp  // Fan operation mode
    2308              :     )
    2309              :     {
    2310              : 
    2311              :         // SUBROUTINE INFORMATION:
    2312              :         //       AUTHOR         Chandan Sharma, FSEC
    2313              :         //       DATE WRITTEN   January 2013
    2314              : 
    2315              :         // PURPOSE OF THIS SUBROUTINE:
    2316              :         // Calculates the air-side performance and energy use of a multi stage gas heating coil.
    2317              : 
    2318              :         // METHODOLOGY EMPLOYED:
    2319              :         // Uses the same methodology as the single speed Gas heating unit model (SUBROUTINE CalcFuelHeatingCoil).
    2320              :         // In addition it assumes that the unit performance is obtained by interpolating between
    2321              :         // the performance at high stage and that at low stage. If the output needed is below
    2322              :         // that produced at low stage, the coil cycles between off and low stage.
    2323              : 
    2324           65 :         Real64 const MSHPMassFlowRateHigh = state.dataHVACGlobal->MSHPMassFlowRateHigh;
    2325           65 :         Real64 const MSHPMassFlowRateLow = state.dataHVACGlobal->MSHPMassFlowRateLow;
    2326              : 
    2327              :         // SUBROUTINE PARAMETER DEFINITIONS:
    2328              :         static constexpr std::string_view RoutineName("CalcMultiStageGasHeatingCoil");
    2329              :         static constexpr std::string_view RoutineNameAverageLoad("CalcMultiStageGasHeatingCoil:Averageload");
    2330              :         static constexpr std::string_view RoutineNameFullLoad("CalcMultiStageGasHeatingCoil:fullload");
    2331              : 
    2332              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    2333              :         Real64 OutletAirEnthalpy;    // outlet air enthalpy [J/kg]
    2334              :         Real64 OutletAirHumRat;      // outlet air humidity ratio [kg/kg]
    2335              :         Real64 TotCapHS;             // total capacity at high stage [W]
    2336              :         Real64 TotCapLS;             // total capacity at low stage [W]
    2337              :         Real64 TotCap;               // total capacity at current stage [W]
    2338              :         Real64 EffHS;                // efficiency at high stage
    2339           65 :         Real64 EffLS(0.0);           // efficiency at low stage
    2340              :         Real64 EffAvg;               // average efficiency
    2341              :         int StageNumHS;              // High stage number
    2342              :         int StageNumLS;              // Low stage number
    2343              :         Real64 FullLoadOutAirEnth;   // Outlet full load enthalpy
    2344              :         Real64 FullLoadOutAirHumRat; // Outlet humidity ratio at full load
    2345              :         Real64 FullLoadOutAirTemp;   // Outlet temperature at full load
    2346              :         Real64 FullLoadOutAirRH;     // Outler relative humidity at full load
    2347              :         Real64 OutletAirTemp;        // Supply ari temperature
    2348              :         Real64 LSFullLoadOutAirEnth; // Outlet full load enthalpy at low stage
    2349              :         Real64 HSFullLoadOutAirEnth; // Outlet full load enthalpy at high stage
    2350              :         Real64 LSGasHeatingPower;    // Full load power at low stage
    2351              :         Real64 HSGasHeatingPower;    // Full load power at high stage
    2352           65 :         Real64 PartLoadRat(0.0);     // part load ratio
    2353              :         Real64 PLF;                  // part load factor used to calculate RTF
    2354              : 
    2355           65 :         auto &heatingCoil = state.dataHeatingCoils->HeatingCoil(CoilNum);
    2356              : 
    2357           65 :         if (StageNum > 1) {
    2358           14 :             StageNumLS = StageNum - 1;
    2359           14 :             StageNumHS = StageNum;
    2360           14 :             if (StageNum > heatingCoil.NumOfStages) {
    2361            0 :                 StageNumLS = heatingCoil.NumOfStages - 1;
    2362            0 :                 StageNumHS = heatingCoil.NumOfStages;
    2363              :             }
    2364              :         } else {
    2365           51 :             StageNumLS = 1;
    2366           51 :             StageNumHS = 1;
    2367              :         }
    2368              : 
    2369           65 :         Real64 AirMassFlow = heatingCoil.InletAirMassFlowRate;
    2370           65 :         Real64 InletAirEnthalpy = heatingCoil.InletAirEnthalpy;
    2371           65 :         Real64 InletAirHumRat = heatingCoil.InletAirHumRat;
    2372           65 :         Real64 OutdoorPressure = state.dataEnvrn->OutBaroPress;
    2373              : 
    2374           65 :         if ((AirMassFlow > 0.0) && (heatingCoil.availSched->getCurrentVal() > 0.0) && ((CycRatio > 0.0) || (SpeedRatio > 0.0))) {
    2375              : 
    2376           34 :             if (StageNum > 1) {
    2377              : 
    2378           14 :                 TotCapLS = heatingCoil.MSNominalCapacity(StageNumLS);
    2379           14 :                 TotCapHS = heatingCoil.MSNominalCapacity(StageNumHS);
    2380              : 
    2381           14 :                 EffLS = heatingCoil.MSEfficiency(StageNumLS);
    2382           14 :                 EffHS = heatingCoil.MSEfficiency(StageNumHS);
    2383              : 
    2384           14 :                 PartLoadRat = min(1.0, SpeedRatio);
    2385           14 :                 heatingCoil.RTF = 1.0;
    2386              : 
    2387              :                 // Get full load output and power
    2388           14 :                 LSFullLoadOutAirEnth = InletAirEnthalpy + TotCapLS / MSHPMassFlowRateLow;
    2389           14 :                 HSFullLoadOutAirEnth = InletAirEnthalpy + TotCapHS / MSHPMassFlowRateHigh;
    2390           14 :                 LSGasHeatingPower = TotCapLS / EffLS;
    2391           14 :                 HSGasHeatingPower = TotCapHS / EffHS;
    2392           14 :                 OutletAirHumRat = InletAirHumRat;
    2393              : 
    2394              :                 // if cycling fan, send coil part-load fraction to on/off fan via HVACDataGlobals
    2395              :                 // IF (FanOpMode .EQ. FanOp::Cycling) OnOffFanPartLoadFraction = 1.0d0
    2396              : 
    2397              :                 // Power calculation. If PartLoadRat (SpeedRatio) = 0, operate at LS the whole time step
    2398           14 :                 heatingCoil.ElecUseLoad =
    2399           14 :                     PartLoadRat * heatingCoil.MSParasiticElecLoad(StageNumHS) + (1.0 - PartLoadRat) * heatingCoil.MSParasiticElecLoad(StageNumLS);
    2400              : 
    2401           14 :                 state.dataHVACGlobal->ElecHeatingCoilPower = heatingCoil.ElecUseLoad;
    2402           14 :                 heatingCoil.HeatingCoilLoad = MSHPMassFlowRateHigh * (HSFullLoadOutAirEnth - InletAirEnthalpy) * PartLoadRat +
    2403           14 :                                               MSHPMassFlowRateLow * (LSFullLoadOutAirEnth - InletAirEnthalpy) * (1.0 - PartLoadRat);
    2404           14 :                 EffAvg = (EffHS * PartLoadRat) + (EffLS * (1.0 - PartLoadRat));
    2405           14 :                 heatingCoil.FuelUseLoad = heatingCoil.HeatingCoilLoad / EffAvg;
    2406           14 :                 heatingCoil.ParasiticFuelRate = 0.0;
    2407              : 
    2408           14 :                 OutletAirEnthalpy = InletAirEnthalpy + heatingCoil.HeatingCoilLoad / heatingCoil.InletAirMassFlowRate;
    2409           14 :                 OutletAirTemp = Psychrometrics::PsyTdbFnHW(OutletAirEnthalpy, OutletAirHumRat);
    2410           14 :                 FullLoadOutAirRH = Psychrometrics::PsyRhFnTdbWPb(state, OutletAirTemp, OutletAirHumRat, OutdoorPressure, RoutineNameAverageLoad);
    2411              : 
    2412           14 :                 if (FullLoadOutAirRH > 1.0) { // Limit to saturated conditions at FullLoadOutAirEnth
    2413            0 :                     OutletAirTemp = Psychrometrics::PsyTsatFnHPb(state, OutletAirEnthalpy, OutdoorPressure, RoutineName);
    2414            0 :                     OutletAirHumRat = Psychrometrics::PsyWFnTdbH(state, OutletAirTemp, OutletAirEnthalpy, RoutineName);
    2415              :                 }
    2416              : 
    2417           14 :                 heatingCoil.OutletAirTemp = OutletAirTemp;
    2418           14 :                 heatingCoil.OutletAirHumRat = OutletAirHumRat;
    2419           14 :                 heatingCoil.OutletAirEnthalpy = OutletAirEnthalpy;
    2420           14 :                 heatingCoil.OutletAirMassFlowRate = heatingCoil.InletAirMassFlowRate;
    2421              : 
    2422              :                 // Stage 1
    2423           20 :             } else if (CycRatio > 0.0) {
    2424              : 
    2425              :                 // for cycling fan, reset mass flow to full on rate
    2426           20 :                 if (fanOp == HVAC::FanOp::Cycling) {
    2427            2 :                     AirMassFlow /= CycRatio;
    2428           18 :                 } else if (fanOp == HVAC::FanOp::Continuous) {
    2429           18 :                     AirMassFlow = MSHPMassFlowRateLow;
    2430              :                 }
    2431              : 
    2432           20 :                 TotCap = heatingCoil.MSNominalCapacity(StageNumLS);
    2433              : 
    2434           20 :                 PartLoadRat = min(1.0, CycRatio);
    2435           20 :                 heatingCoil.RTF = PartLoadRat;
    2436              : 
    2437              :                 // Calculate full load outlet conditions
    2438           20 :                 FullLoadOutAirEnth = InletAirEnthalpy + TotCap / AirMassFlow;
    2439           20 :                 FullLoadOutAirHumRat = InletAirHumRat;
    2440           20 :                 FullLoadOutAirTemp = Psychrometrics::PsyTdbFnHW(FullLoadOutAirEnth, FullLoadOutAirHumRat);
    2441              :                 FullLoadOutAirRH =
    2442           20 :                     Psychrometrics::PsyRhFnTdbWPb(state, FullLoadOutAirTemp, FullLoadOutAirHumRat, OutdoorPressure, RoutineNameFullLoad);
    2443              : 
    2444           20 :                 if (FullLoadOutAirRH > 1.0) { // Limit to saturated conditions at FullLoadOutAirEnth
    2445            0 :                     FullLoadOutAirTemp = Psychrometrics::PsyTsatFnHPb(state, FullLoadOutAirEnth, OutdoorPressure, RoutineName);
    2446              :                     //  Eventually inlet air conditions will be used in Gas Coil, these lines are commented out and marked with this comment line
    2447              :                     //  FullLoadOutAirTemp = PsyTsatFnHPb(FullLoadOutAirEnth,InletAirPressure)
    2448            0 :                     FullLoadOutAirHumRat = Psychrometrics::PsyWFnTdbH(state, FullLoadOutAirTemp, FullLoadOutAirEnth, RoutineName);
    2449              :                 }
    2450              : 
    2451              :                 // Set outlet conditions from the full load calculation
    2452           20 :                 if (fanOp == HVAC::FanOp::Cycling) {
    2453            2 :                     OutletAirEnthalpy = FullLoadOutAirEnth;
    2454            2 :                     OutletAirHumRat = FullLoadOutAirHumRat;
    2455            2 :                     OutletAirTemp = FullLoadOutAirTemp;
    2456              :                 } else {
    2457           18 :                     OutletAirEnthalpy =
    2458           18 :                         PartLoadRat * AirMassFlow / heatingCoil.InletAirMassFlowRate * (FullLoadOutAirEnth - InletAirEnthalpy) + InletAirEnthalpy;
    2459           18 :                     OutletAirHumRat =
    2460           18 :                         PartLoadRat * AirMassFlow / heatingCoil.InletAirMassFlowRate * (FullLoadOutAirHumRat - InletAirHumRat) + InletAirHumRat;
    2461           18 :                     OutletAirTemp = Psychrometrics::PsyTdbFnHW(OutletAirEnthalpy, OutletAirHumRat);
    2462              :                 }
    2463              : 
    2464           20 :                 EffLS = heatingCoil.MSEfficiency(StageNumLS);
    2465              : 
    2466           20 :                 heatingCoil.HeatingCoilLoad = TotCap * PartLoadRat;
    2467              : 
    2468           20 :                 heatingCoil.FuelUseLoad = heatingCoil.HeatingCoilLoad / EffLS;
    2469              :                 //   parasitics are calculated when the coil is off (1-PLR)
    2470           20 :                 heatingCoil.ElecUseLoad = heatingCoil.MSParasiticElecLoad(StageNumLS) * (1.0 - PartLoadRat);
    2471           20 :                 heatingCoil.ParasiticFuelRate = heatingCoil.ParasiticFuelCapacity * (1.0 - PartLoadRat);
    2472           20 :                 state.dataHVACGlobal->ElecHeatingCoilPower = heatingCoil.ElecUseLoad;
    2473              : 
    2474           20 :                 heatingCoil.OutletAirTemp = OutletAirTemp;
    2475           20 :                 heatingCoil.OutletAirHumRat = OutletAirHumRat;
    2476           20 :                 heatingCoil.OutletAirEnthalpy = OutletAirEnthalpy;
    2477           20 :                 heatingCoil.OutletAirMassFlowRate = heatingCoil.InletAirMassFlowRate;
    2478              :             }
    2479              : 
    2480              :             // This requires a CR to correct (i.e., calculate outputs when coil is off)
    2481              :         } else {
    2482              : 
    2483              :             // Gas coil is off; just pass through conditions
    2484           31 :             heatingCoil.OutletAirEnthalpy = heatingCoil.InletAirEnthalpy;
    2485           31 :             heatingCoil.OutletAirHumRat = heatingCoil.InletAirHumRat;
    2486           31 :             heatingCoil.OutletAirTemp = heatingCoil.InletAirTemp;
    2487           31 :             heatingCoil.OutletAirMassFlowRate = heatingCoil.InletAirMassFlowRate;
    2488              : 
    2489              :             // some of these are reset in Init, can be removed to speed up code
    2490           31 :             heatingCoil.ElecUseLoad = 0.0;
    2491           31 :             heatingCoil.HeatingCoilLoad = 0.0;
    2492           31 :             heatingCoil.FuelUseLoad = 0.0;
    2493           31 :             heatingCoil.ParasiticFuelRate = heatingCoil.ParasiticFuelCapacity;
    2494           31 :             state.dataHVACGlobal->ElecHeatingCoilPower = 0.0;
    2495           31 :             PartLoadRat = 0.0;
    2496              : 
    2497              :         } // end of on/off if - else
    2498              : 
    2499              :         // If the PLF curve is defined the gas usage needs to be modified.
    2500              :         // The PLF curve is only used when the coil cycles.
    2501           65 :         if (heatingCoil.PLFCurveIndex > 0) {
    2502           62 :             if (PartLoadRat > 0.0 && StageNum < 2) {
    2503           18 :                 PLF = Curve::CurveValue(state, heatingCoil.PLFCurveIndex, PartLoadRat);
    2504           18 :                 if (PLF < 0.7) {
    2505            0 :                     if (heatingCoil.PLFErrorCount < 1) {
    2506            0 :                         ++heatingCoil.PLFErrorCount;
    2507            0 :                         ShowWarningError(state,
    2508            0 :                                          format("CalcFuelHeatingCoil: {}=\"{}\", PLF curve values",
    2509              :                                                 HVAC::cAllCoilTypes(heatingCoil.HCoilType_Num),
    2510            0 :                                                 heatingCoil.Name));
    2511            0 :                         ShowContinueError(state, format("The PLF curve value = {:.5T} for part-load ratio = {:.5T}", PLF, PartLoadRat));
    2512            0 :                         ShowContinueError(state, "PLF curve values must be >= 0.7. PLF has been reset to 0.7 and the simulation continues...");
    2513            0 :                         ShowContinueError(state, "Check the IO reference manual for PLF curve guidance [Coil:Heating:Fuel].");
    2514              :                     } else {
    2515            0 :                         ShowRecurringWarningErrorAtEnd(state,
    2516            0 :                                                        format("{}, Heating coil PLF curve < 0.7 warning continues... ", heatingCoil.Name),
    2517            0 :                                                        heatingCoil.PLFErrorIndex,
    2518              :                                                        PLF,
    2519              :                                                        PLF);
    2520              :                     }
    2521            0 :                     PLF = 0.7;
    2522              :                 }
    2523              :                 // Modify the Gas Coil Consumption and parasitic loads based on PLF curve
    2524           18 :                 heatingCoil.RTF = PartLoadRat / PLF;
    2525           18 :                 if (heatingCoil.RTF > 1.0 && std::abs(heatingCoil.RTF - 1.0) > 0.001) {
    2526            0 :                     if (heatingCoil.RTFErrorCount < 1) {
    2527            0 :                         ++heatingCoil.RTFErrorCount;
    2528            0 :                         ShowWarningError(state,
    2529            0 :                                          format("CalcFuelHeatingCoil: {}=\"{}\", runtime fraction",
    2530              :                                                 HVAC::cAllCoilTypes(heatingCoil.HCoilType_Num),
    2531            0 :                                                 heatingCoil.Name));
    2532            0 :                         ShowContinueError(state, format("The runtime fraction exceeded 1.0. [{:.4T}].", heatingCoil.RTF));
    2533            0 :                         ShowContinueError(state, "Runtime fraction is set to 1.0 and the simulation continues...");
    2534            0 :                         ShowContinueError(state, "Check the IO reference manual for PLF curve guidance [Coil:Heating:Fuel].");
    2535              :                     } else {
    2536            0 :                         ShowRecurringWarningErrorAtEnd(state,
    2537            0 :                                                        format("{}, Heating coil runtime fraction > 1.0 warning continues... ", heatingCoil.Name),
    2538            0 :                                                        heatingCoil.RTFErrorIndex,
    2539            0 :                                                        heatingCoil.RTF,
    2540            0 :                                                        heatingCoil.RTF);
    2541              :                     }
    2542            0 :                     heatingCoil.RTF = 1.0; // Reset coil runtime fraction to 1.0
    2543           18 :                 } else if (heatingCoil.RTF > 1.0) {
    2544            0 :                     heatingCoil.RTF = 1.0; // Reset coil runtime fraction to 1.0
    2545              :                 }
    2546           18 :                 heatingCoil.ElecUseLoad = heatingCoil.MSParasiticElecLoad(StageNum) * heatingCoil.RTF;
    2547           18 :                 heatingCoil.FuelUseLoad = (heatingCoil.MSNominalCapacity(StageNum) / EffLS) * heatingCoil.RTF;
    2548           18 :                 heatingCoil.ParasiticFuelRate = heatingCoil.ParasiticFuelCapacity * (1.0 - heatingCoil.RTF);
    2549              :                 // Fan power will also be modified by the heating coil's part load fraction
    2550              :                 // OnOffFanPartLoadFraction passed to fan via DataHVACGlobals (cycling fan only)
    2551           18 :                 if (fanOp == HVAC::FanOp::Cycling) {
    2552            2 :                     state.dataHVACGlobal->OnOffFanPartLoadFraction = PLF;
    2553              :                 }
    2554              :             }
    2555              :         }
    2556              : 
    2557              :         // set outlet node temp so parent objects can call calc directly without have to simulate entire model
    2558           65 :         state.dataLoopNodes->Node(heatingCoil.AirOutletNodeNum).Temp = heatingCoil.OutletAirTemp;
    2559           65 :     }
    2560              : 
    2561            4 :     void CalcDesuperheaterHeatingCoil(EnergyPlusData &state,
    2562              :                                       int const CoilNum,     // index to desuperheater heating coil
    2563              :                                       Real64 const QCoilReq, // load requested by the simulation for load based control [W]
    2564              :                                       Real64 &QCoilActual    // coil load actually delivered
    2565              :     )
    2566              :     {
    2567              :         // SUBROUTINE INFORMATION:
    2568              :         //       AUTHOR         Richard Raustad
    2569              :         //       DATE WRITTEN   January 2005
    2570              :         //       MODIFIED       Jul. 2016, R. Zhang, Applied the coil supply air temperature sensor offset
    2571              : 
    2572              :         // PURPOSE OF THIS SUBROUTINE:
    2573              :         // Simulates a simple desuperheater heating coil with a heat reclaim efficiency
    2574              :         // (eff = ratio of condenser waste heat reclaimed to total condenser waste heat rejected)
    2575              : 
    2576              :         // METHODOLOGY EMPLOYED:
    2577              :         // The available capacity of the desuperheater heating coil is determined by the
    2578              :         // amount of heat rejected at the heating source condenser multiplied by the
    2579              :         // desuperheater heat reclaim efficiency. This capacity is either applied towards
    2580              :         // a requested load (load based control) or applied to the air stream to meet a
    2581              :         // heating setpoint (temperature based control). This subroutine is similar to
    2582              :         // the electric or gas heating coil except that the NominalCapacity is variable
    2583              :         // and based on the runtime fraction and heat rejection of the heat source object.
    2584              : 
    2585              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    2586              :         Real64 AvailTemp;       // Lowest temperature available from desuperheater (~T condensing)[C]
    2587              :         Real64 TempAirOut;      // temperature of the air leaving the desuperheater heating coil [C]
    2588              :         Real64 HeatingCoilLoad; // actual load delivered by the desuperheater heating coil [W]
    2589              :         Real64 QCoilCap;        // available capacity of the desuperheater heating coil [W]
    2590              :         int SourceID;           // waste heat source id number
    2591              : 
    2592            4 :         auto &heatingCoil = state.dataHeatingCoils->HeatingCoil(CoilNum);
    2593              : 
    2594            4 :         Real64 Effic = heatingCoil.Efficiency;
    2595            4 :         Real64 AirMassFlow = heatingCoil.InletAirMassFlowRate;
    2596            4 :         Real64 TempAirIn = heatingCoil.InletAirTemp;
    2597            4 :         Real64 Win = heatingCoil.InletAirHumRat;
    2598            4 :         Real64 CapacitanceAir = Psychrometrics::PsyCpAirFnW(Win) * AirMassFlow;
    2599            4 :         Real64 TempSetPoint = heatingCoil.DesiredOutletTemp;
    2600              : 
    2601              :         // If there is a fault of coil SAT Sensor
    2602            4 :         if (heatingCoil.FaultyCoilSATFlag && (!state.dataGlobal->WarmupFlag) && (!state.dataGlobal->DoingSizing) &&
    2603            0 :             (!state.dataGlobal->KickOffSimulation)) {
    2604              :             // calculate the sensor offset using fault information
    2605            0 :             int FaultIndex = heatingCoil.FaultyCoilSATIndex;
    2606            0 :             heatingCoil.FaultyCoilSATOffset = state.dataFaultsMgr->FaultsCoilSATSensor(FaultIndex).CalFaultOffsetAct(state);
    2607              :             // update the TempSetPoint
    2608            0 :             TempSetPoint -= heatingCoil.FaultyCoilSATOffset;
    2609              :         }
    2610              : 
    2611              :         // Access the appropriate structure to find the available heating capacity of the desuperheater heating coil
    2612              :         // The nominal capacity of the desuperheater heating coil varies based on the amount of heat rejected by the source
    2613              :         // Stovall 2011, add comparison to available temperature of heat reclaim source
    2614            4 :         if (state.dataHeatingCoils->ValidSourceType(CoilNum)) {
    2615            4 :             SourceID = heatingCoil.ReclaimHeatingSourceIndexNum;
    2616            4 :             switch (heatingCoil.ReclaimHeatingSource) {
    2617            4 :             case HeatObjTypes::COMPRESSORRACK_REFRIGERATEDCASE:
    2618              :                 // Added last term to available energy equations to avoid double counting reclaimed energy
    2619              :                 // because refrigeration systems are solved outside the hvac time step iterations
    2620            4 :                 heatingCoil.RTF = 1.0;
    2621            4 :                 heatingCoil.NominalCapacity = state.dataHeatBal->HeatReclaimRefrigeratedRack(SourceID).AvailCapacity * Effic -
    2622            4 :                                               state.dataHeatBal->HeatReclaimRefrigeratedRack(SourceID).WaterHeatingDesuperheaterReclaimedHeatTotal;
    2623            4 :                 break;
    2624            0 :             case HeatObjTypes::CONDENSER_REFRIGERATION:
    2625            0 :                 AvailTemp = state.dataHeatBal->HeatReclaimRefrigCondenser(SourceID).AvailTemperature;
    2626            0 :                 heatingCoil.RTF = 1.0;
    2627            0 :                 if (AvailTemp <= TempAirIn) {
    2628            0 :                     heatingCoil.NominalCapacity = 0.0;
    2629            0 :                     ShowRecurringWarningErrorAtEnd(
    2630              :                         state,
    2631            0 :                         format("Coil:Heating:Desuperheater {} - Waste heat source temperature was too low to be useful.", heatingCoil.Name),
    2632            0 :                         heatingCoil.InsuffTemperatureWarn);
    2633              :                 } else {
    2634            0 :                     heatingCoil.NominalCapacity = state.dataHeatBal->HeatReclaimRefrigCondenser(SourceID).AvailCapacity * Effic -
    2635            0 :                                                   state.dataHeatBal->HeatReclaimRefrigCondenser(SourceID).WaterHeatingDesuperheaterReclaimedHeatTotal;
    2636              :                 }
    2637            0 :                 break;
    2638            0 :             case HeatObjTypes::COIL_DX_COOLING:
    2639              :             case HeatObjTypes::COIL_DX_MULTISPEED:
    2640              :             case HeatObjTypes::COIL_DX_MULTIMODE:
    2641            0 :                 heatingCoil.RTF = state.dataDXCoils->DXCoil(SourceID).CoolingCoilRuntimeFraction;
    2642            0 :                 heatingCoil.NominalCapacity = state.dataHeatBal->HeatReclaimDXCoil(SourceID).AvailCapacity * Effic -
    2643            0 :                                               state.dataHeatBal->HeatReclaimDXCoil(SourceID).WaterHeatingDesuperheaterReclaimedHeatTotal;
    2644            0 :                 break;
    2645            0 :             case HeatObjTypes::COIL_DX_VARIABLE_COOLING:
    2646              :                 // condenser heat rejection
    2647            0 :                 heatingCoil.RTF = state.dataVariableSpeedCoils->VarSpeedCoil(SourceID).RunFrac;
    2648            0 :                 heatingCoil.NominalCapacity = state.dataHeatBal->HeatReclaimVS_Coil(SourceID).AvailCapacity * Effic -
    2649            0 :                                               state.dataHeatBal->HeatReclaimVS_Coil(SourceID).WaterHeatingDesuperheaterReclaimedHeatTotal;
    2650            0 :                 break;
    2651            0 :             case HeatObjTypes::COIL_COOLING_DX_NEW:
    2652              :                 // get RTF and NominalCapacity from Coil:CoolingDX
    2653              :                 {
    2654            0 :                     auto const &thisCoolingCoil = state.dataCoilCoolingDX->coilCoolingDXs[SourceID];
    2655            0 :                     heatingCoil.RTF = thisCoolingCoil.runTimeFraction;
    2656            0 :                     heatingCoil.NominalCapacity =
    2657            0 :                         thisCoolingCoil.reclaimHeat.AvailCapacity * Effic - thisCoolingCoil.reclaimHeat.WaterHeatingDesuperheaterReclaimedHeatTotal;
    2658              :                 }
    2659            0 :                 break;
    2660            0 :             default:
    2661            0 :                 assert(false);
    2662              :             }
    2663              : 
    2664              :         } else {
    2665            0 :             heatingCoil.NominalCapacity = 0.0;
    2666              :         }
    2667              : 
    2668              :         // Control output to meet load (QCoilReq)
    2669            4 :         if ((AirMassFlow > 0.0) && (heatingCoil.availSched->getCurrentVal() > 0.0) && (QCoilReq > 0.0)) {
    2670              : 
    2671              :             // check to see if the Required heating capacity is greater than the available heating capacity.
    2672            2 :             if (QCoilReq > heatingCoil.NominalCapacity) {
    2673            0 :                 QCoilCap = heatingCoil.NominalCapacity;
    2674              :             } else {
    2675            2 :                 QCoilCap = QCoilReq;
    2676              :             }
    2677              : 
    2678              :             // report the runtime fraction of the desuperheater heating coil
    2679            2 :             if (heatingCoil.NominalCapacity > 0.0) {
    2680            2 :                 heatingCoil.RTF *= (QCoilCap / heatingCoil.NominalCapacity);
    2681            2 :                 TempAirOut = TempAirIn + QCoilCap / CapacitanceAir;
    2682            2 :                 HeatingCoilLoad = QCoilCap;
    2683              :             } else {
    2684            0 :                 heatingCoil.RTF = 0.0;
    2685            0 :                 TempAirOut = TempAirIn;
    2686            0 :                 HeatingCoilLoad = 0.0;
    2687              :             }
    2688              : 
    2689              :             // Control coil output to meet a setpoint temperature.
    2690            1 :         } else if ((AirMassFlow > 0.0 && heatingCoil.NominalCapacity > 0.0) && (heatingCoil.availSched->getCurrentVal() > 0.0) &&
    2691            3 :                    (QCoilReq == DataLoopNode::SensedLoadFlagValue) && (std::abs(TempSetPoint - TempAirIn) > HVAC::TempControlTol)) {
    2692              : 
    2693            0 :             QCoilCap = CapacitanceAir * (TempSetPoint - TempAirIn);
    2694              :             // check to see if setpoint is above entering air temperature. If not, set output to zero.
    2695            0 :             if (QCoilCap <= 0.0) {
    2696            0 :                 QCoilCap = 0.0;
    2697            0 :                 TempAirOut = TempAirIn;
    2698              :                 // check to see if the required heating capacity is greater than the available capacity.
    2699            0 :             } else if (QCoilCap > heatingCoil.NominalCapacity) {
    2700            0 :                 QCoilCap = heatingCoil.NominalCapacity;
    2701            0 :                 TempAirOut = TempAirIn + QCoilCap / CapacitanceAir;
    2702              :             } else {
    2703            0 :                 TempAirOut = TempSetPoint;
    2704              :             }
    2705              : 
    2706            0 :             HeatingCoilLoad = QCoilCap;
    2707              :             //     report the runtime fraction of the desuperheater heating coil
    2708            0 :             heatingCoil.RTF *= (QCoilCap / heatingCoil.NominalCapacity);
    2709              : 
    2710              :         } else { // If not running, conditions do not change across heating coil from inlet to outlet
    2711              : 
    2712            2 :             TempAirOut = TempAirIn;
    2713            2 :             HeatingCoilLoad = 0.0;
    2714            2 :             heatingCoil.ElecUseLoad = 0.0;
    2715            2 :             heatingCoil.RTF = 0.0;
    2716              :         }
    2717              : 
    2718              :         // Set the outlet conditions
    2719            4 :         heatingCoil.HeatingCoilLoad = HeatingCoilLoad;
    2720            4 :         heatingCoil.OutletAirTemp = TempAirOut;
    2721              : 
    2722              :         // This HeatingCoil does not change the moisture or Mass Flow across the component
    2723            4 :         heatingCoil.OutletAirHumRat = heatingCoil.InletAirHumRat;
    2724            4 :         heatingCoil.OutletAirMassFlowRate = heatingCoil.InletAirMassFlowRate;
    2725              :         // Set the outlet enthalpy
    2726            4 :         heatingCoil.OutletAirEnthalpy = Psychrometrics::PsyHFnTdbW(heatingCoil.OutletAirTemp, heatingCoil.OutletAirHumRat);
    2727              : 
    2728            4 :         heatingCoil.ElecUseLoad = heatingCoil.ParasiticElecLoad * heatingCoil.RTF;
    2729            4 :         QCoilActual = HeatingCoilLoad;
    2730              : 
    2731              :         // Update remaining waste heat (just in case multiple users of waste heat use same source)
    2732            4 :         if (state.dataHeatingCoils->ValidSourceType(CoilNum)) {
    2733            4 :             SourceID = heatingCoil.ReclaimHeatingSourceIndexNum;
    2734              :             //   Refrigerated cases are simulated at the zone time step, do not decrement available capacity
    2735              :             //   (the heat reclaim available capacity will not get reinitialized as the air loop iterates)
    2736            4 :             int DesuperheaterNum = CoilNum - state.dataHeatingCoils->NumElecCoil - state.dataHeatingCoils->NumElecCoilMultiStage -
    2737            4 :                                    state.dataHeatingCoils->NumFuelCoil - state.dataHeatingCoils->NumGasCoilMultiStage;
    2738            4 :             switch (heatingCoil.ReclaimHeatingSource) {
    2739            4 :             case HeatObjTypes::COMPRESSORRACK_REFRIGERATEDCASE: {
    2740            4 :                 state.dataHeatBal->HeatReclaimRefrigeratedRack(SourceID).HVACDesuperheaterReclaimedHeat(DesuperheaterNum) = HeatingCoilLoad;
    2741            4 :                 state.dataHeatBal->HeatReclaimRefrigeratedRack(SourceID).HVACDesuperheaterReclaimedHeatTotal = 0.0;
    2742            8 :                 for (auto const &num : state.dataHeatBal->HeatReclaimRefrigeratedRack(SourceID).HVACDesuperheaterReclaimedHeat) {
    2743            4 :                     state.dataHeatBal->HeatReclaimRefrigeratedRack(SourceID).HVACDesuperheaterReclaimedHeatTotal += num;
    2744              :                 }
    2745            4 :             } break;
    2746            0 :             case HeatObjTypes::CONDENSER_REFRIGERATION: {
    2747            0 :                 state.dataHeatBal->HeatReclaimRefrigCondenser(SourceID).HVACDesuperheaterReclaimedHeat(DesuperheaterNum) = HeatingCoilLoad;
    2748            0 :                 state.dataHeatBal->HeatReclaimRefrigCondenser(SourceID).HVACDesuperheaterReclaimedHeatTotal = 0.0;
    2749            0 :                 for (auto const &num : state.dataHeatBal->HeatReclaimRefrigCondenser(SourceID).HVACDesuperheaterReclaimedHeat) {
    2750            0 :                     state.dataHeatBal->HeatReclaimRefrigCondenser(SourceID).HVACDesuperheaterReclaimedHeatTotal += num;
    2751              :                 }
    2752            0 :             } break;
    2753            0 :             case HeatObjTypes::COIL_DX_COOLING:
    2754              :             case HeatObjTypes::COIL_DX_MULTISPEED:
    2755              :             case HeatObjTypes::COIL_DX_MULTIMODE: {
    2756            0 :                 state.dataHeatBal->HeatReclaimDXCoil(SourceID).HVACDesuperheaterReclaimedHeat(DesuperheaterNum) = HeatingCoilLoad;
    2757            0 :                 state.dataHeatBal->HeatReclaimDXCoil(SourceID).HVACDesuperheaterReclaimedHeatTotal = 0.0;
    2758            0 :                 for (auto const &num : state.dataHeatBal->HeatReclaimDXCoil(SourceID).HVACDesuperheaterReclaimedHeat) {
    2759            0 :                     state.dataHeatBal->HeatReclaimDXCoil(SourceID).HVACDesuperheaterReclaimedHeatTotal += num;
    2760              :                 }
    2761            0 :             } break;
    2762            0 :             case HeatObjTypes::COIL_DX_VARIABLE_COOLING: {
    2763            0 :                 state.dataHeatBal->HeatReclaimVS_Coil(SourceID).HVACDesuperheaterReclaimedHeat(DesuperheaterNum) = HeatingCoilLoad;
    2764            0 :                 state.dataHeatBal->HeatReclaimVS_Coil(SourceID).HVACDesuperheaterReclaimedHeatTotal = 0.0;
    2765            0 :                 for (auto const &num : state.dataHeatBal->HeatReclaimVS_Coil(SourceID).HVACDesuperheaterReclaimedHeat) {
    2766            0 :                     state.dataHeatBal->HeatReclaimVS_Coil(SourceID).HVACDesuperheaterReclaimedHeatTotal += num;
    2767              :                 }
    2768            0 :             } break;
    2769            0 :             default:
    2770            0 :                 break;
    2771              :             }
    2772              :         }
    2773            4 :     }
    2774              : 
    2775       233160 :     void UpdateHeatingCoil(EnergyPlusData &state, int const CoilNum)
    2776              :     {
    2777              :         // SUBROUTINE INFORMATION:
    2778              :         //       AUTHOR         Richard Liesen
    2779              :         //       DATE WRITTEN   May 2000
    2780              : 
    2781              :         // PURPOSE OF THIS SUBROUTINE:
    2782              :         // This subroutine updates the coil outlet nodes.
    2783              : 
    2784              :         // METHODOLOGY EMPLOYED:
    2785              :         // Data is moved from the coil data structure to the coil outlet nodes.
    2786              : 
    2787              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    2788       233160 :         auto const &heatingCoil = state.dataHeatingCoils->HeatingCoil(CoilNum);
    2789       233160 :         auto const &airInletNode = state.dataLoopNodes->Node(heatingCoil.AirInletNodeNum);
    2790       233160 :         auto &airOuletNode = state.dataLoopNodes->Node(heatingCoil.AirOutletNodeNum);
    2791              : 
    2792              :         // Set the outlet air nodes of the HeatingCoil
    2793       233160 :         airOuletNode.MassFlowRate = heatingCoil.OutletAirMassFlowRate;
    2794       233160 :         airOuletNode.Temp = heatingCoil.OutletAirTemp;
    2795       233160 :         airOuletNode.HumRat = heatingCoil.OutletAirHumRat;
    2796       233160 :         airOuletNode.Enthalpy = heatingCoil.OutletAirEnthalpy;
    2797              : 
    2798              :         // Set the outlet nodes for properties that just pass through & not used
    2799       233160 :         airOuletNode.Quality = airInletNode.Quality;
    2800       233160 :         airOuletNode.Press = airInletNode.Press;
    2801       233160 :         airOuletNode.MassFlowRateMin = airInletNode.MassFlowRateMin;
    2802       233160 :         airOuletNode.MassFlowRateMax = airInletNode.MassFlowRateMax;
    2803       233160 :         airOuletNode.MassFlowRateMinAvail = airInletNode.MassFlowRateMinAvail;
    2804       233160 :         airOuletNode.MassFlowRateMaxAvail = airInletNode.MassFlowRateMaxAvail;
    2805              : 
    2806       233160 :         if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
    2807            0 :             airOuletNode.CO2 = airInletNode.CO2;
    2808              :         }
    2809              : 
    2810       233160 :         if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
    2811            0 :             airOuletNode.GenContam = airInletNode.GenContam;
    2812              :         }
    2813       233160 :     }
    2814              : 
    2815       233160 :     void ReportHeatingCoil(EnergyPlusData &state, int const CoilNum, bool const coilIsSuppHeater)
    2816              :     {
    2817              : 
    2818              :         // SUBROUTINE INFORMATION:
    2819              :         //       AUTHOR         Richard Liesen
    2820              :         //       DATE WRITTEN   May 2000
    2821              : 
    2822              :         // PURPOSE OF THIS SUBROUTINE:
    2823              :         // This subroutine updates the report variable for the coils.
    2824              : 
    2825              :         // Using/Aliasing
    2826       233160 :         Real64 TimeStepSysSec = state.dataHVACGlobal->TimeStepSysSec;
    2827       233160 :         auto &heatingCoil = state.dataHeatingCoils->HeatingCoil(CoilNum);
    2828              : 
    2829              :         // report the HeatingCoil energy from this component
    2830       233160 :         heatingCoil.HeatingCoilRate = heatingCoil.HeatingCoilLoad;
    2831       233160 :         heatingCoil.HeatingCoilLoad *= TimeStepSysSec;
    2832              : 
    2833       233160 :         heatingCoil.FuelUseRate = heatingCoil.FuelUseLoad;
    2834       233160 :         heatingCoil.ElecUseRate = heatingCoil.ElecUseLoad;
    2835       233160 :         if (coilIsSuppHeater) {
    2836       137752 :             state.dataHVACGlobal->SuppHeatingCoilPower = heatingCoil.ElecUseLoad;
    2837              :         } else {
    2838        95408 :             state.dataHVACGlobal->ElecHeatingCoilPower = heatingCoil.ElecUseLoad;
    2839              :         }
    2840       233160 :         heatingCoil.FuelUseLoad *= TimeStepSysSec;
    2841       233160 :         heatingCoil.ElecUseLoad *= TimeStepSysSec;
    2842              : 
    2843       233160 :         heatingCoil.ParasiticFuelConsumption = heatingCoil.ParasiticFuelRate * TimeStepSysSec;
    2844              : 
    2845       233160 :         std::string coilObjClassName;
    2846       233160 :         switch (heatingCoil.HCoilType_Num) {
    2847        73698 :         case HVAC::Coil_HeatingElectric: {
    2848        73698 :             coilObjClassName = "Coil:Heating:Electric";
    2849        73698 :         } break;
    2850          217 :         case HVAC::Coil_HeatingElectric_MultiStage: {
    2851          217 :             coilObjClassName = "Coil:Heating:Electric:MultiStage";
    2852          217 :         } break;
    2853       159191 :         case HVAC::Coil_HeatingGasOrOtherFuel: {
    2854       159191 :             coilObjClassName = "Coil:Heating:Fuel";
    2855       159191 :         } break;
    2856           50 :         case HVAC::Coil_HeatingGas_MultiStage: {
    2857           50 :             coilObjClassName = "Coil:Heating:Gas:MultiStage";
    2858           50 :         } break;
    2859            4 :         case HVAC::Coil_HeatingDesuperheater: {
    2860            4 :             coilObjClassName = "Coil:Heating:Desuperheater";
    2861            4 :         } break;
    2862            0 :         default:
    2863            0 :             break;
    2864              :         }
    2865       233160 :         if (heatingCoil.reportCoilFinalSizes) {
    2866        56127 :             if (!state.dataGlobal->WarmupFlag && !state.dataGlobal->DoingHVACSizingSimulations && !state.dataGlobal->DoingSizing) {
    2867          117 :                 state.dataRptCoilSelection->coilSelectionReportObj->setCoilFinalSizes(
    2868          117 :                     state, heatingCoil.Name, coilObjClassName, heatingCoil.NominalCapacity, heatingCoil.NominalCapacity, -999.0, -999.0);
    2869          117 :                 heatingCoil.reportCoilFinalSizes = false;
    2870              :             }
    2871              :         }
    2872       233160 :     }
    2873              : 
    2874              :     //        End of Reporting subroutines for the HeatingCoil Module
    2875              : 
    2876           84 :     void GetCoilIndex(EnergyPlusData &state, std::string const &HeatingCoilName, int &HeatingCoilIndex, bool &ErrorsFound)
    2877              :     {
    2878              : 
    2879              :         // SUBROUTINE INFORMATION:
    2880              :         //       AUTHOR         Richard Raustad
    2881              :         //       DATE WRITTEN   March 2005
    2882              : 
    2883              :         // PURPOSE OF THIS SUBROUTINE:
    2884              :         // This subroutine sets an index for a given DX Coil -- issues error message if that
    2885              :         // DX Coil is not a legal DX Coil.
    2886              : 
    2887              :         // Obtains and Allocates HeatingCoil related parameters from input file
    2888           84 :         if (state.dataHeatingCoils->GetCoilsInputFlag) { // First time subroutine has been entered
    2889           36 :             GetHeatingCoilInput(state);
    2890           36 :             state.dataHeatingCoils->GetCoilsInputFlag = false;
    2891              :         }
    2892              : 
    2893           84 :         HeatingCoilIndex = Util::FindItem(HeatingCoilName, state.dataHeatingCoils->HeatingCoil);
    2894           84 :         if (HeatingCoilIndex == 0) {
    2895            0 :             ShowSevereError(state, format("GetCoilIndex: Heating coil not found={}", HeatingCoilName));
    2896            0 :             ErrorsFound = true;
    2897              :         }
    2898           84 :     }
    2899              : 
    2900            2 :     void CheckHeatingCoilSchedule(EnergyPlusData &state,
    2901              :                                   std::string const &CompType, // unused1208
    2902              :                                   std::string_view CompName,
    2903              :                                   Real64 &Value,
    2904              :                                   int &CompIndex)
    2905              :     {
    2906              : 
    2907              :         // SUBROUTINE INFORMATION:
    2908              :         //       AUTHOR         Linda Lawrie
    2909              :         //       DATE WRITTEN   October 2005
    2910              : 
    2911              :         // PURPOSE OF THIS SUBROUTINE:
    2912              :         // This routine provides a method for outside routines to check if
    2913              :         // the heating coil is scheduled to be on.
    2914              : 
    2915              :         // Obtains and Allocates HeatingCoil related parameters from input file
    2916            2 :         if (state.dataHeatingCoils->GetCoilsInputFlag) { // First time subroutine has been entered
    2917            2 :             GetHeatingCoilInput(state);
    2918            2 :             state.dataHeatingCoils->GetCoilsInputFlag = false;
    2919              :         }
    2920              : 
    2921              :         // Find the correct Coil number
    2922            2 :         if (CompIndex == 0) {
    2923            2 :             int CoilNum = Util::FindItem(CompName, state.dataHeatingCoils->HeatingCoil);
    2924            2 :             if (CoilNum == 0) {
    2925            0 :                 ShowFatalError(state, format("CheckHeatingCoilSchedule: Coil not found=\"{}\".", CompName));
    2926              :             }
    2927            2 :             if (!Util::SameString(CompType, HVAC::cAllCoilTypes(state.dataHeatingCoils->HeatingCoil(CoilNum).HCoilType_Num))) {
    2928            0 :                 ShowSevereError(state, format("CheckHeatingCoilSchedule: Coil=\"{}\"", CompName));
    2929            0 :                 ShowContinueError(state,
    2930            0 :                                   format("...expected type=\"{}\", actual type=\"{}\".",
    2931              :                                          CompType,
    2932            0 :                                          HVAC::cAllCoilTypes(state.dataHeatingCoils->HeatingCoil(CoilNum).HCoilType_Num)));
    2933            0 :                 ShowFatalError(state, "Program terminates due to preceding conditions.");
    2934              :             }
    2935            2 :             CompIndex = CoilNum;
    2936            2 :             Value = state.dataHeatingCoils->HeatingCoil(CoilNum).availSched->getCurrentVal(); // not scheduled?
    2937              :         } else {
    2938            0 :             int CoilNum = CompIndex;
    2939            0 :             if (CoilNum > state.dataHeatingCoils->NumHeatingCoils || CoilNum < 1) {
    2940            0 :                 ShowFatalError(state,
    2941            0 :                                format("CheckHeatingCoilSchedule: Invalid CompIndex passed={}, Number of Heating Coils={}, Coil name={}",
    2942              :                                       CoilNum,
    2943            0 :                                       state.dataHeatingCoils->NumHeatingCoils,
    2944              :                                       CompName));
    2945              :             }
    2946            0 :             if (CompName != state.dataHeatingCoils->HeatingCoil(CoilNum).Name) {
    2947            0 :                 ShowSevereError(state,
    2948            0 :                                 format("CheckHeatingCoilSchedule: Invalid CompIndex passed={}, Coil name={}, stored Coil Name for that index={}",
    2949              :                                        CoilNum,
    2950              :                                        CompName,
    2951            0 :                                        state.dataHeatingCoils->HeatingCoil(CoilNum).Name));
    2952            0 :                 ShowContinueError(state,
    2953            0 :                                   format("...expected type=\"{}\", actual type=\"{}\".",
    2954              :                                          CompType,
    2955            0 :                                          HVAC::cAllCoilTypes(state.dataHeatingCoils->HeatingCoil(CoilNum).HCoilType_Num)));
    2956            0 :                 ShowFatalError(state, "Program terminates due to preceding conditions.");
    2957              :             }
    2958            0 :             Value = state.dataHeatingCoils->HeatingCoil(CoilNum).availSched->getCurrentVal(); // not scheduled?
    2959              :         }
    2960            2 :     }
    2961              : 
    2962           22 :     Real64 GetCoilCapacity(EnergyPlusData &state,
    2963              :                            std::string const &CoilType, // must match coil types in this module
    2964              :                            std::string const &CoilName, // must match coil names for the coil type
    2965              :                            bool &ErrorsFound            // set to true if problem
    2966              :     )
    2967              :     {
    2968              : 
    2969              :         // FUNCTION INFORMATION:
    2970              :         //       AUTHOR         Linda Lawrie
    2971              :         //       DATE WRITTEN   February 2006
    2972              : 
    2973              :         // PURPOSE OF THIS FUNCTION:
    2974              :         // This function looks up the coil capacity for the given coil and returns it.  If
    2975              :         // incorrect coil type or name is given, ErrorsFound is returned as true and capacity is returned
    2976              :         // as negative.
    2977              : 
    2978              :         // Return value
    2979              :         Real64 CoilCapacity; // returned capacity of matched coil
    2980              : 
    2981              :         // FUNCTION LOCAL VARIABLE DECLARATIONS:
    2982              :         int WhichCoil;
    2983              : 
    2984              :         // Obtains and Allocates HeatingCoil related parameters from input file
    2985           22 :         if (state.dataHeatingCoils->GetCoilsInputFlag) { // First time subroutine has been entered
    2986            0 :             GetHeatingCoilInput(state);
    2987            0 :             state.dataHeatingCoils->GetCoilsInputFlag = false;
    2988              :         }
    2989              : 
    2990           22 :         int FoundType = Util::FindItem(CoilType, HVAC::cAllCoilTypes, HVAC::NumAllCoilTypes);
    2991           22 :         if (FoundType == HVAC::Coil_HeatingElectric || FoundType == HVAC::Coil_HeatingGasOrOtherFuel ||
    2992              :             FoundType == HVAC::Coil_HeatingDesuperheater) {
    2993           22 :             WhichCoil = Util::FindItem(CoilName, state.dataHeatingCoils->HeatingCoil);
    2994           22 :             if (WhichCoil != 0) {
    2995           22 :                 CoilCapacity = state.dataHeatingCoils->HeatingCoil(WhichCoil).NominalCapacity;
    2996              :             }
    2997            0 :         } else if (FoundType == HVAC::Coil_HeatingElectric_MultiStage || FoundType == HVAC::Coil_HeatingGas_MultiStage) {
    2998            0 :             WhichCoil = Util::FindItem(CoilName, state.dataHeatingCoils->HeatingCoil);
    2999            0 :             if (WhichCoil != 0) {
    3000            0 :                 CoilCapacity =
    3001            0 :                     state.dataHeatingCoils->HeatingCoil(WhichCoil).MSNominalCapacity(state.dataHeatingCoils->HeatingCoil(WhichCoil).NumOfStages);
    3002              :             }
    3003              :         } else {
    3004            0 :             WhichCoil = 0;
    3005              :         }
    3006              : 
    3007           22 :         if (WhichCoil == 0) { // Autodesk:Return Reworked block to assure CoilCapacity is set before return
    3008            0 :             if (FoundType == 0) {
    3009            0 :                 ShowSevereError(state, format("GetCoilCapacity: Could not find Coil, Type=\"{}\" Name=\"{}\"", CoilType, CoilName));
    3010            0 :             } else if (FoundType > 0) {
    3011            0 :                 ShowSevereError(state, format("GetCoilCapacity: Invalid coil type for capacity, Type=\"{}\" Name=\"{}\"", CoilType, CoilName));
    3012            0 :                 ShowContinueError(state,
    3013            0 :                                   format("...only {}, {} or {} are valid in this context.",
    3014              :                                          HVAC::cAllCoilTypes(HVAC::Coil_HeatingElectric),
    3015              :                                          HVAC::cAllCoilTypes(HVAC::Coil_HeatingGasOrOtherFuel),
    3016              :                                          HVAC::cAllCoilTypes(HVAC::Coil_HeatingDesuperheater)));
    3017              :             }
    3018            0 :             ShowContinueError(state, "... returning Coil Capacity as -1000.");
    3019            0 :             ErrorsFound = true;
    3020            0 :             CoilCapacity = -1000.0;
    3021              :         }
    3022              : 
    3023           22 :         return CoilCapacity;
    3024              :     }
    3025              : 
    3026            0 :     Sched::Schedule *GetCoilAvailSched(EnergyPlusData &state,
    3027              :                                        std::string const &CoilType, // must match coil types in this module
    3028              :                                        std::string const &CoilName, // must match coil names for the coil type
    3029              :                                        bool &ErrorsFound            // set to true if problem
    3030              :     )
    3031              :     {
    3032              : 
    3033              :         // FUNCTION INFORMATION:
    3034              :         //       AUTHOR         Richard Raustad, FSEC
    3035              :         //       DATE WRITTEN   February 2013
    3036              : 
    3037              :         // PURPOSE OF THIS FUNCTION:
    3038              :         // This function looks up the given coil and returns the availability schedule index.  If
    3039              :         // incorrect coil type or name is given, ErrorsFound is returned as true and index is returned
    3040              :         // as zero.
    3041              : 
    3042              :         // Obtains and Allocates HeatingCoil related parameters from input file
    3043            0 :         if (state.dataHeatingCoils->GetCoilsInputFlag) { // First time subroutine has been entered
    3044            0 :             GetHeatingCoilInput(state);
    3045            0 :             state.dataHeatingCoils->GetCoilsInputFlag = false;
    3046              :         }
    3047              : 
    3048            0 :         int WhichCoil = 0;
    3049            0 :         int FoundType = Util::FindItem(CoilType, HVAC::cAllCoilTypes, HVAC::NumAllCoilTypes);
    3050            0 :         if (FoundType == HVAC::Coil_HeatingElectric || FoundType == HVAC::Coil_HeatingElectric_MultiStage ||
    3051            0 :             FoundType == HVAC::Coil_HeatingGasOrOtherFuel || FoundType == HVAC::Coil_HeatingGas_MultiStage ||
    3052              :             FoundType == HVAC::Coil_HeatingDesuperheater) {
    3053            0 :             WhichCoil = Util::FindItem(CoilName, state.dataHeatingCoils->HeatingCoil);
    3054            0 :             if (WhichCoil != 0) {
    3055            0 :                 return state.dataHeatingCoils->HeatingCoil(WhichCoil).availSched;
    3056              :             }
    3057              :         } else {
    3058            0 :             WhichCoil = 0;
    3059              :         }
    3060              : 
    3061            0 :         if (WhichCoil == 0) {
    3062            0 :             ShowSevereError(state, format("GetCoilAvailScheduleIndex: Could not find Coil, Type=\"{}\" Name=\"{}\"", CoilType, CoilName));
    3063            0 :             ErrorsFound = true;
    3064              :         }
    3065              : 
    3066            0 :         return nullptr;
    3067              :     }
    3068              : 
    3069           21 :     int GetCoilInletNode(EnergyPlusData &state,
    3070              :                          std::string_view CoilType,   // must match coil types in this module
    3071              :                          std::string const &CoilName, // must match coil names for the coil type
    3072              :                          bool &ErrorsFound            // set to true if problem
    3073              :     )
    3074              :     {
    3075              : 
    3076              :         // FUNCTION INFORMATION:
    3077              :         //       AUTHOR         Linda Lawrie
    3078              :         //       DATE WRITTEN   February 2006
    3079              : 
    3080              :         // PURPOSE OF THIS FUNCTION:
    3081              :         // This function looks up the given coil and returns the inlet node number.  If
    3082              :         // incorrect coil type or name is given, ErrorsFound is returned as true and node number is returned
    3083              :         // as zero.
    3084              : 
    3085              :         // Obtains and Allocates HeatingCoil related parameters from input file
    3086           21 :         if (state.dataHeatingCoils->GetCoilsInputFlag) { // First time subroutine has been entered
    3087            6 :             GetHeatingCoilInput(state);
    3088            6 :             state.dataHeatingCoils->GetCoilsInputFlag = false;
    3089              :         }
    3090              : 
    3091           21 :         int WhichCoil = 0;
    3092           21 :         int NodeNumber = 0;
    3093           21 :         int FoundType = Util::FindItem(CoilType, HVAC::cAllCoilTypes, HVAC::NumAllCoilTypes);
    3094           21 :         if (FoundType == HVAC::Coil_HeatingElectric || FoundType == HVAC::Coil_HeatingElectric_MultiStage ||
    3095            0 :             FoundType == HVAC::Coil_HeatingGasOrOtherFuel || FoundType == HVAC::Coil_HeatingGas_MultiStage ||
    3096              :             FoundType == HVAC::Coil_HeatingDesuperheater) {
    3097           21 :             WhichCoil = Util::FindItem(CoilName, state.dataHeatingCoils->HeatingCoil);
    3098           21 :             if (WhichCoil != 0) {
    3099           21 :                 NodeNumber = state.dataHeatingCoils->HeatingCoil(WhichCoil).AirInletNodeNum;
    3100              :             }
    3101              :         } else {
    3102            0 :             WhichCoil = 0;
    3103              :         }
    3104              : 
    3105           21 :         if (WhichCoil == 0) {
    3106            0 :             ShowSevereError(state, format("GetCoilInletNode: Could not find Coil, Type=\"{}\" Name=\"{}\"", CoilType, CoilName));
    3107            0 :             ErrorsFound = true;
    3108            0 :             NodeNumber = 0;
    3109              :         }
    3110              : 
    3111           21 :         return NodeNumber;
    3112              :     }
    3113              : 
    3114           24 :     int GetCoilOutletNode(EnergyPlusData &state,
    3115              :                           std::string_view CoilType,   // must match coil types in this module
    3116              :                           std::string const &CoilName, // must match coil names for the coil type
    3117              :                           bool &ErrorsFound            // set to true if problem
    3118              :     )
    3119              :     {
    3120              : 
    3121              :         // FUNCTION INFORMATION:
    3122              :         //       AUTHOR         Richard Raustad
    3123              :         //       DATE WRITTEN   August 2006
    3124              : 
    3125              :         // PURPOSE OF THIS FUNCTION:
    3126              :         // This function looks up the given coil and returns the outlet node number.  If
    3127              :         // incorrect coil type or name is given, ErrorsFound is returned as true and node number is returned
    3128              :         // as zero.
    3129              : 
    3130              :         // Obtains and Allocates HeatingCoil related parameters from input file
    3131           24 :         if (state.dataHeatingCoils->GetCoilsInputFlag) { // First time subroutine has been entered
    3132            2 :             GetHeatingCoilInput(state);
    3133            2 :             state.dataHeatingCoils->GetCoilsInputFlag = false;
    3134              :         }
    3135              : 
    3136           24 :         int WhichCoil = 0;
    3137           24 :         int NodeNumber = 0;
    3138           24 :         int FoundType = Util::FindItem(CoilType, HVAC::cAllCoilTypes, HVAC::NumAllCoilTypes);
    3139           24 :         if (FoundType == HVAC::Coil_HeatingElectric || FoundType == HVAC::Coil_HeatingElectric_MultiStage ||
    3140            0 :             FoundType == HVAC::Coil_HeatingGasOrOtherFuel || FoundType == HVAC::Coil_HeatingGas_MultiStage ||
    3141              :             FoundType == HVAC::Coil_HeatingDesuperheater) {
    3142           24 :             WhichCoil = Util::FindItem(CoilName, state.dataHeatingCoils->HeatingCoil);
    3143           24 :             if (WhichCoil != 0) {
    3144           24 :                 NodeNumber = state.dataHeatingCoils->HeatingCoil(WhichCoil).AirOutletNodeNum;
    3145              :             }
    3146              :         } else {
    3147            0 :             WhichCoil = 0;
    3148              :         }
    3149              : 
    3150           24 :         if (WhichCoil == 0) {
    3151            0 :             ShowSevereError(state, format("GetCoilOutletNode: Could not find Coil, Type=\"{}\" Name=\"{}\"", CoilType, CoilName));
    3152            0 :             ErrorsFound = true;
    3153            0 :             NodeNumber = 0;
    3154              :         }
    3155              : 
    3156           24 :         return NodeNumber;
    3157              :     }
    3158              : 
    3159            3 :     int GetHeatReclaimSourceIndex(EnergyPlusData &state,
    3160              :                                   std::string const &CoilType, // must match coil types in this module
    3161              :                                   std::string const &CoilName, // must match coil names for the coil type
    3162              :                                   bool &ErrorsFound            // set to true if problem
    3163              :     )
    3164              :     {
    3165              : 
    3166              :         // FUNCTION INFORMATION:
    3167              :         //       AUTHOR         Richard Raustad
    3168              :         //       DATE WRITTEN   June 2007
    3169              : 
    3170              :         // PURPOSE OF THIS FUNCTION:
    3171              :         // This function looks up the given coil and returns the heating coil index number if it is a desuperheating coil.
    3172              :         // If incorrect coil type or name is given, ErrorsFound is returned as true and index number is returned
    3173              :         // as zero.
    3174              : 
    3175              :         // FUNCTION LOCAL VARIABLE DECLARATIONS:
    3176              :         bool GetCoilErrFlag;
    3177              :         int NumCoil;
    3178            3 :         int CoilNum(0);
    3179              : 
    3180              :         // Obtains and Allocates HeatingCoil related parameters from input file
    3181            3 :         if (state.dataHeatingCoils->GetCoilsInputFlag) { // First time subroutine has been entered
    3182            1 :             GetHeatingCoilInput(state);
    3183            1 :             state.dataHeatingCoils->GetCoilsInputFlag = false;
    3184              :         }
    3185              : 
    3186            3 :         int CoilFound = 0;
    3187              : 
    3188              :         // note should eventually get rid of this string comparison
    3189            4 :         if (Util::SameString(CoilType, "COIL:COOLING:DX:SINGLESPEED") || Util::SameString(CoilType, "COIL:COOLING:DX:TWOSPEED") ||
    3190            4 :             Util::SameString(CoilType, "COIL:COOLING:DX:TWOSTAGEWITHHUMIDITYCONTROLMODE")) {
    3191            2 :             bool SuppressWarning = true;
    3192            2 :             DXCoils::GetDXCoilIndex(state, CoilName, CoilNum, GetCoilErrFlag, CoilType, SuppressWarning);
    3193            5 :             for (NumCoil = 1; NumCoil <= state.dataHeatingCoils->NumHeatingCoils; ++NumCoil) {
    3194            3 :                 if (state.dataHeatingCoils->HeatingCoil(NumCoil).ReclaimHeatingSource != HeatObjTypes::COIL_DX_COOLING &&
    3195            3 :                     state.dataHeatingCoils->HeatingCoil(NumCoil).ReclaimHeatingSource != HeatObjTypes::COIL_DX_MULTISPEED &&
    3196            9 :                     state.dataHeatingCoils->HeatingCoil(NumCoil).ReclaimHeatingSource != HeatObjTypes::COIL_DX_MULTIMODE &&
    3197            3 :                     state.dataHeatingCoils->HeatingCoil(NumCoil).ReclaimHeatingCoilName != CoilName) {
    3198            3 :                     continue;
    3199              :                 }
    3200            0 :                 CoilFound = CoilNum;
    3201            0 :                 break;
    3202              :             }
    3203            1 :         } else if (Util::SameString(CoilType, "COIL:COOLING:DX:VARIABLESPEED")) {
    3204            1 :             CoilNum = VariableSpeedCoils::GetCoilIndexVariableSpeed(state, CoilType, CoilName, GetCoilErrFlag);
    3205            3 :             for (NumCoil = 1; NumCoil <= state.dataHeatingCoils->NumHeatingCoils; ++NumCoil) {
    3206            4 :                 if (state.dataHeatingCoils->HeatingCoil(NumCoil).ReclaimHeatingSource != HeatObjTypes::COIL_DX_VARIABLE_COOLING &&
    3207            2 :                     state.dataHeatingCoils->HeatingCoil(NumCoil).ReclaimHeatingCoilName != CoilName) {
    3208            2 :                     continue;
    3209              :                 }
    3210            0 :                 CoilFound = CoilNum;
    3211            0 :                 break;
    3212              :             }
    3213              :         }
    3214              : 
    3215            3 :         if (CoilNum == 0) {
    3216            0 :             ErrorsFound = true;
    3217              :         }
    3218              : 
    3219            3 :         return CoilFound;
    3220              :     }
    3221              : 
    3222            3 :     int GetCoilControlNodeNum(EnergyPlusData &state,
    3223              :                               std::string const &CoilType, // must match coil types in this module
    3224              :                               std::string const &CoilName, // must match coil names for the coil type
    3225              :                               bool &ErrorsFound            // set to true if problem
    3226              :     )
    3227              :     {
    3228              : 
    3229              :         // FUNCTION INFORMATION:
    3230              :         //       AUTHOR         Richard Raustad
    3231              :         //       DATE WRITTEN   June 2007
    3232              : 
    3233              :         // PURPOSE OF THIS FUNCTION:
    3234              :         // This function looks up the given coil and returns the control node number.  If
    3235              :         // incorrect coil type or name is given, ErrorsFound is returned as true and node number is returned
    3236              :         // as zero.
    3237              : 
    3238              :         // Obtains and Allocates HeatingCoil related parameters from input file
    3239            3 :         if (state.dataHeatingCoils->GetCoilsInputFlag) { // First time subroutine has been entered
    3240            0 :             GetHeatingCoilInput(state);
    3241            0 :             state.dataHeatingCoils->GetCoilsInputFlag = false;
    3242              :         }
    3243              : 
    3244            3 :         int FoundType = Util::FindItem(CoilType, HVAC::cAllCoilTypes, HVAC::NumAllCoilTypes);
    3245            3 :         if (FoundType == HVAC::Coil_HeatingElectric || FoundType == HVAC::Coil_HeatingElectric_MultiStage ||
    3246            0 :             FoundType == HVAC::Coil_HeatingGasOrOtherFuel || FoundType == HVAC::Coil_HeatingGas_MultiStage ||
    3247              :             FoundType == HVAC::Coil_HeatingDesuperheater) {
    3248            3 :             int WhichCoil = Util::FindItem(CoilName, state.dataHeatingCoils->HeatingCoil);
    3249            3 :             if (WhichCoil != 0) {
    3250            3 :                 return state.dataHeatingCoils->HeatingCoil(WhichCoil).TempSetPointNodeNum;
    3251              :             }
    3252              :         }
    3253              : 
    3254            0 :         ShowSevereError(state, format("GetCoilControlNodeNum: Could not find Coil, Type=\"{}\" Name=\"{}\"", CoilType, CoilName));
    3255            0 :         ErrorsFound = true;
    3256            0 :         return 0;
    3257              :     }
    3258              : 
    3259           81 :     int GetHeatingCoilTypeNum(EnergyPlusData &state,
    3260              :                               std::string const &CoilType, // must match coil types in this module
    3261              :                               std::string const &CoilName, // must match coil names for the coil type
    3262              :                               bool &ErrorsFound            // set to true if problem
    3263              :     )
    3264              :     {
    3265              : 
    3266              :         // FUNCTION INFORMATION:
    3267              :         //       AUTHOR         Richard Raustad
    3268              :         //       DATE WRITTEN   August 2008
    3269              : 
    3270              :         // PURPOSE OF THIS FUNCTION:
    3271              :         // This function looks up the given coil and returns the type number.  If
    3272              :         // incorrect coil type or name is given, ErrorsFound is returned as true and type number is returned
    3273              :         // as zero.
    3274              : 
    3275              :         // Obtains and Allocates HeatingCoil related parameters from input file
    3276           81 :         if (state.dataHeatingCoils->GetCoilsInputFlag) { // First time subroutine has been entered
    3277           49 :             GetHeatingCoilInput(state);
    3278           49 :             state.dataHeatingCoils->GetCoilsInputFlag = false;
    3279              :         }
    3280              : 
    3281           81 :         int FoundType = Util::FindItem(CoilType, HVAC::cAllCoilTypes, HVAC::NumAllCoilTypes);
    3282           81 :         if (FoundType == HVAC::Coil_HeatingElectric || FoundType == HVAC::Coil_HeatingElectric_MultiStage ||
    3283            1 :             FoundType == HVAC::Coil_HeatingGasOrOtherFuel || FoundType == HVAC::Coil_HeatingGas_MultiStage ||
    3284              :             FoundType == HVAC::Coil_HeatingDesuperheater) {
    3285           81 :             int WhichCoil = Util::FindItem(CoilName, state.dataHeatingCoils->HeatingCoil);
    3286           81 :             if (WhichCoil != 0) {
    3287           81 :                 return state.dataHeatingCoils->HeatingCoil(WhichCoil).HCoilType_Num;
    3288              :             }
    3289              :         }
    3290              : 
    3291            0 :         ShowSevereError(state, format("GetHeatingCoilTypeNum: Could not find Coil, Type=\"{}\" Name=\"{}\"", CoilType, CoilName));
    3292            0 :         ErrorsFound = true;
    3293            0 :         return 0;
    3294              :     }
    3295              : 
    3296           37 :     int GetHeatingCoilIndex(EnergyPlusData &state,
    3297              :                             std::string const &CoilType, // must match coil types in this module
    3298              :                             std::string const &CoilName, // must match coil names for the coil type
    3299              :                             bool &ErrorsFound            // set to true if problem
    3300              :     )
    3301              :     {
    3302              : 
    3303              :         // FUNCTION INFORMATION:
    3304              :         //       AUTHOR         Linda Lawrie
    3305              :         //       DATE WRITTEN   February 2011
    3306              : 
    3307              :         // PURPOSE OF THIS FUNCTION:
    3308              :         // This function looks up the given coil and returns the index into the structure.  If
    3309              :         // incorrect coil type or name is given, ErrorsFound is returned as true and index is returned
    3310              :         // as zero.
    3311              : 
    3312              :         // Obtains and Allocates HeatingCoil related parameters from input file
    3313           37 :         if (state.dataHeatingCoils->GetCoilsInputFlag) { // First time subroutine has been entered
    3314            2 :             GetHeatingCoilInput(state);
    3315            2 :             state.dataHeatingCoils->GetCoilsInputFlag = false;
    3316              :         }
    3317              : 
    3318           37 :         int WhichCoil = 0;
    3319           37 :         int FoundType = Util::FindItem(CoilType, HVAC::cAllCoilTypes, HVAC::NumAllCoilTypes);
    3320           37 :         if (FoundType == HVAC::Coil_HeatingElectric || FoundType == HVAC::Coil_HeatingElectric_MultiStage ||
    3321            0 :             FoundType == HVAC::Coil_HeatingGasOrOtherFuel || FoundType == HVAC::Coil_HeatingGas_MultiStage ||
    3322              :             FoundType == HVAC::Coil_HeatingDesuperheater) {
    3323           37 :             WhichCoil = Util::FindItem(CoilName, state.dataHeatingCoils->HeatingCoil);
    3324              :         }
    3325              : 
    3326           37 :         if (WhichCoil == 0) {
    3327            0 :             ShowSevereError(state, format("GetHeatingCoilIndex: Could not find Coil, Type=\"{}\" Name=\"{}\"", CoilType, CoilName));
    3328            0 :             ErrorsFound = true;
    3329              :         }
    3330              : 
    3331           37 :         return WhichCoil;
    3332              :     }
    3333              : 
    3334            0 :     int GetHeatingCoilPLFCurveIndex(EnergyPlusData &state,
    3335              :                                     std::string const &CoilType, // must match coil types in this module
    3336              :                                     std::string const &CoilName, // must match coil names for the coil type
    3337              :                                     bool &ErrorsFound            // set to true if problem
    3338              :     )
    3339              :     {
    3340              : 
    3341              :         // FUNCTION INFORMATION:
    3342              :         //       AUTHOR         Richard Raustad
    3343              :         //       DATE WRITTEN   December 2008
    3344              : 
    3345              :         // PURPOSE OF THIS FUNCTION:
    3346              :         // This function looks up the given coil and returns the PLF curve index.  If
    3347              :         // incorrect coil name is given for gas or electric heating coils, ErrorsFound
    3348              :         // is returned as true and curve index is returned as zero.
    3349              :         // If not a gas or electric heating coil, ErrorsFound is unchanged and index is 0.
    3350              : 
    3351              :         // Obtains and Allocates HeatingCoil related parameters from input file
    3352            0 :         if (state.dataHeatingCoils->GetCoilsInputFlag) { // First time subroutine has been entered
    3353            0 :             GetHeatingCoilInput(state);
    3354            0 :             state.dataHeatingCoils->GetCoilsInputFlag = false;
    3355              :         }
    3356              : 
    3357            0 :         int FoundType = Util::FindItem(CoilType, HVAC::cAllCoilTypes, HVAC::NumAllCoilTypes);
    3358            0 :         if (FoundType == HVAC::Coil_HeatingElectric || FoundType == HVAC::Coil_HeatingElectric_MultiStage ||
    3359            0 :             FoundType == HVAC::Coil_HeatingGasOrOtherFuel || FoundType == HVAC::Coil_HeatingGas_MultiStage ||
    3360              :             FoundType == HVAC::Coil_HeatingDesuperheater) {
    3361            0 :             int WhichCoil = Util::FindItem(CoilName, state.dataHeatingCoils->HeatingCoil);
    3362            0 :             if (WhichCoil != 0) {
    3363            0 :                 return state.dataHeatingCoils->HeatingCoil(WhichCoil).PLFCurveIndex;
    3364              :             } else {
    3365            0 :                 ShowSevereError(state, format("GetHeatingCoilPLFCurveIndex: Could not find Coil, Type=\"{}\" Name=\"{}\"", CoilType, CoilName));
    3366            0 :                 ErrorsFound = true;
    3367            0 :                 return 0;
    3368              :             }
    3369              :         } else {
    3370            0 :             return 0;
    3371              :         }
    3372              :     }
    3373              : 
    3374            0 :     int GetHeatingCoilNumberOfStages(EnergyPlusData &state,
    3375              :                                      std::string const &CoilType, // must match coil types in this module
    3376              :                                      std::string const &CoilName, // must match coil names for the coil type
    3377              :                                      bool &ErrorsFound            // set to true if problem
    3378              :     )
    3379              :     {
    3380              : 
    3381              :         // FUNCTION INFORMATION:
    3382              :         //       AUTHOR         Chandan Sharma
    3383              :         //       DATE WRITTEN   February 2013
    3384              : 
    3385              :         // PURPOSE OF THIS FUNCTION:
    3386              :         // This function looks up the given coil and returns the number of speeds for multistage coils.
    3387              :         // If incorrect coil type or name is given, ErrorsFound is returned as true.
    3388              : 
    3389              :         // Obtains and Allocates HeatingCoils
    3390            0 :         if (state.dataHeatingCoils->GetCoilsInputFlag) { // First time subroutine has been entered
    3391            0 :             GetHeatingCoilInput(state);
    3392            0 :             state.dataHeatingCoils->GetCoilsInputFlag = false;
    3393              :         }
    3394              : 
    3395            0 :         int WhichCoil = Util::FindItemInList(CoilName, state.dataHeatingCoils->HeatingCoil);
    3396            0 :         if (WhichCoil != 0) {
    3397            0 :             return state.dataHeatingCoils->HeatingCoil(WhichCoil).NumOfStages;
    3398              :         } else {
    3399            0 :             ShowSevereError(state, format("GetHeatingCoilNumberOfSpeeds: Invalid Heating Coil Type=\"{}\" Name=\"{}\"", CoilType, CoilName));
    3400            0 :             ErrorsFound = true;
    3401            0 :             return 0;
    3402              :         }
    3403              :     }
    3404              : 
    3405            3 :     void SetHeatingCoilData(EnergyPlusData &state,
    3406              :                             int const CoilNum,                                  // Number of electric or gas heating Coil
    3407              :                             bool &ErrorsFound,                                  // Set to true if certain errors found
    3408              :                             ObjexxFCL::Optional_bool DesiccantRegenerationCoil, // Flag that this coil is used as regeneration air heating coil
    3409              :                             ObjexxFCL::Optional_int DesiccantDehumIndex         // Index for the desiccant dehum system where this coil is used
    3410              :     )
    3411              :     {
    3412              : 
    3413              :         // FUNCTION INFORMATION:
    3414              :         //       AUTHOR         Bereket Nigusse
    3415              :         //       DATE WRITTEN   February 2016
    3416              : 
    3417              :         // PURPOSE OF THIS FUNCTION:
    3418              :         // This function sets data to Heating Coil using the coil index and arguments passed
    3419              : 
    3420            3 :         auto &heatingCoil = state.dataHeatingCoils->HeatingCoil(CoilNum);
    3421            3 :         if (state.dataHeatingCoils->GetCoilsInputFlag) {
    3422            0 :             GetHeatingCoilInput(state);
    3423            0 :             state.dataHeatingCoils->GetCoilsInputFlag = false;
    3424              :         }
    3425              : 
    3426            3 :         if (CoilNum <= 0 || CoilNum > state.dataHeatingCoils->NumHeatingCoils) {
    3427            0 :             ShowSevereError(state,
    3428            0 :                             format("SetHeatingCoilData: called with heating coil Number out of range={} should be >0 and <{}",
    3429              :                                    CoilNum,
    3430            0 :                                    state.dataHeatingCoils->NumHeatingCoils));
    3431            0 :             ErrorsFound = true;
    3432            0 :             return;
    3433              :         }
    3434              : 
    3435            3 :         if (present(DesiccantRegenerationCoil)) {
    3436            3 :             heatingCoil.DesiccantRegenerationCoil = DesiccantRegenerationCoil;
    3437              :         }
    3438              : 
    3439            3 :         if (present(DesiccantDehumIndex)) {
    3440            3 :             heatingCoil.DesiccantDehumNum = DesiccantDehumIndex;
    3441              :         }
    3442              :     }
    3443              : 
    3444            3 :     void SetHeatingCoilAirLoopNumber(EnergyPlusData &state, std::string const &HeatingCoilName, int AirLoopNum, bool &ErrorsFound)
    3445              :     {
    3446              :         // SUBROUTINE INFORMATION:
    3447              :         //       AUTHOR         L.Gu
    3448              :         //       DATE WRITTEN   March 2018
    3449              : 
    3450              :         // PURPOSE OF THIS SUBROUTINE:
    3451              :         // This subroutine sets an AirLoopNum for a given heating Coil
    3452              : 
    3453              :         int HeatingCoilIndex;
    3454              : 
    3455            3 :         if (state.dataHeatingCoils->GetCoilsInputFlag) { // First time subroutine has been entered
    3456            0 :             GetHeatingCoilInput(state);
    3457            0 :             state.dataHeatingCoils->GetCoilsInputFlag = false;
    3458              :         }
    3459              : 
    3460            3 :         HeatingCoilIndex = Util::FindItem(HeatingCoilName, state.dataHeatingCoils->HeatingCoil);
    3461            3 :         if (HeatingCoilIndex == 0) {
    3462            0 :             ShowSevereError(state, format("GetCoilIndex: Heating coil not found={}", HeatingCoilName));
    3463            0 :             ErrorsFound = true;
    3464              :         } else {
    3465            3 :             state.dataHeatingCoils->HeatingCoil(HeatingCoilIndex).AirLoopNum = AirLoopNum;
    3466              :         }
    3467            3 :     }
    3468              : } // namespace HeatingCoils
    3469              : 
    3470              : } // namespace EnergyPlus
        

Generated by: LCOV version 2.0-1