LCOV - code coverage report
Current view: top level - EnergyPlus - SingleDuct.cc (source / functions) Coverage Total Hit
Test: lcov.output.filtered Lines: 65.1 % 3182 2073
Test Date: 2025-06-02 12:03:30 Functions: 75.9 % 29 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              : 
      54              : // EnergyPlus Headers
      55              : #include <AirflowNetwork/Solver.hpp>
      56              : #include <EnergyPlus/Autosizing/Base.hh>
      57              : #include <EnergyPlus/BranchNodeConnections.hh>
      58              : #include <EnergyPlus/Data/EnergyPlusData.hh>
      59              : #include <EnergyPlus/DataContaminantBalance.hh>
      60              : #include <EnergyPlus/DataConvergParams.hh>
      61              : #include <EnergyPlus/DataDefineEquip.hh>
      62              : #include <EnergyPlus/DataEnvironment.hh>
      63              : #include <EnergyPlus/DataHVACGlobals.hh>
      64              : #include <EnergyPlus/DataHeatBalFanSys.hh>
      65              : #include <EnergyPlus/DataHeatBalance.hh>
      66              : #include <EnergyPlus/DataIPShortCuts.hh>
      67              : #include <EnergyPlus/DataLoopNode.hh>
      68              : #include <EnergyPlus/DataSizing.hh>
      69              : #include <EnergyPlus/DataZoneEnergyDemands.hh>
      70              : #include <EnergyPlus/DataZoneEquipment.hh>
      71              : #include <EnergyPlus/EMSManager.hh>
      72              : #include <EnergyPlus/Fans.hh>
      73              : #include <EnergyPlus/FluidProperties.hh>
      74              : #include <EnergyPlus/General.hh>
      75              : #include <EnergyPlus/GeneralRoutines.hh>
      76              : #include <EnergyPlus/GlobalNames.hh>
      77              : #include <EnergyPlus/HeatingCoils.hh>
      78              : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
      79              : #include <EnergyPlus/NodeInputManager.hh>
      80              : #include <EnergyPlus/OutputProcessor.hh>
      81              : #include <EnergyPlus/OutputReportPredefined.hh>
      82              : #include <EnergyPlus/Plant/DataPlant.hh>
      83              : #include <EnergyPlus/PlantUtilities.hh>
      84              : #include <EnergyPlus/Psychrometrics.hh>
      85              : #include <EnergyPlus/ReportCoilSelection.hh>
      86              : #include <EnergyPlus/ScheduleManager.hh>
      87              : #include <EnergyPlus/SingleDuct.hh>
      88              : #include <EnergyPlus/SteamCoils.hh>
      89              : #include <EnergyPlus/UtilityRoutines.hh>
      90              : #include <EnergyPlus/WaterCoils.hh>
      91              : #include <EnergyPlus/ZoneAirLoopEquipmentManager.hh>
      92              : 
      93              : namespace EnergyPlus::SingleDuct {
      94              : 
      95              : // Module containing the Single Duct Systems as a single component/ or really a single driver
      96              : 
      97              : // MODULE INFORMATION:
      98              : //       AUTHOR         Richard J. Liesen
      99              : //       DATE WRITTEN   January 2000
     100              : 
     101              : // PURPOSE OF THIS MODULE:
     102              : // To encapsulate the data and algorithms required to
     103              : // simulate single duct systems as a single driver or inter-connecting controllers.
     104              : 
     105              : // Using/Aliasing
     106              : using namespace DataLoopNode;
     107              : using BranchNodeConnections::SetUpCompSets;
     108              : using BranchNodeConnections::TestCompSet;
     109              : using HVAC::SmallAirVolFlow;
     110              : using HVAC::SmallLoad;
     111              : using HVAC::SmallMassFlow;
     112              : using namespace DataSizing;
     113              : using Psychrometrics::PsyCpAirFnW;
     114              : using Psychrometrics::PsyRhoAirFnPbTdbW;
     115              : using namespace SteamCoils;
     116              : 
     117        97453 : void SimulateSingleDuct(
     118              :     EnergyPlusData &state, std::string_view CompName, bool const FirstHVACIteration, int const ZoneNum, int const ZoneNodeNum, int &CompIndex)
     119              : {
     120              : 
     121              :     // SUBROUTINE INFORMATION:
     122              :     //       AUTHOR         Richard Liesen
     123              :     //       DATE WRITTEN   January 2000
     124              : 
     125              :     // PURPOSE OF THIS SUBROUTINE:
     126              :     // This subroutine manages Sys system simulation.
     127              :     // It is called from the ManageZoneEquip
     128              :     // at the system time step.
     129              : 
     130              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     131              :     int SysNum; // The Sys that you are currently loading input into
     132              : 
     133              :     // Obtains and Allocates Sys related parameters from input file
     134        97453 :     if (state.dataSingleDuct->GetInputFlag) { // First time subroutine has been entered
     135           29 :         GetSysInput(state);
     136           29 :         state.dataSingleDuct->GetInputFlag = false;
     137              :     }
     138              : 
     139              :     // Find the correct SysNumber with the Component Name
     140        97453 :     if (CompIndex == 0) {
     141           47 :         SysNum = Util::FindItemInList(CompName, state.dataSingleDuct->sd_airterminal, &SingleDuctAirTerminal::SysName);
     142           47 :         if (SysNum == 0) {
     143            0 :             ShowFatalError(state, format("SimulateSingleDuct: System not found={}", CompName));
     144              :         }
     145           47 :         CompIndex = SysNum;
     146              :     } else {
     147        97406 :         SysNum = CompIndex;
     148        97406 :         if (SysNum > state.dataSingleDuct->NumSDAirTerminal || SysNum < 1) {
     149            0 :             ShowFatalError(state,
     150            0 :                            format("SimulateSingleDuct: Invalid CompIndex passed={}, Number of Systems={}, System name={}",
     151              :                                   CompIndex,
     152            0 :                                   state.dataSingleDuct->NumSDAirTerminal,
     153              :                                   CompName));
     154              :         }
     155        97406 :         if (state.dataSingleDuct->CheckEquipName(SysNum)) {
     156           33 :             if (CompName != state.dataSingleDuct->sd_airterminal(SysNum).SysName) {
     157            0 :                 ShowFatalError(state,
     158            0 :                                format("SimulateSingleDuct: Invalid CompIndex passed={}, System name={}, stored System Name for that index={}",
     159              :                                       CompIndex,
     160              :                                       CompName,
     161            0 :                                       state.dataSingleDuct->sd_airterminal(SysNum).SysName));
     162              :             }
     163           33 :             state.dataSingleDuct->CheckEquipName(SysNum) = false;
     164              :         }
     165              :     }
     166              : 
     167        97453 :     auto &thisATU(state.dataSingleDuct->sd_airterminal(SysNum));
     168              : 
     169        97453 :     state.dataSize->TermUnitSingDuct = true;
     170        97453 :     state.dataSize->CurTermUnitSizingNum = state.dataDefineEquipment->AirDistUnit(thisATU.ADUNum).TermUnitSizingNum;
     171              : 
     172              :     // With the correct SysNum Initialize the system
     173        97453 :     thisATU.InitSys(state, FirstHVACIteration); // Initialize all Sys related parameters
     174              : 
     175              :     // Calculate the Correct Sys Model with the current SysNum
     176        97453 :     switch (thisATU.SysType_Num) {
     177         3472 :     case SysType::SingleDuctConstVolReheat: // AirTerminal:SingleDuct:ConstantVolume:Reheat
     178         3472 :         thisATU.SimConstVol(state, FirstHVACIteration, ZoneNum, ZoneNodeNum);
     179         3472 :         break;
     180        30642 :     case SysType::SingleDuctConstVolNoReheat: // AirTerminal:SingleDuct:ConstantVolume:NoReheat
     181        30642 :         thisATU.SimConstVolNoReheat(state);
     182        30642 :         break;
     183        63337 :     case SysType::SingleDuctVAVReheat:   // SINGLE DUCT:VAV:REHEAT
     184              :     case SysType::SingleDuctVAVNoReheat: // SINGLE DUCT:VAV:NOREHEAT
     185        63337 :         thisATU.SimVAV(state, FirstHVACIteration, ZoneNum, ZoneNodeNum);
     186        63337 :         break;
     187            0 :     case SysType::SingleDuctVAVReheatVSFan: // SINGLE DUCT:VAV:REHEAT:VS FAN
     188            0 :         thisATU.SimVAVVS(state, FirstHVACIteration, ZoneNum, ZoneNodeNum);
     189            0 :         break;
     190            2 :     case SysType::SingleDuctCBVAVReheat:   // SINGLE DUCT:VAVHEATANDCOOL:REHEAT
     191              :     case SysType::SingleDuctCBVAVNoReheat: // SINGLE DUCT:VAVHEATANDCOOL:NOREHEAT
     192            2 :         thisATU.SimCBVAV(state, FirstHVACIteration, ZoneNum, ZoneNodeNum);
     193            2 :         break;
     194            0 :     default:
     195              :         // assert(false);
     196            0 :         break;
     197              :     }
     198              : 
     199              :     // Report the current Sys
     200        97453 :     thisATU.ReportSys(state);
     201              : 
     202        97453 :     state.dataSize->TermUnitSingDuct = false;
     203        97453 : }
     204              : 
     205              : // Get Input Section of the Module
     206              : //******************************************************************************
     207              : 
     208           72 : void GetSysInput(EnergyPlusData &state)
     209              : {
     210              : 
     211              :     // SUBROUTINE INFORMATION:
     212              :     //       AUTHOR         Richard Liesen
     213              :     //       DATE WRITTEN   April 1998
     214              : 
     215              :     // PURPOSE OF THIS SUBROUTINE:
     216              :     // This subroutine is the main routine to call other input routines and Get routines
     217              : 
     218              :     // METHODOLOGY EMPLOYED:
     219              :     // Uses the status flags to trigger events.
     220              : 
     221              :     // Using/Aliasing
     222              :     using NodeInputManager::GetOnlySingleNode;
     223              :     using SteamCoils::GetCoilAirOutletNode;
     224              :     using SteamCoils::GetCoilSteamInletNode;
     225              :     using SteamCoils::GetSteamCoilIndex;
     226              :     using WaterCoils::GetCoilOutletNode;
     227              :     using WaterCoils::GetCoilWaterInletNode;
     228           72 :     auto &GetHeatingCoilCapacity(HeatingCoils::GetCoilCapacity);
     229           72 :     auto &GetHeatingCoilOutletNode(HeatingCoils::GetCoilOutletNode);
     230              :     using namespace DataHeatBalance;
     231              : 
     232              :     // SUBROUTINE PARAMETER DEFINITIONS:
     233              :     static constexpr std::string_view RoutineName("GetSysInput: "); // include trailing blank
     234              :     static constexpr std::string_view routineName = "GetSysInput";
     235              : 
     236              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     237              : 
     238              :     int NumZoneSiz;
     239              :     int ZoneSizIndex;
     240              :     int IOStat;
     241           72 :     bool ErrorsFound(false);         // If errors detected in input
     242              :     bool IsNotOK;                    // Flag to verify name
     243              :     int CtrlZone;                    // controlled zone do loop index
     244              :     int SupAirIn;                    // controlled zone supply air inlet index
     245              :     int ADUNum;                      // air distribution unit index
     246           72 :     std::string CurrentModuleObject; // for ease in getting objects
     247           72 :     Array1D_string Alphas;           // Alpha input items for object
     248           72 :     Array1D_string cAlphaFields;     // Alpha field names
     249           72 :     Array1D_string cNumericFields;   // Numeric field names
     250           72 :     Array1D<Real64> Numbers;         // Numeric input items for object
     251           72 :     Array1D_bool lAlphaBlanks;       // Logical array, alpha field input BLANK = .TRUE.
     252           72 :     Array1D_bool lNumericBlanks;     // Logical array, numeric field input BLANK = .TRUE.
     253              : 
     254              :     //  certain object in the input file
     255           72 :     std::string AirTermSysInletNodeName;  // air terminal single duct system inlet node name
     256           72 :     std::string AirTermSysOutletNodeName; // air terminal single duct system outlet node name
     257              : 
     258           72 :     state.dataSingleDuct->NumVAVSysGSI = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "AirTerminal:SingleDuct:VAV:Reheat");
     259          144 :     state.dataSingleDuct->NumNoRHVAVSysGSI =
     260           72 :         state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "AirTerminal:SingleDuct:VAV:NoReheat");
     261          144 :     state.dataSingleDuct->NumConstVolSys =
     262           72 :         state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "AirTerminal:SingleDuct:ConstantVolume:Reheat");
     263          144 :     state.dataSingleDuct->NumCVNoReheatSysGSI =
     264           72 :         state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "AirTerminal:SingleDuct:ConstantVolume:NoReheat");
     265          144 :     state.dataSingleDuct->NumVAVVSGSI =
     266           72 :         state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "AirTerminal:SingleDuct:VAV:Reheat:VariableSpeedFan");
     267          144 :     state.dataSingleDuct->NumCBVAVSysGSI =
     268           72 :         state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "AirTerminal:SingleDuct:VAV:HeatAndCool:Reheat");
     269          144 :     state.dataSingleDuct->NumNoRHCBVAVSysGSI =
     270           72 :         state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "AirTerminal:SingleDuct:VAV:HeatAndCool:NoReheat");
     271           72 :     state.dataSingleDuct->NumSDAirTerminal = state.dataSingleDuct->NumVAVSysGSI + state.dataSingleDuct->NumConstVolSys +
     272           72 :                                              state.dataSingleDuct->NumCVNoReheatSysGSI + state.dataSingleDuct->NumNoRHVAVSysGSI +
     273           72 :                                              state.dataSingleDuct->NumVAVVSGSI + state.dataSingleDuct->NumCBVAVSysGSI +
     274           72 :                                              state.dataSingleDuct->NumNoRHCBVAVSysGSI;
     275              : 
     276           72 :     state.dataSingleDuct->sd_airterminal.allocate(state.dataSingleDuct->NumSDAirTerminal);
     277           72 :     state.dataSingleDuct->SysUniqueNames.reserve(static_cast<unsigned>(state.dataSingleDuct->NumSDAirTerminal));
     278           72 :     state.dataSingleDuct->CheckEquipName.dimension(state.dataSingleDuct->NumSDAirTerminal, true);
     279              : 
     280          144 :     state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state,
     281              :                                                                    "AirTerminal:SingleDuct:VAV:Reheat",
     282           72 :                                                                    state.dataSingleDuct->TotalArgsGSI,
     283           72 :                                                                    state.dataSingleDuct->NumAlphasGSI,
     284           72 :                                                                    state.dataSingleDuct->NumNumsGSI);
     285           72 :     state.dataSingleDuct->MaxNumsGSI = max(state.dataSingleDuct->MaxNumsGSI, state.dataSingleDuct->NumNumsGSI);
     286           72 :     state.dataSingleDuct->MaxAlphasGSI = max(state.dataSingleDuct->MaxAlphasGSI, state.dataSingleDuct->NumAlphasGSI);
     287          144 :     state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state,
     288              :                                                                    "AirTerminal:SingleDuct:VAV:NoReheat",
     289           72 :                                                                    state.dataSingleDuct->TotalArgsGSI,
     290           72 :                                                                    state.dataSingleDuct->NumAlphasGSI,
     291           72 :                                                                    state.dataSingleDuct->NumNumsGSI);
     292           72 :     state.dataSingleDuct->MaxNumsGSI = max(state.dataSingleDuct->MaxNumsGSI, state.dataSingleDuct->NumNumsGSI);
     293           72 :     state.dataSingleDuct->MaxAlphasGSI = max(state.dataSingleDuct->MaxAlphasGSI, state.dataSingleDuct->NumAlphasGSI);
     294          144 :     state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state,
     295              :                                                                    "AirTerminal:SingleDuct:ConstantVolume:Reheat",
     296           72 :                                                                    state.dataSingleDuct->TotalArgsGSI,
     297           72 :                                                                    state.dataSingleDuct->NumAlphasGSI,
     298           72 :                                                                    state.dataSingleDuct->NumNumsGSI);
     299           72 :     state.dataSingleDuct->MaxNumsGSI = max(state.dataSingleDuct->MaxNumsGSI, state.dataSingleDuct->NumNumsGSI);
     300           72 :     state.dataSingleDuct->MaxAlphasGSI = max(state.dataSingleDuct->MaxAlphasGSI, state.dataSingleDuct->NumAlphasGSI);
     301          144 :     state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state,
     302              :                                                                    "AirTerminal:SingleDuct:ConstantVolume:NoReheat",
     303           72 :                                                                    state.dataSingleDuct->TotalArgsGSI,
     304           72 :                                                                    state.dataSingleDuct->NumAlphasGSI,
     305           72 :                                                                    state.dataSingleDuct->NumNumsGSI);
     306           72 :     state.dataSingleDuct->MaxNumsGSI = max(state.dataSingleDuct->MaxNumsGSI, state.dataSingleDuct->NumNumsGSI);
     307           72 :     state.dataSingleDuct->MaxAlphasGSI = max(state.dataSingleDuct->MaxAlphasGSI, state.dataSingleDuct->NumAlphasGSI);
     308          144 :     state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state,
     309              :                                                                    "AirTerminal:SingleDuct:VAV:Reheat:VariableSpeedFan",
     310           72 :                                                                    state.dataSingleDuct->TotalArgsGSI,
     311           72 :                                                                    state.dataSingleDuct->NumAlphasGSI,
     312           72 :                                                                    state.dataSingleDuct->NumNumsGSI);
     313           72 :     state.dataSingleDuct->MaxNumsGSI = max(state.dataSingleDuct->MaxNumsGSI, state.dataSingleDuct->NumNumsGSI);
     314           72 :     state.dataSingleDuct->MaxAlphasGSI = max(state.dataSingleDuct->MaxAlphasGSI, state.dataSingleDuct->NumAlphasGSI);
     315          144 :     state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state,
     316              :                                                                    "AirTerminal:SingleDuct:VAV:HeatAndCool:Reheat",
     317           72 :                                                                    state.dataSingleDuct->TotalArgsGSI,
     318           72 :                                                                    state.dataSingleDuct->NumAlphasGSI,
     319           72 :                                                                    state.dataSingleDuct->NumNumsGSI);
     320           72 :     state.dataSingleDuct->MaxNumsGSI = max(state.dataSingleDuct->MaxNumsGSI, state.dataSingleDuct->NumNumsGSI);
     321           72 :     state.dataSingleDuct->MaxAlphasGSI = max(state.dataSingleDuct->MaxAlphasGSI, state.dataSingleDuct->NumAlphasGSI);
     322          144 :     state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state,
     323              :                                                                    "AirTerminal:SingleDuct:VAV:HeatAndCool:NoReheat",
     324           72 :                                                                    state.dataSingleDuct->TotalArgsGSI,
     325           72 :                                                                    state.dataSingleDuct->NumAlphasGSI,
     326           72 :                                                                    state.dataSingleDuct->NumNumsGSI);
     327           72 :     state.dataSingleDuct->MaxNumsGSI = max(state.dataSingleDuct->MaxNumsGSI, state.dataSingleDuct->NumNumsGSI);
     328           72 :     state.dataSingleDuct->MaxAlphasGSI = max(state.dataSingleDuct->MaxAlphasGSI, state.dataSingleDuct->NumAlphasGSI);
     329              : 
     330           72 :     Alphas.allocate(state.dataSingleDuct->MaxAlphasGSI);
     331           72 :     cAlphaFields.allocate(state.dataSingleDuct->MaxAlphasGSI);
     332           72 :     cNumericFields.allocate(state.dataSingleDuct->MaxNumsGSI);
     333           72 :     Numbers.dimension(state.dataSingleDuct->MaxNumsGSI, 0.0);
     334           72 :     lAlphaBlanks.dimension(state.dataSingleDuct->MaxAlphasGSI, true);
     335           72 :     lNumericBlanks.dimension(state.dataSingleDuct->MaxNumsGSI, true);
     336              : 
     337              :     // Start Loading the System Input
     338           97 :     for (state.dataSingleDuct->SysIndexGSI = 1; state.dataSingleDuct->SysIndexGSI <= state.dataSingleDuct->NumVAVSysGSI;
     339           25 :          ++state.dataSingleDuct->SysIndexGSI) {
     340              : 
     341           25 :         CurrentModuleObject = "AirTerminal:SingleDuct:VAV:Reheat";
     342              : 
     343           50 :         state.dataInputProcessing->inputProcessor->getObjectItem(state,
     344              :                                                                  CurrentModuleObject,
     345           25 :                                                                  state.dataSingleDuct->SysIndexGSI,
     346              :                                                                  Alphas,
     347           25 :                                                                  state.dataSingleDuct->NumAlphasGSI,
     348              :                                                                  Numbers,
     349           25 :                                                                  state.dataSingleDuct->NumNumsGSI,
     350              :                                                                  IOStat,
     351              :                                                                  lNumericBlanks,
     352              :                                                                  lAlphaBlanks,
     353              :                                                                  cAlphaFields,
     354              :                                                                  cNumericFields);
     355              : 
     356           25 :         ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)};
     357              : 
     358           25 :         state.dataSingleDuct->SysNumGSI = state.dataSingleDuct->SysIndexGSI;
     359              : 
     360           25 :         auto &airTerm = state.dataSingleDuct->sd_airterminal(state.dataSingleDuct->SysNumGSI);
     361           25 :         airTerm.SysNum = state.dataSingleDuct->SysNumGSI;
     362           25 :         GlobalNames::VerifyUniqueInterObjectName(
     363           50 :             state, state.dataSingleDuct->SysUniqueNames, Alphas(1), CurrentModuleObject, cAlphaFields(1), ErrorsFound);
     364           25 :         airTerm.SysName = Alphas(1);
     365           25 :         airTerm.sysType = CurrentModuleObject;
     366           25 :         airTerm.SysType_Num = SysType::SingleDuctVAVReheat;
     367              : 
     368           25 :         airTerm.ReheatComp = Alphas(7);
     369           25 :         if (Util::SameString(airTerm.ReheatComp, "Coil:Heating:Fuel")) {
     370           12 :             airTerm.ReheatComp_Num = HeatingCoilType::Gas;
     371           13 :         } else if (Util::SameString(airTerm.ReheatComp, "Coil:Heating:Electric")) {
     372            6 :             airTerm.ReheatComp_Num = HeatingCoilType::Electric;
     373            7 :         } else if (Util::SameString(airTerm.ReheatComp, "Coil:Heating:Water")) {
     374            7 :             airTerm.ReheatComp_Num = HeatingCoilType::SimpleHeating;
     375            7 :             airTerm.ReheatComp_PlantType = DataPlant::PlantEquipmentType::CoilWaterSimpleHeating;
     376            0 :         } else if (Util::SameString(airTerm.ReheatComp, "Coil:Heating:Steam")) {
     377            0 :             airTerm.ReheatComp_Num = HeatingCoilType::SteamAirHeating;
     378            0 :             airTerm.ReheatComp_PlantType = DataPlant::PlantEquipmentType::CoilSteamAirHeating;
     379            0 :         } else if (!airTerm.ReheatComp.empty()) {
     380            0 :             ShowSevereError(state, format("Illegal {} = {}.", cAlphaFields(8), airTerm.ReheatComp));
     381            0 :             ShowContinueError(state, format("Occurs in {} = {}", airTerm.sysType, airTerm.SysName));
     382            0 :             ErrorsFound = true;
     383              :         }
     384              : 
     385           25 :         airTerm.ReheatName = Alphas(8);
     386           25 :         if (airTerm.ReheatComp_Num == HeatingCoilType::Gas || airTerm.ReheatComp_Num == HeatingCoilType::Electric) {
     387           18 :             HeatingCoils::GetCoilIndex(state, airTerm.ReheatName, airTerm.ReheatComp_Index, ErrorsFound);
     388           18 :             if (airTerm.ReheatComp_Index == 0) {
     389            0 :                 ShowSevereItemNotFound(state, eoh, cAlphaFields(8), Alphas(8));
     390            0 :                 ErrorsFound = true;
     391              :             }
     392            7 :         } else if (airTerm.ReheatComp_Num == HeatingCoilType::SimpleHeating) {
     393            7 :             airTerm.ReheatComp_Index = WaterCoils::GetWaterCoilIndex(state, airTerm.ReheatComp, airTerm.ReheatName, ErrorsFound);
     394            7 :             if (airTerm.ReheatComp_Index == 0) {
     395            0 :                 ShowSevereItemNotFound(state, eoh, cAlphaFields(8), Alphas(8));
     396            0 :                 ErrorsFound = true;
     397              :             }
     398            0 :         } else if (airTerm.ReheatComp_Num == HeatingCoilType::SteamAirHeating) {
     399            0 :             airTerm.ReheatComp_Index = SteamCoils::GetSteamCoilIndex(state, airTerm.ReheatComp, airTerm.ReheatName, ErrorsFound);
     400            0 :             if (airTerm.ReheatComp_Index == 0) {
     401            0 :                 ShowSevereItemNotFound(state, eoh, cAlphaFields(8), Alphas(8));
     402            0 :                 ErrorsFound = true;
     403              :             }
     404              :         }
     405              : 
     406           25 :         if (lAlphaBlanks(2)) {
     407            4 :             airTerm.availSched = Sched::GetScheduleAlwaysOn(state);
     408           21 :         } else if ((airTerm.availSched = Sched::GetSchedule(state, Alphas(2))) == nullptr) {
     409            0 :             ShowSevereItemNotFound(state, eoh, cAlphaFields(2), Alphas(2));
     410            0 :             ErrorsFound = true;
     411              :         }
     412              :         // For node connections, this object is both a parent and a non-parent, because the
     413              :         // VAV damper is not called out as a separate component, its nodes must be connected
     414              :         // as ObjectIsNotParent.  But for the reheat coil, the nodes are connected as ObjectIsParent
     415           75 :         airTerm.OutletNodeNum = GetOnlySingleNode(state,
     416           25 :                                                   Alphas(3),
     417              :                                                   ErrorsFound,
     418              :                                                   DataLoopNode::ConnectionObjectType::AirTerminalSingleDuctVAVReheat,
     419           25 :                                                   Alphas(1),
     420              :                                                   DataLoopNode::NodeFluidType::Air,
     421              :                                                   DataLoopNode::ConnectionType::Outlet,
     422              :                                                   NodeInputManager::CompFluidStream::Primary,
     423              :                                                   ObjectIsNotParent,
     424           25 :                                                   cAlphaFields(3));
     425           75 :         airTerm.InletNodeNum = GetOnlySingleNode(state,
     426           25 :                                                  Alphas(4),
     427              :                                                  ErrorsFound,
     428              :                                                  DataLoopNode::ConnectionObjectType::AirTerminalSingleDuctVAVReheat,
     429           25 :                                                  Alphas(1),
     430              :                                                  DataLoopNode::NodeFluidType::Air,
     431              :                                                  DataLoopNode::ConnectionType::Inlet,
     432              :                                                  NodeInputManager::CompFluidStream::Primary,
     433              :                                                  ObjectIsNotParent,
     434           25 :                                                  cAlphaFields(4));
     435           25 :         airTerm.MaxAirVolFlowRate = Numbers(1);
     436              : 
     437           25 :         if (Util::SameString(Alphas(5), "Constant")) {
     438           24 :             airTerm.ZoneMinAirFracMethod = MinFlowFraction::Constant;
     439            1 :         } else if (Util::SameString(Alphas(5), "FixedFlowRate")) {
     440            1 :             airTerm.ZoneMinAirFracMethod = MinFlowFraction::Fixed;
     441            0 :         } else if (Util::SameString(Alphas(5), "Scheduled")) {
     442            0 :             airTerm.ZoneMinAirFracMethod = MinFlowFraction::Scheduled;
     443              :         } else {
     444            0 :             ShowSevereError(state, format("{} = {} not found.", cAlphaFields(5), Alphas(5)));
     445            0 :             ShowContinueError(state, format("Occurs in {} = {}", airTerm.sysType, airTerm.SysName));
     446            0 :             ErrorsFound = true;
     447              :         }
     448              : 
     449           25 :         airTerm.ZoneMinAirFracDes = Numbers(2);
     450           25 :         if (lNumericBlanks(2)) {
     451            9 :             airTerm.ConstantMinAirFracSetByUser = false;
     452            9 :             airTerm.DesignMinAirFrac = 0.0;
     453              :         } else {
     454           16 :             airTerm.ConstantMinAirFracSetByUser = true;
     455           16 :             airTerm.DesignMinAirFrac = Numbers(2);
     456           16 :             if (airTerm.ZoneMinAirFracMethod == MinFlowFraction::Fixed) {
     457            0 :                 ShowWarningError(state, format("Since {} = {}, input for {} will be ignored.", cAlphaFields(5), Alphas(5), cNumericFields(2)));
     458            0 :                 ShowContinueError(state, format("Occurs in {} = {}", airTerm.sysType, airTerm.SysName));
     459            0 :                 airTerm.ZoneMinAirFracDes = 0.0;
     460              :             }
     461              :         }
     462              : 
     463           25 :         airTerm.ZoneFixedMinAir = Numbers(3);
     464           25 :         if (lNumericBlanks(3)) {
     465           25 :             airTerm.FixedMinAirSetByUser = false;
     466           25 :             airTerm.DesignMinAirFrac = 0.0;
     467              :         } else {
     468            0 :             airTerm.FixedMinAirSetByUser = true;
     469            0 :             airTerm.DesignMinAirFrac = Numbers(3);
     470            0 :             if (airTerm.ZoneMinAirFracMethod == MinFlowFraction::Constant) {
     471            0 :                 ShowWarningError(state, format("Since {} = {}, input for {} will be ignored.", cAlphaFields(5), Alphas(5), cNumericFields(3)));
     472            0 :                 ShowContinueError(state, format("Occurs in {} = {}", airTerm.sysType, airTerm.SysName));
     473            0 :                 airTerm.ZoneFixedMinAir = 0.0;
     474              :             }
     475              :         }
     476              : 
     477           25 :         if (airTerm.ZoneMinAirFracMethod != MinFlowFraction::Scheduled) {
     478            0 :         } else if (lAlphaBlanks(6)) {
     479            0 :             ShowSevereEmptyField(state, eoh, cAlphaFields(6));
     480            0 :             ErrorsFound = true;
     481            0 :         } else if ((airTerm.zoneMinAirFracSched = Sched::GetSchedule(state, Alphas(6))) == nullptr) {
     482            0 :             ShowSevereItemNotFound(state, eoh, cAlphaFields(6), Alphas(6));
     483            0 :             ErrorsFound = true;
     484            0 :         } else if (!airTerm.zoneMinAirFracSched->checkMinMaxVals(state, Clusive::In, 0.0, Clusive::In, 1.0)) {
     485            0 :             Sched::ShowSevereBadMinMax(state, eoh, cAlphaFields(6), Alphas(6), Clusive::In, 0.0, Clusive::In, 1.0);
     486            0 :             ErrorsFound = true;
     487              :         }
     488              : 
     489              :         // The reheat coil control node is necessary for hot water and steam reheat, but not necessary for
     490              :         // electric or gas reheat.
     491           25 :         if (airTerm.ReheatComp_Num != HeatingCoilType::Gas && airTerm.ReheatComp_Num != HeatingCoilType::Electric) {
     492            7 :             if (airTerm.ReheatComp_Num == HeatingCoilType::SteamAirHeating) {
     493            0 :                 IsNotOK = false;
     494            0 :                 airTerm.ReheatControlNode = GetCoilSteamInletNode(state, airTerm.ReheatComp, airTerm.ReheatName, IsNotOK);
     495            0 :                 if (IsNotOK) {
     496            0 :                     ShowContinueError(state, format("..Occurs in {} = {}", airTerm.sysType, airTerm.SysName));
     497            0 :                     ErrorsFound = true;
     498              :                 }
     499              :             } else {
     500            7 :                 IsNotOK = false;
     501            7 :                 airTerm.ReheatControlNode = GetCoilWaterInletNode(state, airTerm.ReheatComp, airTerm.ReheatName, IsNotOK);
     502            7 :                 if (IsNotOK) {
     503            0 :                     ShowContinueError(state, format("..Occurs in {} = {}", airTerm.sysType, airTerm.SysName));
     504            0 :                     ErrorsFound = true;
     505              :                 }
     506              :             }
     507              :         }
     508           75 :         airTerm.ReheatAirOutletNode = GetOnlySingleNode(state,
     509           25 :                                                         Alphas(9),
     510              :                                                         ErrorsFound,
     511              :                                                         DataLoopNode::ConnectionObjectType::AirTerminalSingleDuctVAVReheat,
     512           25 :                                                         Alphas(1),
     513              :                                                         DataLoopNode::NodeFluidType::Air,
     514              :                                                         DataLoopNode::ConnectionType::Outlet,
     515              :                                                         NodeInputManager::CompFluidStream::Primary,
     516              :                                                         ObjectIsParent,
     517           25 :                                                         cAlphaFields(9));
     518           25 :         if (airTerm.ReheatComp_Num == HeatingCoilType::SteamAirHeating) {
     519            0 :             airTerm.MaxReheatSteamVolFlow = Numbers(4);
     520            0 :             airTerm.MinReheatSteamVolFlow = Numbers(5);
     521              :         } else {
     522           25 :             airTerm.MaxReheatWaterVolFlow = Numbers(4);
     523           25 :             airTerm.MinReheatWaterVolFlow = Numbers(5);
     524              :         }
     525           25 :         airTerm.ControllerOffset = Numbers(6);
     526              :         // Set default convergence tolerance
     527           25 :         if (airTerm.ControllerOffset <= 0.0) {
     528            0 :             airTerm.ControllerOffset = 0.001;
     529              :         }
     530           25 :         if (Util::SameString(Alphas(10), "Reverse")) {
     531            5 :             airTerm.DamperHeatingAction = Action::Reverse;
     532           20 :         } else if (Util::SameString(Alphas(10), "Normal")) {
     533            3 :             airTerm.DamperHeatingAction = Action::Normal;
     534           17 :         } else if (Util::SameString(Alphas(10), "ReverseWithLimits")) {
     535           17 :             airTerm.DamperHeatingAction = Action::ReverseWithLimits;
     536              :         } else {
     537            0 :             ShowSevereError(state, format("{} = {} not found.", cAlphaFields(10), Alphas(10)));
     538            0 :             ShowContinueError(state, format("Occurs in {} = {}", airTerm.sysType, airTerm.SysName));
     539            0 :             ErrorsFound = true;
     540              :         }
     541              : 
     542              :         // Register component set data
     543           50 :         TestCompSet(state,
     544              :                     airTerm.sysType,
     545              :                     airTerm.SysName,
     546           25 :                     state.dataLoopNodes->NodeID(airTerm.InletNodeNum),
     547           25 :                     state.dataLoopNodes->NodeID(airTerm.ReheatAirOutletNode),
     548              :                     "Air Nodes");
     549              : 
     550           33 :         for (ADUNum = 1; ADUNum <= (int)state.dataDefineEquipment->AirDistUnit.size(); ++ADUNum) {
     551           33 :             if (airTerm.ReheatAirOutletNode == state.dataDefineEquipment->AirDistUnit(ADUNum).OutletNodeNum) {
     552           25 :                 state.dataDefineEquipment->AirDistUnit(ADUNum).InletNodeNum = airTerm.InletNodeNum;
     553           25 :                 airTerm.ADUNum = ADUNum;
     554           25 :                 break;
     555              :             }
     556              :         }
     557              :         // one assumes if there isn't one assigned, it's an error?
     558           25 :         if (airTerm.ADUNum == 0) {
     559            0 :             ShowSevereError(state,
     560            0 :                             format("{}No matching Air Distribution Unit, for System = [{},{}].", RoutineName, airTerm.sysType, airTerm.SysName));
     561            0 :             ShowContinueError(state, format("...should have outlet node = {}", state.dataLoopNodes->NodeID(airTerm.ReheatAirOutletNode)));
     562            0 :             ErrorsFound = true;
     563              :         } else {
     564              : 
     565              :             // Fill the Zone Equipment data with the inlet node number of this unit.
     566           73 :             for (CtrlZone = 1; CtrlZone <= state.dataGlobal->NumOfZones; ++CtrlZone) {
     567           48 :                 if (!state.dataZoneEquip->ZoneEquipConfig(CtrlZone).IsControlled) {
     568            8 :                     continue;
     569              :                 }
     570           81 :                 for (SupAirIn = 1; SupAirIn <= state.dataZoneEquip->ZoneEquipConfig(CtrlZone).NumInletNodes; ++SupAirIn) {
     571           41 :                     if (airTerm.ReheatAirOutletNode == state.dataZoneEquip->ZoneEquipConfig(CtrlZone).InletNode(SupAirIn)) {
     572           24 :                         if (state.dataZoneEquip->ZoneEquipConfig(CtrlZone).AirDistUnitCool(SupAirIn).OutNode > 0) {
     573            0 :                             ShowSevereError(state, "Error in connecting a terminal unit to a zone");
     574            0 :                             ShowContinueError(
     575            0 :                                 state, format("{} already connects to another zone", state.dataLoopNodes->NodeID(airTerm.ReheatAirOutletNode)));
     576            0 :                             ShowContinueError(state, format("Occurs for terminal unit {} = {}", airTerm.sysType, airTerm.SysName));
     577            0 :                             ShowContinueError(state, "Check terminal unit node names for errors");
     578            0 :                             ErrorsFound = true;
     579              :                         } else {
     580           24 :                             state.dataZoneEquip->ZoneEquipConfig(CtrlZone).AirDistUnitCool(SupAirIn).InNode = airTerm.InletNodeNum;
     581           24 :                             state.dataZoneEquip->ZoneEquipConfig(CtrlZone).AirDistUnitCool(SupAirIn).OutNode = airTerm.ReheatAirOutletNode;
     582           24 :                             state.dataDefineEquipment->AirDistUnit(airTerm.ADUNum).TermUnitSizingNum =
     583           24 :                                 state.dataZoneEquip->ZoneEquipConfig(CtrlZone).AirDistUnitCool(SupAirIn).TermUnitSizingIndex;
     584           24 :                             state.dataDefineEquipment->AirDistUnit(airTerm.ADUNum).ZoneEqNum = CtrlZone;
     585              :                         }
     586              : 
     587           24 :                         airTerm.CtrlZoneNum = CtrlZone;
     588           24 :                         airTerm.CtrlZoneInNodeIndex = SupAirIn;
     589           24 :                         airTerm.ZoneFloorArea = state.dataHeatBal->Zone(CtrlZone).FloorArea * state.dataHeatBal->Zone(CtrlZone).Multiplier *
     590           24 :                                                 state.dataHeatBal->Zone(CtrlZone).ListMultiplier;
     591              :                     }
     592              :                 }
     593              :             }
     594              :         }
     595           25 :         if (Numbers(7) == Constant::AutoCalculate) {
     596           25 :             airTerm.MaxAirVolFlowRateDuringReheat = Numbers(7);
     597              :         } else {
     598            0 :             airTerm.MaxAirVolFlowRateDuringReheat = Numbers(7) * airTerm.ZoneFloorArea;
     599              :         }
     600              : 
     601           25 :         airTerm.MaxAirVolFractionDuringReheat = Numbers(8);
     602              : 
     603           25 :         if (airTerm.DamperHeatingAction != Action::ReverseWithLimits) {
     604            8 :             if (airTerm.MaxAirVolFlowRateDuringReheat > 0.0) {
     605            0 :                 ShowWarningError(state, format("Since {} = {}, input for {} will be ignored.", cAlphaFields(10), Alphas(10), cNumericFields(7)));
     606            0 :                 ShowContinueError(state, format("Occurs in {} = {}", airTerm.sysType, airTerm.SysName));
     607              :             }
     608            8 :             if (airTerm.MaxAirVolFractionDuringReheat > 0.0) {
     609            0 :                 ShowWarningError(state, format("Since {} = {}, input for {} will be ignored.", cAlphaFields(10), Alphas(10), cNumericFields(8)));
     610            0 :                 ShowContinueError(state, format("Occurs in {} = {}", airTerm.sysType, airTerm.SysName));
     611              :             }
     612              :         }
     613              : 
     614              :         // Maximum reheat air temperature, i.e. the maximum supply air temperature leaving the reheat coil
     615           25 :         if (!lNumericBlanks(9)) {
     616            3 :             airTerm.MaxReheatTemp = Numbers(9);
     617            3 :             airTerm.MaxReheatTempSetByUser = true;
     618              :         } else {
     619              :             // user does not specify maximum supply air temperature
     620              :             // sd_airterminal(SysNum)%MaxReheatTemp = 35.0D0 !C
     621           22 :             airTerm.MaxReheatTempSetByUser = false;
     622              :         }
     623              : 
     624           25 :         if (!lAlphaBlanks(11)) {
     625            0 :             airTerm.OARequirementsPtr = Util::FindItemInList(Alphas(11), state.dataSize->OARequirements);
     626            0 :             if (airTerm.OARequirementsPtr == 0) {
     627            0 :                 ShowSevereError(state, format("{} = {} not found.", cAlphaFields(11), Alphas(11)));
     628            0 :                 ShowContinueError(state, format("Occurs in {} = {}", airTerm.sysType, airTerm.SysName));
     629            0 :                 ErrorsFound = true;
     630              :             } else {
     631            0 :                 airTerm.NoOAFlowInputFromUser = false;
     632              :             }
     633              :         }
     634              : 
     635           25 :         if (lAlphaBlanks(12)) {
     636           23 :             airTerm.ZoneTurndownMinAirFrac = 1.0;
     637            2 :         } else if ((airTerm.zoneTurndownMinAirFracSched = Sched::GetSchedule(state, Alphas(12))) == nullptr) {
     638            0 :             ShowSevereItemNotFound(state, eoh, cAlphaFields(12), Alphas(12));
     639            0 :             ErrorsFound = true;
     640              :         }
     641              : 
     642           25 :         ValidateComponent(state, Alphas(7), Alphas(8), IsNotOK, airTerm.sysType);
     643           25 :         if (IsNotOK) {
     644            0 :             ShowContinueError(state, format("In {} = {}", airTerm.sysType, airTerm.SysName));
     645            0 :             ErrorsFound = true;
     646              :         }
     647              : 
     648              :         // Add reheat coil to component sets array
     649           25 :         SetUpCompSets(state, airTerm.sysType, airTerm.SysName, Alphas(7), Alphas(8), Alphas(3), Alphas(9));
     650              : 
     651              :         // Setup the Average damper Position output variable
     652           50 :         SetupOutputVariable(state,
     653              :                             "Zone Air Terminal VAV Damper Position",
     654              :                             Constant::Units::None,
     655           25 :                             airTerm.DamperPosition,
     656              :                             OutputProcessor::TimeStepType::System,
     657              :                             OutputProcessor::StoreType::Average,
     658           25 :                             airTerm.SysName);
     659           50 :         SetupOutputVariable(state,
     660              :                             "Zone Air Terminal Minimum Air Flow Fraction",
     661              :                             Constant::Units::None,
     662           25 :                             airTerm.ZoneMinAirFracReport,
     663              :                             OutputProcessor::TimeStepType::System,
     664              :                             OutputProcessor::StoreType::Average,
     665           25 :                             airTerm.SysName);
     666              : 
     667              :     } // end Number of Sys Loop
     668              : 
     669           77 :     for (state.dataSingleDuct->SysIndexGSI = 1; state.dataSingleDuct->SysIndexGSI <= state.dataSingleDuct->NumCBVAVSysGSI;
     670            5 :          ++state.dataSingleDuct->SysIndexGSI) {
     671              : 
     672            5 :         CurrentModuleObject = "AirTerminal:SingleDuct:VAV:HeatAndCool:Reheat";
     673              : 
     674           10 :         state.dataInputProcessing->inputProcessor->getObjectItem(state,
     675              :                                                                  CurrentModuleObject,
     676            5 :                                                                  state.dataSingleDuct->SysIndexGSI,
     677              :                                                                  Alphas,
     678            5 :                                                                  state.dataSingleDuct->NumAlphasGSI,
     679              :                                                                  Numbers,
     680            5 :                                                                  state.dataSingleDuct->NumNumsGSI,
     681              :                                                                  IOStat,
     682              :                                                                  lNumericBlanks,
     683              :                                                                  lAlphaBlanks,
     684              :                                                                  cAlphaFields,
     685              :                                                                  cNumericFields);
     686              : 
     687            5 :         ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)};
     688            5 :         state.dataSingleDuct->SysNumGSI = state.dataSingleDuct->SysIndexGSI + state.dataSingleDuct->NumVAVSysGSI;
     689              : 
     690            5 :         auto &airTerm = state.dataSingleDuct->sd_airterminal(state.dataSingleDuct->SysNumGSI);
     691            5 :         airTerm.SysNum = state.dataSingleDuct->SysNumGSI;
     692            5 :         GlobalNames::VerifyUniqueInterObjectName(
     693           10 :             state, state.dataSingleDuct->SysUniqueNames, Alphas(1), CurrentModuleObject, cAlphaFields(1), ErrorsFound);
     694            5 :         airTerm.SysName = Alphas(1);
     695            5 :         airTerm.sysType = CurrentModuleObject;
     696            5 :         airTerm.SysType_Num = SysType::SingleDuctCBVAVReheat;
     697            5 :         airTerm.ReheatComp = Alphas(5);
     698            5 :         if (Util::SameString(airTerm.ReheatComp, "Coil:Heating:Fuel")) {
     699            3 :             airTerm.ReheatComp_Num = HeatingCoilType::Gas;
     700            2 :         } else if (Util::SameString(airTerm.ReheatComp, "Coil:Heating:Electric")) {
     701            2 :             airTerm.ReheatComp_Num = HeatingCoilType::Electric;
     702            0 :         } else if (Util::SameString(airTerm.ReheatComp, "Coil:Heating:Water")) {
     703            0 :             airTerm.ReheatComp_Num = HeatingCoilType::SimpleHeating;
     704            0 :             airTerm.ReheatComp_PlantType = DataPlant::PlantEquipmentType::CoilWaterSimpleHeating;
     705            0 :         } else if (Util::SameString(airTerm.ReheatComp, "Coil:Heating:Steam")) {
     706            0 :             airTerm.ReheatComp_Num = HeatingCoilType::SteamAirHeating;
     707            0 :             airTerm.ReheatComp_PlantType = DataPlant::PlantEquipmentType::CoilSteamAirHeating;
     708            0 :         } else if (!airTerm.ReheatComp.empty()) {
     709            0 :             ShowSevereError(state, format("Illegal {} = {}.", cAlphaFields(5), airTerm.ReheatComp));
     710            0 :             ShowContinueError(state, format("Occurs in {} = {}", airTerm.sysType, airTerm.SysName));
     711            0 :             ErrorsFound = true;
     712              :         }
     713            5 :         airTerm.ReheatName = Alphas(6);
     714            5 :         if (airTerm.ReheatComp_Num == HeatingCoilType::Gas || airTerm.ReheatComp_Num == HeatingCoilType::Electric) {
     715            5 :             HeatingCoils::GetCoilIndex(state, airTerm.ReheatName, airTerm.ReheatComp_Index, ErrorsFound);
     716            5 :             if (airTerm.ReheatComp_Index == 0) {
     717            0 :                 ShowSevereItemNotFound(state, eoh, cAlphaFields(6), Alphas(6));
     718            0 :                 ErrorsFound = true;
     719              :             }
     720            0 :         } else if (airTerm.ReheatComp_Num == HeatingCoilType::SimpleHeating) {
     721            0 :             airTerm.ReheatComp_Index = WaterCoils::GetWaterCoilIndex(state, airTerm.ReheatComp, airTerm.ReheatName, ErrorsFound);
     722            0 :             if (airTerm.ReheatComp_Index == 0) {
     723            0 :                 ShowSevereItemNotFound(state, eoh, cAlphaFields(6), Alphas(6));
     724            0 :                 ErrorsFound = true;
     725              :             }
     726            0 :         } else if (airTerm.ReheatComp_Num == HeatingCoilType::SteamAirHeating) {
     727            0 :             airTerm.ReheatComp_Index = SteamCoils::GetSteamCoilIndex(state, airTerm.ReheatComp, airTerm.ReheatName, ErrorsFound);
     728            0 :             if (airTerm.ReheatComp_Index == 0) {
     729            0 :                 ShowSevereItemNotFound(state, eoh, cAlphaFields(6), Alphas(6));
     730            0 :                 ErrorsFound = true;
     731              :             }
     732              :         }
     733              : 
     734            5 :         if (lAlphaBlanks(2)) {
     735            3 :             airTerm.availSched = Sched::GetScheduleAlwaysOn(state);
     736            2 :         } else if ((airTerm.availSched = Sched::GetSchedule(state, Alphas(2))) == nullptr) {
     737            0 :             ShowSevereItemNotFound(state, eoh, cAlphaFields(2), Alphas(2));
     738            0 :             ErrorsFound = true;
     739              :         }
     740              :         // For node connections, this object is both a parent and a non-parent, because the
     741              :         // VAV damper is not called out as a separate component, its nodes must be connected
     742              :         // as ObjectIsNotParent.  But for the reheat coil, the nodes are connected as ObjectIsParent
     743           15 :         airTerm.OutletNodeNum = GetOnlySingleNode(state,
     744            5 :                                                   Alphas(3),
     745              :                                                   ErrorsFound,
     746              :                                                   DataLoopNode::ConnectionObjectType::AirTerminalSingleDuctVAVHeatAndCoolReheat,
     747            5 :                                                   Alphas(1),
     748              :                                                   DataLoopNode::NodeFluidType::Air,
     749              :                                                   DataLoopNode::ConnectionType::Outlet,
     750              :                                                   NodeInputManager::CompFluidStream::Primary,
     751              :                                                   ObjectIsNotParent,
     752            5 :                                                   cAlphaFields(3));
     753           15 :         airTerm.InletNodeNum = GetOnlySingleNode(state,
     754            5 :                                                  Alphas(4),
     755              :                                                  ErrorsFound,
     756              :                                                  DataLoopNode::ConnectionObjectType::AirTerminalSingleDuctVAVHeatAndCoolReheat,
     757            5 :                                                  Alphas(1),
     758              :                                                  DataLoopNode::NodeFluidType::Air,
     759              :                                                  DataLoopNode::ConnectionType::Inlet,
     760              :                                                  NodeInputManager::CompFluidStream::Primary,
     761              :                                                  ObjectIsNotParent,
     762            5 :                                                  cAlphaFields(4));
     763            5 :         airTerm.MaxAirVolFlowRate = Numbers(1);
     764            5 :         airTerm.ZoneMinAirFracDes = Numbers(2);
     765            5 :         if (airTerm.ZoneMinAirFracDes < 0.0) {
     766            0 :             ShowWarningError(state, format("{} \"{}\"", airTerm.sysType, airTerm.SysName));
     767            0 :             ShowContinueError(state,
     768            0 :                               format("{} must be greater than or equal to 0. Resetting to 0 and the simulation continues.", cNumericFields(2)));
     769            0 :             airTerm.ZoneMinAirFracDes = 0.0;
     770              :         }
     771            5 :         if (airTerm.ZoneMinAirFracDes > 1.0) {
     772            0 :             ShowWarningError(state, format("{} \"{}\"", airTerm.sysType, airTerm.SysName));
     773            0 :             ShowContinueError(state, format("{} must be less than or equal to 1. Resetting to 1 and the simulation continues.", cNumericFields(2)));
     774            0 :             airTerm.ZoneMinAirFracDes = 1.0;
     775              :         }
     776              :         // The reheat coil control node is necessary for hot water and steam reheat, but not necessary for
     777              :         // electric or gas reheat.
     778            5 :         if (airTerm.ReheatComp_Num == HeatingCoilType::Gas || airTerm.ReheatComp_Num == HeatingCoilType::Electric) {
     779              :         } else {
     780            0 :             if (airTerm.ReheatComp_Num == HeatingCoilType::SteamAirHeating) {
     781            0 :                 IsNotOK = false;
     782            0 :                 airTerm.ReheatControlNode = GetCoilSteamInletNode(state, airTerm.ReheatComp, airTerm.ReheatName, IsNotOK);
     783            0 :                 if (IsNotOK) {
     784            0 :                     ShowContinueError(state, format("..Occurs in {} = {}", airTerm.sysType, airTerm.SysName));
     785            0 :                     ErrorsFound = true;
     786              :                 }
     787              :             } else {
     788            0 :                 IsNotOK = false;
     789            0 :                 airTerm.ReheatControlNode = GetCoilWaterInletNode(state, airTerm.ReheatComp, airTerm.ReheatName, IsNotOK);
     790            0 :                 if (IsNotOK) {
     791            0 :                     ShowContinueError(state, format("..Occurs in {} = {}", airTerm.sysType, airTerm.SysName));
     792            0 :                     ErrorsFound = true;
     793              :                 }
     794              :             }
     795              :             //  END IF
     796              :         }
     797           15 :         airTerm.ReheatAirOutletNode = GetOnlySingleNode(state,
     798            5 :                                                         Alphas(7),
     799              :                                                         ErrorsFound,
     800              :                                                         DataLoopNode::ConnectionObjectType::AirTerminalSingleDuctVAVHeatAndCoolReheat,
     801            5 :                                                         Alphas(1),
     802              :                                                         DataLoopNode::NodeFluidType::Air,
     803              :                                                         DataLoopNode::ConnectionType::Outlet,
     804              :                                                         NodeInputManager::CompFluidStream::Primary,
     805              :                                                         ObjectIsParent,
     806            5 :                                                         cAlphaFields(7));
     807            5 :         if (airTerm.ReheatComp_Num == HeatingCoilType::SteamAirHeating) {
     808            0 :             airTerm.MaxReheatSteamVolFlow = Numbers(3);
     809            0 :             airTerm.MinReheatSteamVolFlow = Numbers(4);
     810              :         } else {
     811            5 :             airTerm.MaxReheatWaterVolFlow = Numbers(3);
     812            5 :             airTerm.MinReheatWaterVolFlow = Numbers(4);
     813              :         }
     814            5 :         airTerm.ControllerOffset = Numbers(5);
     815              :         // Set default convergence tolerance
     816            5 :         if (airTerm.ControllerOffset <= 0.0) {
     817            0 :             airTerm.ControllerOffset = 0.001;
     818              :         }
     819              : 
     820            5 :         airTerm.DamperHeatingAction = Action::Reverse;
     821              : 
     822              :         // Register component set data
     823           10 :         TestCompSet(state,
     824              :                     airTerm.sysType,
     825              :                     airTerm.SysName,
     826            5 :                     state.dataLoopNodes->NodeID(airTerm.InletNodeNum),
     827            5 :                     state.dataLoopNodes->NodeID(airTerm.ReheatAirOutletNode),
     828              :                     "Air Nodes");
     829              : 
     830            6 :         for (ADUNum = 1; ADUNum <= (int)state.dataDefineEquipment->AirDistUnit.size(); ++ADUNum) {
     831            6 :             if (airTerm.ReheatAirOutletNode == state.dataDefineEquipment->AirDistUnit(ADUNum).OutletNodeNum) {
     832            5 :                 state.dataDefineEquipment->AirDistUnit(ADUNum).InletNodeNum = airTerm.InletNodeNum;
     833            5 :                 airTerm.ADUNum = ADUNum;
     834            5 :                 break;
     835              :             }
     836              :         }
     837              :         // one assumes if there isn't one assigned, it's an error?
     838            5 :         if (airTerm.ADUNum == 0) {
     839            0 :             ShowSevereError(state,
     840            0 :                             format("{}No matching Air Distribution Unit, for System = [{},{}].", RoutineName, airTerm.sysType, airTerm.SysName));
     841            0 :             ShowContinueError(state, format("...should have outlet node = {}", state.dataLoopNodes->NodeID(airTerm.ReheatAirOutletNode)));
     842            0 :             ErrorsFound = true;
     843              :         } else {
     844              : 
     845              :             // Fill the Zone Equipment data with the inlet node number of this unit
     846            9 :             for (CtrlZone = 1; CtrlZone <= state.dataGlobal->NumOfZones; ++CtrlZone) {
     847            4 :                 if (!state.dataZoneEquip->ZoneEquipConfig(CtrlZone).IsControlled) {
     848            0 :                     continue;
     849              :                 }
     850            8 :                 for (SupAirIn = 1; SupAirIn <= state.dataZoneEquip->ZoneEquipConfig(CtrlZone).NumInletNodes; ++SupAirIn) {
     851            4 :                     if (airTerm.ReheatAirOutletNode == state.dataZoneEquip->ZoneEquipConfig(CtrlZone).InletNode(SupAirIn)) {
     852            3 :                         if (state.dataZoneEquip->ZoneEquipConfig(CtrlZone).AirDistUnitCool(SupAirIn).OutNode > 0) {
     853            0 :                             ShowSevereError(state, "Error in connecting a terminal unit to a zone");
     854            0 :                             ShowContinueError(
     855            0 :                                 state, format("{} already connects to another zone", state.dataLoopNodes->NodeID(airTerm.ReheatAirOutletNode)));
     856            0 :                             ShowContinueError(state, format("Occurs for terminal unit {} = {}", airTerm.sysType, airTerm.SysName));
     857            0 :                             ShowContinueError(state, "Check terminal unit node names for errors");
     858            0 :                             ErrorsFound = true;
     859              :                         } else {
     860            3 :                             state.dataZoneEquip->ZoneEquipConfig(CtrlZone).AirDistUnitCool(SupAirIn).InNode = airTerm.InletNodeNum;
     861            3 :                             state.dataZoneEquip->ZoneEquipConfig(CtrlZone).AirDistUnitCool(SupAirIn).OutNode = airTerm.ReheatAirOutletNode;
     862            3 :                             state.dataDefineEquipment->AirDistUnit(airTerm.ADUNum).TermUnitSizingNum =
     863            3 :                                 state.dataZoneEquip->ZoneEquipConfig(CtrlZone).AirDistUnitCool(SupAirIn).TermUnitSizingIndex;
     864            3 :                             state.dataDefineEquipment->AirDistUnit(airTerm.ADUNum).ZoneEqNum = CtrlZone;
     865              :                         }
     866            3 :                         airTerm.CtrlZoneNum = CtrlZone;
     867            3 :                         airTerm.CtrlZoneInNodeIndex = SupAirIn;
     868            3 :                         airTerm.ZoneFloorArea = state.dataHeatBal->Zone(CtrlZone).FloorArea * state.dataHeatBal->Zone(CtrlZone).Multiplier *
     869            3 :                                                 state.dataHeatBal->Zone(CtrlZone).ListMultiplier;
     870              :                     }
     871              :                 }
     872              :             }
     873              :         }
     874            5 :         if (!lNumericBlanks(6)) {
     875            4 :             airTerm.MaxReheatTemp = Numbers(6);
     876            4 :             airTerm.MaxReheatTempSetByUser = true;
     877              :         } else {
     878              :             // user does not specify maximum supply air temperature
     879              :             // sd_airterminal(SysNum)%MaxReheatTemp = 35.0D0 !C
     880            1 :             airTerm.MaxReheatTempSetByUser = false;
     881              :         }
     882              : 
     883            5 :         ValidateComponent(state, Alphas(5), Alphas(6), IsNotOK, airTerm.sysType);
     884            5 :         if (IsNotOK) {
     885            0 :             ShowContinueError(state, format("In {} = {}", airTerm.sysType, airTerm.SysName));
     886            0 :             ErrorsFound = true;
     887              :         }
     888              : 
     889            5 :         if (lAlphaBlanks(8)) {
     890            3 :             airTerm.ZoneTurndownMinAirFrac = 1.0;
     891            2 :         } else if ((airTerm.zoneTurndownMinAirFracSched = Sched::GetSchedule(state, Alphas(8))) == nullptr) {
     892            0 :             ShowSevereItemNotFound(state, eoh, cAlphaFields(8), Alphas(8));
     893            0 :             ErrorsFound = true;
     894              :         }
     895              : 
     896              :         // Add reheat coil to component sets array
     897            5 :         SetUpCompSets(state, airTerm.sysType, airTerm.SysName, Alphas(5), Alphas(6), Alphas(3), Alphas(7));
     898              : 
     899              :         // Setup the Average damper Position output variable
     900           10 :         SetupOutputVariable(state,
     901              :                             "Zone Air Terminal VAV Damper Position",
     902              :                             Constant::Units::None,
     903            5 :                             airTerm.DamperPosition,
     904              :                             OutputProcessor::TimeStepType::System,
     905              :                             OutputProcessor::StoreType::Average,
     906            5 :                             airTerm.SysName);
     907              : 
     908              :     } // end Number of VAVHeatandCool Sys Loop
     909              : 
     910           72 :     CurrentModuleObject = "AirTerminal:SingleDuct:ConstantVolume:Reheat";
     911              : 
     912           75 :     for (state.dataSingleDuct->SysIndexGSI = 1; state.dataSingleDuct->SysIndexGSI <= state.dataSingleDuct->NumConstVolSys;
     913            3 :          ++state.dataSingleDuct->SysIndexGSI) {
     914              : 
     915            6 :         state.dataInputProcessing->inputProcessor->getObjectItem(state,
     916              :                                                                  CurrentModuleObject,
     917            3 :                                                                  state.dataSingleDuct->SysIndexGSI,
     918              :                                                                  Alphas,
     919            3 :                                                                  state.dataSingleDuct->NumAlphasGSI,
     920              :                                                                  Numbers,
     921            3 :                                                                  state.dataSingleDuct->NumNumsGSI,
     922              :                                                                  IOStat,
     923              :                                                                  lNumericBlanks,
     924              :                                                                  lAlphaBlanks,
     925              :                                                                  cAlphaFields,
     926              :                                                                  cNumericFields);
     927              : 
     928            3 :         ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)};
     929              : 
     930            6 :         state.dataSingleDuct->SysNumGSI =
     931            3 :             state.dataSingleDuct->SysIndexGSI + state.dataSingleDuct->NumVAVSysGSI + state.dataSingleDuct->NumCBVAVSysGSI;
     932            3 :         auto &airTerm = state.dataSingleDuct->sd_airterminal(state.dataSingleDuct->SysNumGSI);
     933              : 
     934            3 :         airTerm.SysNum = state.dataSingleDuct->SysNumGSI;
     935            3 :         GlobalNames::VerifyUniqueInterObjectName(
     936            6 :             state, state.dataSingleDuct->SysUniqueNames, Alphas(1), CurrentModuleObject, cAlphaFields(1), ErrorsFound);
     937            3 :         airTerm.SysName = Alphas(1);
     938            3 :         airTerm.sysType = CurrentModuleObject;
     939            3 :         airTerm.SysType_Num = SysType::SingleDuctConstVolReheat;
     940            3 :         airTerm.ReheatComp = Alphas(5);
     941            3 :         if (Util::SameString(airTerm.ReheatComp, "Coil:Heating:Fuel")) {
     942            0 :             airTerm.ReheatComp_Num = HeatingCoilType::Gas;
     943            3 :         } else if (Util::SameString(airTerm.ReheatComp, "Coil:Heating:Electric")) {
     944            1 :             airTerm.ReheatComp_Num = HeatingCoilType::Electric;
     945            2 :         } else if (Util::SameString(airTerm.ReheatComp, "Coil:Heating:Water")) {
     946            2 :             airTerm.ReheatComp_Num = HeatingCoilType::SimpleHeating;
     947            2 :             airTerm.ReheatComp_PlantType = DataPlant::PlantEquipmentType::CoilWaterSimpleHeating;
     948            0 :         } else if (Util::SameString(airTerm.ReheatComp, "Coil:Heating:Steam")) {
     949            0 :             airTerm.ReheatComp_Num = HeatingCoilType::SteamAirHeating;
     950            0 :             airTerm.ReheatComp_PlantType = DataPlant::PlantEquipmentType::CoilSteamAirHeating;
     951              :         } else {
     952            0 :             ShowSevereError(state, format("Illegal {} = {}.", cAlphaFields(5), airTerm.ReheatComp));
     953            0 :             ShowContinueError(state, format("Occurs in {} = {}", airTerm.sysType, airTerm.SysName));
     954            0 :             ErrorsFound = true;
     955              :         }
     956            3 :         airTerm.ReheatName = Alphas(6);
     957            3 :         if (airTerm.ReheatComp_Num == HeatingCoilType::Gas || airTerm.ReheatComp_Num == HeatingCoilType::Electric) {
     958            1 :             HeatingCoils::GetCoilIndex(state, airTerm.ReheatName, airTerm.ReheatComp_Index, ErrorsFound);
     959            1 :             if (airTerm.ReheatComp_Index == 0) {
     960            0 :                 ShowSevereItemNotFound(state, eoh, cAlphaFields(6), Alphas(6));
     961            0 :                 ErrorsFound = true;
     962              :             }
     963            2 :         } else if (airTerm.ReheatComp_Num == HeatingCoilType::SimpleHeating) {
     964            2 :             airTerm.ReheatComp_Index = WaterCoils::GetWaterCoilIndex(state, airTerm.ReheatComp, airTerm.ReheatName, ErrorsFound);
     965            2 :             if (airTerm.ReheatComp_Index == 0) {
     966            0 :                 ShowSevereItemNotFound(state, eoh, cAlphaFields(6), Alphas(6));
     967            0 :                 ErrorsFound = true;
     968              :             }
     969            0 :         } else if (airTerm.ReheatComp_Num == HeatingCoilType::SteamAirHeating) {
     970            0 :             airTerm.ReheatComp_Index = SteamCoils::GetSteamCoilIndex(state, airTerm.ReheatComp, airTerm.ReheatName, ErrorsFound);
     971            0 :             if (airTerm.ReheatComp_Index == 0) {
     972            0 :                 ShowSevereItemNotFound(state, eoh, cAlphaFields(6), Alphas(6));
     973            0 :                 ErrorsFound = true;
     974              :             }
     975              :         }
     976              : 
     977            3 :         if (lAlphaBlanks(2)) {
     978            1 :             airTerm.availSched = Sched::GetScheduleAlwaysOn(state);
     979            2 :         } else if ((airTerm.availSched = Sched::GetSchedule(state, Alphas(2))) == nullptr) {
     980            0 :             ShowSevereItemNotFound(state, eoh, cAlphaFields(2), Alphas(2));
     981            0 :             ErrorsFound = true;
     982              :         }
     983              : 
     984            9 :         airTerm.OutletNodeNum = GetOnlySingleNode(state,
     985            3 :                                                   Alphas(3),
     986              :                                                   ErrorsFound,
     987              :                                                   DataLoopNode::ConnectionObjectType::AirTerminalSingleDuctConstantVolumeReheat,
     988            3 :                                                   Alphas(1),
     989              :                                                   DataLoopNode::NodeFluidType::Air,
     990              :                                                   DataLoopNode::ConnectionType::Outlet,
     991              :                                                   NodeInputManager::CompFluidStream::Primary,
     992              :                                                   ObjectIsParent,
     993            3 :                                                   cAlphaFields(3));
     994            9 :         airTerm.InletNodeNum = GetOnlySingleNode(state,
     995            3 :                                                  Alphas(4),
     996              :                                                  ErrorsFound,
     997              :                                                  DataLoopNode::ConnectionObjectType::AirTerminalSingleDuctConstantVolumeReheat,
     998            3 :                                                  Alphas(1),
     999              :                                                  DataLoopNode::NodeFluidType::Air,
    1000              :                                                  DataLoopNode::ConnectionType::Inlet,
    1001              :                                                  NodeInputManager::CompFluidStream::Primary,
    1002              :                                                  ObjectIsParent,
    1003            3 :                                                  cAlphaFields(4));
    1004              :         // The reheat coil control node is necessary for hot water reheat, but not necessary for
    1005              :         // electric or gas reheat.
    1006            3 :         if (airTerm.ReheatComp_Num == HeatingCoilType::Gas || airTerm.ReheatComp_Num == HeatingCoilType::Electric) {
    1007              :         } else {
    1008            2 :             if (airTerm.ReheatComp_Num == HeatingCoilType::SteamAirHeating) {
    1009            0 :                 IsNotOK = false;
    1010            0 :                 airTerm.ReheatControlNode = GetCoilSteamInletNode(state, airTerm.ReheatComp, airTerm.ReheatName, IsNotOK);
    1011            0 :                 if (IsNotOK) {
    1012            0 :                     ShowContinueError(state, format("..Occurs in {} = {}", airTerm.sysType, airTerm.SysName));
    1013            0 :                     ErrorsFound = true;
    1014              :                 }
    1015              :             } else {
    1016            2 :                 IsNotOK = false;
    1017            2 :                 airTerm.ReheatControlNode = GetCoilWaterInletNode(state, airTerm.ReheatComp, airTerm.ReheatName, IsNotOK);
    1018            2 :                 if (IsNotOK) {
    1019            0 :                     ShowContinueError(state, format("..Occurs in {} = {}", airTerm.sysType, airTerm.SysName));
    1020            0 :                     ErrorsFound = true;
    1021              :                 }
    1022              :             }
    1023              :         }
    1024            3 :         airTerm.ReheatAirOutletNode = airTerm.OutletNodeNum;
    1025            3 :         airTerm.MaxAirVolFlowRate = Numbers(1);
    1026            3 :         airTerm.ZoneMinAirFracDes = 0.0;
    1027            3 :         airTerm.ZoneMinAirFracMethod = MinFlowFraction::MinFracNotUsed;
    1028            3 :         airTerm.DamperHeatingAction = Action::HeatingNotUsed;
    1029            3 :         if (airTerm.ReheatComp_Num == HeatingCoilType::SteamAirHeating) {
    1030            0 :             airTerm.MaxReheatSteamVolFlow = Numbers(2);
    1031            0 :             airTerm.MinReheatSteamVolFlow = Numbers(3);
    1032              :         } else {
    1033            3 :             airTerm.MaxReheatWaterVolFlow = Numbers(2);
    1034            3 :             airTerm.MinReheatWaterVolFlow = Numbers(3);
    1035              :         }
    1036            3 :         airTerm.ControllerOffset = Numbers(4);
    1037              :         // Set default convergence tolerance
    1038            3 :         if (airTerm.ControllerOffset <= 0.0) {
    1039            0 :             airTerm.ControllerOffset = 0.001;
    1040              :         }
    1041              : 
    1042              :         // Maximum reheat air temperature, i.e. the maximum supply air temperature leaving the reheat coil
    1043            3 :         if (!lNumericBlanks(5)) {
    1044            0 :             airTerm.MaxReheatTemp = Numbers(5);
    1045            0 :             airTerm.MaxReheatTempSetByUser = true;
    1046              :         } else {
    1047              :             // user does not specify maximum supply air temperature
    1048              :             // sd_airterminal(SysNum)%MaxReheatTemp = 35.0D0 !C
    1049            3 :             airTerm.MaxReheatTempSetByUser = false;
    1050              :         }
    1051              :         // Register component set data
    1052            6 :         TestCompSet(state,
    1053              :                     airTerm.sysType,
    1054              :                     airTerm.SysName,
    1055            3 :                     state.dataLoopNodes->NodeID(airTerm.InletNodeNum),
    1056            3 :                     state.dataLoopNodes->NodeID(airTerm.OutletNodeNum),
    1057              :                     "Air Nodes");
    1058              : 
    1059            3 :         for (ADUNum = 1; ADUNum <= (int)state.dataDefineEquipment->AirDistUnit.size(); ++ADUNum) {
    1060            3 :             if (airTerm.ReheatAirOutletNode == state.dataDefineEquipment->AirDistUnit(ADUNum).OutletNodeNum) {
    1061            3 :                 state.dataDefineEquipment->AirDistUnit(ADUNum).InletNodeNum = airTerm.InletNodeNum;
    1062            3 :                 airTerm.ADUNum = ADUNum;
    1063            3 :                 break;
    1064              :             }
    1065              :         }
    1066              :         // one assumes if there isn't one assigned, it's an error?
    1067            3 :         if (airTerm.ADUNum == 0) {
    1068            0 :             ShowSevereError(state,
    1069            0 :                             format("{}No matching Air Distribution Unit, for System = [{},{}].", RoutineName, airTerm.sysType, airTerm.SysName));
    1070            0 :             ShowContinueError(state, format("...should have outlet node = {}", state.dataLoopNodes->NodeID(airTerm.ReheatAirOutletNode)));
    1071            0 :             ErrorsFound = true;
    1072              :         } else {
    1073              : 
    1074              :             // Fill the Zone Equipment data with the inlet node number of this unit.
    1075            6 :             for (CtrlZone = 1; CtrlZone <= state.dataGlobal->NumOfZones; ++CtrlZone) {
    1076            3 :                 if (!state.dataZoneEquip->ZoneEquipConfig(CtrlZone).IsControlled) {
    1077            0 :                     continue;
    1078              :                 }
    1079            6 :                 for (SupAirIn = 1; SupAirIn <= state.dataZoneEquip->ZoneEquipConfig(CtrlZone).NumInletNodes; ++SupAirIn) {
    1080            3 :                     if (airTerm.OutletNodeNum == state.dataZoneEquip->ZoneEquipConfig(CtrlZone).InletNode(SupAirIn)) {
    1081            2 :                         if (state.dataZoneEquip->ZoneEquipConfig(CtrlZone).AirDistUnitCool(SupAirIn).OutNode > 0) {
    1082            0 :                             ShowSevereError(state, "Error in connecting a terminal unit to a zone");
    1083            0 :                             ShowContinueError(state,
    1084            0 :                                               format("{} already connects to another zone", state.dataLoopNodes->NodeID(airTerm.OutletNodeNum)));
    1085            0 :                             ShowContinueError(state, format("Occurs for terminal unit {} = {}", airTerm.sysType, airTerm.SysName));
    1086            0 :                             ShowContinueError(state, "Check terminal unit node names for errors");
    1087            0 :                             ErrorsFound = true;
    1088              :                         } else {
    1089            2 :                             state.dataZoneEquip->ZoneEquipConfig(CtrlZone).AirDistUnitCool(SupAirIn).InNode = airTerm.InletNodeNum;
    1090            2 :                             state.dataZoneEquip->ZoneEquipConfig(CtrlZone).AirDistUnitCool(SupAirIn).OutNode = airTerm.OutletNodeNum;
    1091            2 :                             state.dataDefineEquipment->AirDistUnit(airTerm.ADUNum).TermUnitSizingNum =
    1092            2 :                                 state.dataZoneEquip->ZoneEquipConfig(CtrlZone).AirDistUnitCool(SupAirIn).TermUnitSizingIndex;
    1093            2 :                             state.dataDefineEquipment->AirDistUnit(airTerm.ADUNum).ZoneEqNum = CtrlZone;
    1094              :                         }
    1095            2 :                         airTerm.CtrlZoneNum = CtrlZone;
    1096            2 :                         airTerm.CtrlZoneInNodeIndex = SupAirIn;
    1097            2 :                         airTerm.ZoneFloorArea = state.dataHeatBal->Zone(CtrlZone).FloorArea * state.dataHeatBal->Zone(CtrlZone).Multiplier *
    1098            2 :                                                 state.dataHeatBal->Zone(CtrlZone).ListMultiplier;
    1099              :                     }
    1100              :                 }
    1101              :             }
    1102              :         }
    1103              : 
    1104            3 :         ValidateComponent(state, Alphas(5), Alphas(6), IsNotOK, airTerm.sysType);
    1105            3 :         if (IsNotOK) {
    1106            0 :             ShowContinueError(state, format("In {} = {}", airTerm.sysType, airTerm.SysName));
    1107            0 :             ErrorsFound = true;
    1108              :         }
    1109              : 
    1110              :         // Add reheat coil to component sets array
    1111            3 :         SetUpCompSets(state, airTerm.sysType, airTerm.SysName, Alphas(5), Alphas(6), Alphas(4), Alphas(3));
    1112              : 
    1113              :         // Setup the Average damper Position output variable
    1114              :         // BG removed 9-10-2009 during work on CR 7770, constant volume has no damper
    1115              :         //  CALL SetupOutputVariable(state, 'Damper Position', Sys(SysNum)%DamperPosition, &
    1116              :         //                        'System','Average',Sys(SysNum)%SysName)
    1117              : 
    1118              :     } // End Number of Sys Loop
    1119              : 
    1120           72 :     CurrentModuleObject = "AirTerminal:SingleDuct:ConstantVolume:NoReheat";
    1121              : 
    1122           96 :     for (state.dataSingleDuct->SysIndexGSI = 1; state.dataSingleDuct->SysIndexGSI <= state.dataSingleDuct->NumCVNoReheatSysGSI;
    1123           24 :          ++state.dataSingleDuct->SysIndexGSI) {
    1124              : 
    1125           48 :         state.dataInputProcessing->inputProcessor->getObjectItem(state,
    1126              :                                                                  CurrentModuleObject,
    1127           24 :                                                                  state.dataSingleDuct->SysIndexGSI,
    1128              :                                                                  Alphas,
    1129           24 :                                                                  state.dataSingleDuct->NumAlphasGSI,
    1130              :                                                                  Numbers,
    1131           24 :                                                                  state.dataSingleDuct->NumNumsGSI,
    1132              :                                                                  IOStat,
    1133              :                                                                  lNumericBlanks,
    1134              :                                                                  lAlphaBlanks,
    1135              :                                                                  cAlphaFields,
    1136              :                                                                  cNumericFields);
    1137              : 
    1138           24 :         ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)};
    1139              : 
    1140           24 :         state.dataSingleDuct->SysNumGSI = state.dataSingleDuct->SysIndexGSI + state.dataSingleDuct->NumVAVSysGSI +
    1141           24 :                                           state.dataSingleDuct->NumCBVAVSysGSI + state.dataSingleDuct->NumConstVolSys;
    1142           24 :         auto &airTerm = state.dataSingleDuct->sd_airterminal(state.dataSingleDuct->SysNumGSI);
    1143              : 
    1144           24 :         airTerm.SysNum = state.dataSingleDuct->SysNumGSI;
    1145           24 :         GlobalNames::VerifyUniqueInterObjectName(
    1146           48 :             state, state.dataSingleDuct->SysUniqueNames, Alphas(1), CurrentModuleObject, cAlphaFields(1), ErrorsFound);
    1147           24 :         airTerm.SysName = Alphas(1);
    1148           24 :         airTerm.sysType = CurrentModuleObject;
    1149           24 :         airTerm.SysType_Num = SysType::SingleDuctConstVolNoReheat;
    1150              : 
    1151           24 :         if (lAlphaBlanks(2)) {
    1152            5 :             airTerm.availSched = Sched::GetScheduleAlwaysOn(state);
    1153           19 :         } else if ((airTerm.availSched = Sched::GetSchedule(state, Alphas(2))) == nullptr) {
    1154            0 :             ShowSevereItemNotFound(state, eoh, cAlphaFields(2), Alphas(2));
    1155            0 :             ErrorsFound = true;
    1156              :         }
    1157              : 
    1158           72 :         airTerm.InletNodeNum = GetOnlySingleNode(state,
    1159           24 :                                                  Alphas(3),
    1160              :                                                  ErrorsFound,
    1161              :                                                  DataLoopNode::ConnectionObjectType::AirTerminalSingleDuctConstantVolumeNoReheat,
    1162           24 :                                                  Alphas(1),
    1163              :                                                  DataLoopNode::NodeFluidType::Air,
    1164              :                                                  DataLoopNode::ConnectionType::Inlet,
    1165              :                                                  NodeInputManager::CompFluidStream::Primary,
    1166              :                                                  ObjectIsNotParent,
    1167           24 :                                                  cAlphaFields(3));
    1168           72 :         airTerm.OutletNodeNum = GetOnlySingleNode(state,
    1169           24 :                                                   Alphas(4),
    1170              :                                                   ErrorsFound,
    1171              :                                                   DataLoopNode::ConnectionObjectType::AirTerminalSingleDuctConstantVolumeNoReheat,
    1172           24 :                                                   Alphas(1),
    1173              :                                                   DataLoopNode::NodeFluidType::Air,
    1174              :                                                   DataLoopNode::ConnectionType::Outlet,
    1175              :                                                   NodeInputManager::CompFluidStream::Primary,
    1176              :                                                   ObjectIsNotParent,
    1177           24 :                                                   cAlphaFields(4));
    1178              : 
    1179           24 :         airTerm.MaxAirVolFlowRate = Numbers(1);
    1180           24 :         airTerm.ZoneMinAirFracDes = 0.0;
    1181           24 :         airTerm.ZoneMinAirFracMethod = MinFlowFraction::MinFracNotUsed;
    1182           24 :         airTerm.DamperHeatingAction = Action::HeatingNotUsed;
    1183              : 
    1184           24 :         airTerm.ReheatControlNode = 0;
    1185           24 :         airTerm.ReheatAirOutletNode = airTerm.OutletNodeNum;
    1186           24 :         airTerm.MaxReheatWaterVolFlow = 0.0;
    1187           24 :         airTerm.MaxReheatSteamVolFlow = 0.0;
    1188           24 :         airTerm.MinReheatWaterVolFlow = 0.0;
    1189           24 :         airTerm.MinReheatSteamVolFlow = 0.0;
    1190           24 :         airTerm.ControllerOffset = 0.000001;
    1191              : 
    1192              :         // Register component set data
    1193           48 :         TestCompSet(state,
    1194              :                     airTerm.sysType,
    1195              :                     airTerm.SysName,
    1196           24 :                     state.dataLoopNodes->NodeID(airTerm.InletNodeNum),
    1197           24 :                     state.dataLoopNodes->NodeID(airTerm.OutletNodeNum),
    1198              :                     "Air Nodes");
    1199              : 
    1200           27 :         for (ADUNum = 1; ADUNum <= (int)state.dataDefineEquipment->AirDistUnit.size(); ++ADUNum) {
    1201           27 :             if (airTerm.OutletNodeNum == state.dataDefineEquipment->AirDistUnit(ADUNum).OutletNodeNum) {
    1202           24 :                 state.dataDefineEquipment->AirDistUnit(ADUNum).InletNodeNum = airTerm.InletNodeNum;
    1203           24 :                 airTerm.ADUNum = ADUNum;
    1204           24 :                 break;
    1205              :             }
    1206              :         }
    1207              :         // one assumes if there isn't one assigned, it's an error?
    1208           24 :         if (airTerm.ADUNum == 0) {
    1209            0 :             ShowSevereError(state,
    1210            0 :                             format("{}No matching Air Distribution Unit, for System = [{},{}].", RoutineName, airTerm.sysType, airTerm.SysName));
    1211            0 :             ShowContinueError(state, format("...should have outlet node = {}", state.dataLoopNodes->NodeID(airTerm.OutletNodeNum)));
    1212            0 :             ErrorsFound = true;
    1213              :         } else {
    1214              : 
    1215              :             // Fill the Zone Equipment data with the inlet node number of this unit.
    1216           59 :             for (CtrlZone = 1; CtrlZone <= state.dataGlobal->NumOfZones; ++CtrlZone) {
    1217           35 :                 if (!state.dataZoneEquip->ZoneEquipConfig(CtrlZone).IsControlled) {
    1218            3 :                     continue;
    1219              :                 }
    1220           66 :                 for (SupAirIn = 1; SupAirIn <= state.dataZoneEquip->ZoneEquipConfig(CtrlZone).NumInletNodes; ++SupAirIn) {
    1221           34 :                     if (airTerm.OutletNodeNum == state.dataZoneEquip->ZoneEquipConfig(CtrlZone).InletNode(SupAirIn)) {
    1222           24 :                         if (state.dataZoneEquip->ZoneEquipConfig(CtrlZone).AirDistUnitCool(SupAirIn).OutNode > 0) {
    1223            0 :                             ShowSevereError(state, "Error in connecting a terminal unit to a zone");
    1224            0 :                             ShowContinueError(state,
    1225            0 :                                               format("{} already connects to another zone", state.dataLoopNodes->NodeID(airTerm.OutletNodeNum)));
    1226            0 :                             ShowContinueError(state, format("Occurs for terminal unit {} = {}", airTerm.sysType, airTerm.SysName));
    1227            0 :                             ShowContinueError(state, "Check terminal unit node names for errors");
    1228            0 :                             ErrorsFound = true;
    1229              :                         } else {
    1230           24 :                             state.dataZoneEquip->ZoneEquipConfig(CtrlZone).AirDistUnitCool(SupAirIn).InNode = airTerm.InletNodeNum;
    1231           24 :                             state.dataZoneEquip->ZoneEquipConfig(CtrlZone).AirDistUnitCool(SupAirIn).OutNode = airTerm.OutletNodeNum;
    1232           24 :                             state.dataDefineEquipment->AirDistUnit(airTerm.ADUNum).TermUnitSizingNum =
    1233           24 :                                 state.dataZoneEquip->ZoneEquipConfig(CtrlZone).AirDistUnitCool(SupAirIn).TermUnitSizingIndex;
    1234           24 :                             state.dataDefineEquipment->AirDistUnit(airTerm.ADUNum).ZoneEqNum = CtrlZone;
    1235              :                         }
    1236           24 :                         airTerm.CtrlZoneNum = CtrlZone;
    1237           24 :                         airTerm.CtrlZoneInNodeIndex = SupAirIn;
    1238           24 :                         airTerm.ZoneFloorArea = state.dataHeatBal->Zone(CtrlZone).FloorArea * state.dataHeatBal->Zone(CtrlZone).Multiplier *
    1239           24 :                                                 state.dataHeatBal->Zone(CtrlZone).ListMultiplier;
    1240              :                     }
    1241              :                 }
    1242              :             }
    1243              :         }
    1244              : 
    1245           24 :         if (lAlphaBlanks(5)) {
    1246           21 :             airTerm.NoOAFlowInputFromUser = true;
    1247              :         } else {
    1248            3 :             airTerm.OARequirementsPtr = Util::FindItemInList(Alphas(5), state.dataSize->OARequirements);
    1249            3 :             if (airTerm.OARequirementsPtr == 0) {
    1250            0 :                 ShowSevereError(state, format("{}{}=\"{}\", invalid data.", RoutineName, CurrentModuleObject, Alphas(1)));
    1251            0 :                 ShowContinueError(state, format("..invalid {}=\"{}\".", cAlphaFields(5), Alphas(5)));
    1252            0 :                 ErrorsFound = true;
    1253              :             } else {
    1254            3 :                 airTerm.NoOAFlowInputFromUser = false;
    1255              :             }
    1256              :         }
    1257              : 
    1258           24 :         if (lAlphaBlanks(6)) {
    1259           21 :             airTerm.OAPerPersonMode = DataZoneEquipment::PerPersonVentRateMode::DCVByCurrentLevel;
    1260              :         } else {
    1261            3 :             if (Alphas(6) == "CURRENTOCCUPANCY") {
    1262            3 :                 airTerm.OAPerPersonMode = DataZoneEquipment::PerPersonVentRateMode::DCVByCurrentLevel;
    1263            0 :             } else if (Alphas(6) == "DESIGNOCCUPANCY") {
    1264            0 :                 airTerm.OAPerPersonMode = DataZoneEquipment::PerPersonVentRateMode::ByDesignLevel;
    1265              :             } else {
    1266            0 :                 airTerm.OAPerPersonMode = DataZoneEquipment::PerPersonVentRateMode::DCVByCurrentLevel;
    1267            0 :                 ShowWarningError(state, format("{}{}=\"{}\", invalid data.", RoutineName, CurrentModuleObject, Alphas(1)));
    1268            0 :                 ShowContinueError(state,
    1269            0 :                                   format("..invalid {}=\"{}\". The default input of CurrentOccupancy is assigned", cAlphaFields(6), Alphas(6)));
    1270              :             }
    1271              :         }
    1272              : 
    1273           24 :         if (state.dataGlobal->AnyEnergyManagementSystemInModel) {
    1274              :             // model results related actuators
    1275            0 :             SetupEMSActuator(state,
    1276              :                              "AirTerminal:SingleDuct:ConstantVolume:NoReheat",
    1277              :                              airTerm.SysName,
    1278              :                              "Mass Flow Rate",
    1279              :                              "[kg/s]",
    1280            0 :                              airTerm.EMSOverrideAirFlow,
    1281            0 :                              airTerm.EMSMassFlowRateValue);
    1282              :             // model input related internal variables
    1283            0 :             SetupEMSInternalVariable(state,
    1284              :                                      "AirTerminal:SingleDuct:ConstantVolume:NoReheat Maximum Mass Flow Rate",
    1285              :                                      airTerm.SysName,
    1286              :                                      "[kg/s]",
    1287            0 :                                      airTerm.AirMassFlowRateMax);
    1288              :         }
    1289              : 
    1290              :     } // End Number of Sys Loop
    1291              : 
    1292          107 :     for (state.dataSingleDuct->SysIndexGSI = 1; state.dataSingleDuct->SysIndexGSI <= state.dataSingleDuct->NumNoRHVAVSysGSI;
    1293           35 :          ++state.dataSingleDuct->SysIndexGSI) {
    1294              : 
    1295           35 :         CurrentModuleObject = "AirTerminal:SingleDuct:VAV:NoReheat";
    1296              : 
    1297           70 :         state.dataInputProcessing->inputProcessor->getObjectItem(state,
    1298              :                                                                  CurrentModuleObject,
    1299           35 :                                                                  state.dataSingleDuct->SysIndexGSI,
    1300              :                                                                  Alphas,
    1301           35 :                                                                  state.dataSingleDuct->NumAlphasGSI,
    1302              :                                                                  Numbers,
    1303           35 :                                                                  state.dataSingleDuct->NumNumsGSI,
    1304              :                                                                  IOStat,
    1305              :                                                                  lNumericBlanks,
    1306              :                                                                  lAlphaBlanks,
    1307              :                                                                  cAlphaFields,
    1308              :                                                                  cNumericFields);
    1309              : 
    1310           35 :         ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)};
    1311           35 :         state.dataSingleDuct->SysNumGSI = state.dataSingleDuct->SysIndexGSI + state.dataSingleDuct->NumVAVSysGSI +
    1312           35 :                                           state.dataSingleDuct->NumCBVAVSysGSI + state.dataSingleDuct->NumConstVolSys +
    1313           35 :                                           state.dataSingleDuct->NumCVNoReheatSysGSI;
    1314           35 :         auto &airTerm = state.dataSingleDuct->sd_airterminal(state.dataSingleDuct->SysNumGSI);
    1315              : 
    1316           35 :         airTerm.SysNum = state.dataSingleDuct->SysNumGSI;
    1317           35 :         GlobalNames::VerifyUniqueInterObjectName(
    1318           70 :             state, state.dataSingleDuct->SysUniqueNames, Alphas(1), CurrentModuleObject, cAlphaFields(1), ErrorsFound);
    1319           35 :         airTerm.SysName = Alphas(1);
    1320           35 :         airTerm.sysType = CurrentModuleObject;
    1321           35 :         airTerm.SysType_Num = SysType::SingleDuctVAVNoReheat;
    1322           35 :         airTerm.ReheatComp = "";
    1323           35 :         airTerm.ReheatName = "";
    1324              : 
    1325           35 :         if (lAlphaBlanks(2)) {
    1326           15 :             airTerm.availSched = Sched::GetScheduleAlwaysOn(state);
    1327           20 :         } else if ((airTerm.availSched = Sched::GetSchedule(state, Alphas(2))) == nullptr) {
    1328            0 :             ShowSevereItemNotFound(state, eoh, cAlphaFields(2), Alphas(2));
    1329            0 :             ErrorsFound = true;
    1330              :         }
    1331              : 
    1332          105 :         airTerm.OutletNodeNum = GetOnlySingleNode(state,
    1333           35 :                                                   Alphas(3),
    1334              :                                                   ErrorsFound,
    1335              :                                                   DataLoopNode::ConnectionObjectType::AirTerminalSingleDuctVAVNoReheat,
    1336           35 :                                                   Alphas(1),
    1337              :                                                   DataLoopNode::NodeFluidType::Air,
    1338              :                                                   DataLoopNode::ConnectionType::Outlet,
    1339              :                                                   NodeInputManager::CompFluidStream::Primary,
    1340              :                                                   ObjectIsNotParent,
    1341           35 :                                                   cAlphaFields(3));
    1342          105 :         airTerm.InletNodeNum = GetOnlySingleNode(state,
    1343           35 :                                                  Alphas(4),
    1344              :                                                  ErrorsFound,
    1345              :                                                  DataLoopNode::ConnectionObjectType::AirTerminalSingleDuctVAVNoReheat,
    1346           35 :                                                  Alphas(1),
    1347              :                                                  DataLoopNode::NodeFluidType::Air,
    1348              :                                                  DataLoopNode::ConnectionType::Inlet,
    1349              :                                                  NodeInputManager::CompFluidStream::Primary,
    1350              :                                                  ObjectIsNotParent,
    1351           35 :                                                  cAlphaFields(4));
    1352           35 :         airTerm.MaxAirVolFlowRate = Numbers(1);
    1353              : 
    1354           35 :         if (Util::SameString(Alphas(5), "Constant")) {
    1355           33 :             airTerm.ZoneMinAirFracMethod = MinFlowFraction::Constant;
    1356            2 :         } else if (Util::SameString(Alphas(5), "FixedFlowRate")) {
    1357            2 :             airTerm.ZoneMinAirFracMethod = MinFlowFraction::Fixed;
    1358            0 :         } else if (Util::SameString(Alphas(5), "Scheduled")) {
    1359            0 :             airTerm.ZoneMinAirFracMethod = MinFlowFraction::Scheduled;
    1360              :         } else {
    1361            0 :             ShowSevereError(state, format("{} = {} not found.", cAlphaFields(5), Alphas(5)));
    1362            0 :             ShowContinueError(state, format("Occurs in {} = {}", airTerm.sysType, airTerm.SysName));
    1363            0 :             ErrorsFound = true;
    1364              :         }
    1365              : 
    1366           35 :         airTerm.ZoneMinAirFracDes = Numbers(2);
    1367           35 :         if (lNumericBlanks(2)) {
    1368            4 :             airTerm.ConstantMinAirFracSetByUser = false;
    1369            4 :             airTerm.ZoneMinAirFracDes = 0.0;
    1370              :         } else {
    1371           31 :             airTerm.ConstantMinAirFracSetByUser = true;
    1372           31 :             airTerm.ZoneMinAirFracDes = Numbers(2);
    1373           31 :             if (airTerm.ZoneMinAirFracMethod == MinFlowFraction::Fixed) {
    1374            0 :                 ShowWarningError(state, format("Since {} = {}, input for {} will be ignored.", cAlphaFields(5), Alphas(5), cNumericFields(2)));
    1375            0 :                 ShowContinueError(state, format("Occurs in {} = {}", airTerm.sysType, airTerm.SysName));
    1376            0 :                 airTerm.ZoneMinAirFracDes = 0.0;
    1377              :             }
    1378              :         }
    1379              : 
    1380           35 :         airTerm.ZoneFixedMinAir = Numbers(3);
    1381           35 :         if (lNumericBlanks(3)) {
    1382           30 :             airTerm.FixedMinAirSetByUser = false;
    1383           30 :             airTerm.DesignFixedMinAir = 0.0;
    1384              :         } else {
    1385            5 :             airTerm.FixedMinAirSetByUser = true;
    1386            5 :             airTerm.DesignFixedMinAir = Numbers(3);
    1387            5 :             if (airTerm.ZoneMinAirFracMethod == MinFlowFraction::Constant) {
    1388            3 :                 ShowWarningError(state, format("Since {} = {}, input for {} will be ignored.", cAlphaFields(5), Alphas(5), cNumericFields(3)));
    1389            3 :                 ShowContinueError(state, format("Occurs in {} = {}", airTerm.sysType, airTerm.SysName));
    1390            3 :                 airTerm.ZoneFixedMinAir = 0.0;
    1391              :             }
    1392              :         }
    1393              : 
    1394           35 :         if (airTerm.ZoneMinAirFracMethod != MinFlowFraction::Scheduled) {
    1395            0 :         } else if (lAlphaBlanks(6)) {
    1396            0 :             ShowSevereEmptyField(state, eoh, cAlphaFields(6));
    1397            0 :             ErrorsFound = true;
    1398            0 :         } else if ((airTerm.zoneMinAirFracSched = Sched::GetSchedule(state, Alphas(6))) == nullptr) {
    1399            0 :             ShowSevereItemNotFound(state, eoh, cAlphaFields(6), Alphas(6));
    1400            0 :             ErrorsFound = true;
    1401            0 :         } else if (!airTerm.zoneMinAirFracSched->checkMinMaxVals(state, Clusive::In, 0.0, Clusive::In, 1.0)) {
    1402            0 :             Sched::ShowSevereBadMinMax(state, eoh, cAlphaFields(6), Alphas(6), Clusive::In, 0.0, Clusive::In, 1.0);
    1403            0 :             ErrorsFound = true;
    1404              :         }
    1405              : 
    1406           35 :         airTerm.ReheatControlNode = 0;
    1407           35 :         airTerm.ReheatAirOutletNode = airTerm.OutletNodeNum;
    1408           35 :         airTerm.MaxReheatWaterVolFlow = 0.0;
    1409           35 :         airTerm.MaxReheatSteamVolFlow = 0.0;
    1410           35 :         airTerm.MinReheatWaterVolFlow = 0.0;
    1411           35 :         airTerm.MinReheatSteamVolFlow = 0.0;
    1412           35 :         airTerm.ControllerOffset = 0.000001;
    1413           35 :         airTerm.DamperHeatingAction = Action::HeatingNotUsed;
    1414              : 
    1415              :         // Register component set data
    1416           70 :         TestCompSet(state,
    1417              :                     airTerm.sysType,
    1418              :                     airTerm.SysName,
    1419           35 :                     state.dataLoopNodes->NodeID(airTerm.InletNodeNum),
    1420           35 :                     state.dataLoopNodes->NodeID(airTerm.OutletNodeNum),
    1421              :                     "Air Nodes");
    1422              : 
    1423           66 :         for (ADUNum = 1; ADUNum <= (int)state.dataDefineEquipment->AirDistUnit.size(); ++ADUNum) {
    1424           66 :             if (airTerm.OutletNodeNum == state.dataDefineEquipment->AirDistUnit(ADUNum).OutletNodeNum) {
    1425           35 :                 state.dataDefineEquipment->AirDistUnit(ADUNum).InletNodeNum = airTerm.InletNodeNum;
    1426           35 :                 airTerm.ADUNum = ADUNum;
    1427           35 :                 break;
    1428              :             }
    1429              :         }
    1430              :         // one assumes if there isn't one assigned, it's an error?
    1431           35 :         if (airTerm.ADUNum == 0) {
    1432            0 :             ShowSevereError(state,
    1433            0 :                             format("{}No matching Air Distribution Unit, for System = [{},{}].", RoutineName, airTerm.sysType, airTerm.SysName));
    1434            0 :             ShowContinueError(state, format("...should have outlet node = {}", state.dataLoopNodes->NodeID(airTerm.ReheatAirOutletNode)));
    1435            0 :             ErrorsFound = true;
    1436              :         } else {
    1437              : 
    1438              :             // Fill the Zone Equipment data with the inlet node number of this unit.
    1439          122 :             for (CtrlZone = 1; CtrlZone <= state.dataGlobal->NumOfZones; ++CtrlZone) {
    1440           87 :                 if (!state.dataZoneEquip->ZoneEquipConfig(CtrlZone).IsControlled) {
    1441            9 :                     continue;
    1442              :                 }
    1443          190 :                 for (SupAirIn = 1; SupAirIn <= state.dataZoneEquip->ZoneEquipConfig(CtrlZone).NumInletNodes; ++SupAirIn) {
    1444          112 :                     if (airTerm.ReheatAirOutletNode == state.dataZoneEquip->ZoneEquipConfig(CtrlZone).InletNode(SupAirIn)) {
    1445           34 :                         if (state.dataZoneEquip->ZoneEquipConfig(CtrlZone).AirDistUnitCool(SupAirIn).OutNode > 0) {
    1446            0 :                             ShowSevereError(state, "Error in connecting a terminal unit to a zone");
    1447            0 :                             ShowContinueError(
    1448            0 :                                 state, format("{} already connects to another zone", state.dataLoopNodes->NodeID(airTerm.ReheatAirOutletNode)));
    1449            0 :                             ShowContinueError(state, format("Occurs for terminal unit {} = {}", airTerm.sysType, airTerm.SysName));
    1450            0 :                             ShowContinueError(state, "Check terminal unit node names for errors");
    1451            0 :                             ErrorsFound = true;
    1452              :                         } else {
    1453           34 :                             state.dataZoneEquip->ZoneEquipConfig(CtrlZone).AirDistUnitCool(SupAirIn).InNode = airTerm.InletNodeNum;
    1454           34 :                             state.dataZoneEquip->ZoneEquipConfig(CtrlZone).AirDistUnitCool(SupAirIn).OutNode = airTerm.ReheatAirOutletNode;
    1455           34 :                             state.dataDefineEquipment->AirDistUnit(airTerm.ADUNum).TermUnitSizingNum =
    1456           34 :                                 state.dataZoneEquip->ZoneEquipConfig(CtrlZone).AirDistUnitCool(SupAirIn).TermUnitSizingIndex;
    1457           34 :                             state.dataDefineEquipment->AirDistUnit(airTerm.ADUNum).ZoneEqNum = CtrlZone;
    1458              :                         }
    1459              : 
    1460           34 :                         airTerm.CtrlZoneNum = CtrlZone;
    1461           34 :                         airTerm.CtrlZoneInNodeIndex = SupAirIn;
    1462           34 :                         airTerm.ZoneFloorArea = state.dataHeatBal->Zone(CtrlZone).FloorArea * state.dataHeatBal->Zone(CtrlZone).Multiplier *
    1463           34 :                                                 state.dataHeatBal->Zone(CtrlZone).ListMultiplier;
    1464              :                     }
    1465              :                 }
    1466              :             }
    1467              :         }
    1468           35 :         if (!lAlphaBlanks(7)) {
    1469            0 :             airTerm.OARequirementsPtr = Util::FindItemInList(Alphas(7), state.dataSize->OARequirements);
    1470            0 :             if (airTerm.OARequirementsPtr == 0) {
    1471            0 :                 ShowSevereError(state, format("{} = {} not found.", cAlphaFields(7), Alphas(7)));
    1472            0 :                 ShowContinueError(state, format("Occurs in {} = {}", airTerm.sysType, airTerm.SysName));
    1473            0 :                 ErrorsFound = true;
    1474              :             } else {
    1475            0 :                 airTerm.NoOAFlowInputFromUser = false;
    1476              :             }
    1477              :         }
    1478              : 
    1479           35 :         if (lAlphaBlanks(8)) {
    1480           34 :             airTerm.ZoneTurndownMinAirFrac = 1.0;
    1481            1 :         } else if ((airTerm.zoneTurndownMinAirFracSched = Sched::GetSchedule(state, Alphas(8))) == nullptr) {
    1482            0 :             ShowSevereItemNotFound(state, eoh, cAlphaFields(8), Alphas(8));
    1483            0 :             ErrorsFound = true;
    1484              :         }
    1485              : 
    1486              :         // Setup the Average damper Position output variable
    1487           70 :         SetupOutputVariable(state,
    1488              :                             "Zone Air Terminal VAV Damper Position",
    1489              :                             Constant::Units::None,
    1490           35 :                             airTerm.DamperPosition,
    1491              :                             OutputProcessor::TimeStepType::System,
    1492              :                             OutputProcessor::StoreType::Average,
    1493           35 :                             airTerm.SysName);
    1494           70 :         SetupOutputVariable(state,
    1495              :                             "Zone Air Terminal Minimum Air Flow Fraction",
    1496              :                             Constant::Units::None,
    1497           35 :                             airTerm.ZoneMinAirFracReport,
    1498              :                             OutputProcessor::TimeStepType::System,
    1499              :                             OutputProcessor::StoreType::Average,
    1500           35 :                             airTerm.SysName);
    1501              : 
    1502              :     } // end Number of Sys Loop
    1503              : 
    1504           74 :     for (state.dataSingleDuct->SysIndexGSI = 1; state.dataSingleDuct->SysIndexGSI <= state.dataSingleDuct->NumNoRHCBVAVSysGSI;
    1505            2 :          ++state.dataSingleDuct->SysIndexGSI) {
    1506              : 
    1507            2 :         CurrentModuleObject = "AirTerminal:SingleDuct:VAV:HeatAndCool:NoReheat";
    1508              : 
    1509            4 :         state.dataInputProcessing->inputProcessor->getObjectItem(state,
    1510              :                                                                  CurrentModuleObject,
    1511            2 :                                                                  state.dataSingleDuct->SysIndexGSI,
    1512              :                                                                  Alphas,
    1513            2 :                                                                  state.dataSingleDuct->NumAlphasGSI,
    1514              :                                                                  Numbers,
    1515            2 :                                                                  state.dataSingleDuct->NumNumsGSI,
    1516              :                                                                  IOStat,
    1517              :                                                                  lNumericBlanks,
    1518              :                                                                  lAlphaBlanks,
    1519              :                                                                  cAlphaFields,
    1520              :                                                                  cNumericFields);
    1521              : 
    1522            2 :         ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)};
    1523            2 :         state.dataSingleDuct->SysNumGSI = state.dataSingleDuct->SysIndexGSI + state.dataSingleDuct->NumVAVSysGSI +
    1524            2 :                                           state.dataSingleDuct->NumCBVAVSysGSI + state.dataSingleDuct->NumConstVolSys +
    1525            2 :                                           state.dataSingleDuct->NumCVNoReheatSysGSI + state.dataSingleDuct->NumNoRHVAVSysGSI;
    1526            2 :         auto &airTerm = state.dataSingleDuct->sd_airterminal(state.dataSingleDuct->SysNumGSI);
    1527              : 
    1528            2 :         airTerm.SysNum = state.dataSingleDuct->SysNumGSI;
    1529            2 :         GlobalNames::VerifyUniqueInterObjectName(
    1530            4 :             state, state.dataSingleDuct->SysUniqueNames, Alphas(1), CurrentModuleObject, cAlphaFields(1), ErrorsFound);
    1531            2 :         airTerm.SysName = Alphas(1);
    1532            2 :         airTerm.sysType = CurrentModuleObject;
    1533            2 :         airTerm.SysType_Num = SysType::SingleDuctCBVAVNoReheat;
    1534            2 :         airTerm.ReheatComp = "";
    1535            2 :         airTerm.ReheatName = "";
    1536              : 
    1537            2 :         if (lAlphaBlanks(2)) {
    1538            2 :             airTerm.availSched = Sched::GetScheduleAlwaysOn(state);
    1539            0 :         } else if ((airTerm.availSched = Sched::GetSchedule(state, Alphas(2))) == nullptr) {
    1540            0 :             ShowSevereItemNotFound(state, eoh, cAlphaFields(2), Alphas(2));
    1541            0 :             ErrorsFound = true;
    1542              :         }
    1543              : 
    1544            6 :         airTerm.OutletNodeNum = GetOnlySingleNode(state,
    1545            2 :                                                   Alphas(3),
    1546              :                                                   ErrorsFound,
    1547              :                                                   DataLoopNode::ConnectionObjectType::AirTerminalSingleDuctVAVHeatAndCoolNoReheat,
    1548            2 :                                                   Alphas(1),
    1549              :                                                   DataLoopNode::NodeFluidType::Air,
    1550              :                                                   DataLoopNode::ConnectionType::Outlet,
    1551              :                                                   NodeInputManager::CompFluidStream::Primary,
    1552              :                                                   ObjectIsNotParent,
    1553            2 :                                                   cAlphaFields(3));
    1554            6 :         airTerm.InletNodeNum = GetOnlySingleNode(state,
    1555            2 :                                                  Alphas(4),
    1556              :                                                  ErrorsFound,
    1557              :                                                  DataLoopNode::ConnectionObjectType::AirTerminalSingleDuctVAVHeatAndCoolNoReheat,
    1558            2 :                                                  Alphas(1),
    1559              :                                                  DataLoopNode::NodeFluidType::Air,
    1560              :                                                  DataLoopNode::ConnectionType::Inlet,
    1561              :                                                  NodeInputManager::CompFluidStream::Primary,
    1562              :                                                  ObjectIsNotParent,
    1563            2 :                                                  cAlphaFields(4));
    1564            2 :         airTerm.MaxAirVolFlowRate = Numbers(1);
    1565            2 :         airTerm.ZoneMinAirFracDes = Numbers(2);
    1566            2 :         if (airTerm.ZoneMinAirFracDes < 0.0) {
    1567            0 :             ShowWarningError(state, format("{} = \"{}", airTerm.sysType, airTerm.SysName));
    1568            0 :             ShowContinueError(state,
    1569            0 :                               format("{} must be greater than or equal to 0. Resetting to 0 and the simulation continues.", cNumericFields(2)));
    1570            0 :             airTerm.ZoneMinAirFracDes = 0.0;
    1571              :         }
    1572            2 :         if (airTerm.ZoneMinAirFracDes > 1.0) {
    1573            0 :             ShowWarningError(state, format("{} = \"{}", airTerm.sysType, airTerm.SysName));
    1574            0 :             ShowContinueError(state, format("{} must be less than or equal to 1. Resetting to 1 and the simulation continues.", cNumericFields(2)));
    1575            0 :             airTerm.ZoneMinAirFracDes = 1.0;
    1576              :         }
    1577              : 
    1578            2 :         airTerm.ReheatControlNode = 0;
    1579            2 :         airTerm.ReheatAirOutletNode = airTerm.OutletNodeNum;
    1580            2 :         airTerm.MaxReheatWaterVolFlow = 0.0;
    1581            2 :         airTerm.MaxReheatSteamVolFlow = 0.0;
    1582            2 :         airTerm.MinReheatWaterVolFlow = 0.0;
    1583            2 :         airTerm.MinReheatSteamVolFlow = 0.0;
    1584            2 :         airTerm.ControllerOffset = 0.000001;
    1585            2 :         airTerm.DamperHeatingAction = Action::HeatingNotUsed;
    1586              : 
    1587              :         // Register component set data
    1588            4 :         TestCompSet(state,
    1589              :                     airTerm.sysType,
    1590              :                     airTerm.SysName,
    1591            2 :                     state.dataLoopNodes->NodeID(airTerm.InletNodeNum),
    1592            2 :                     state.dataLoopNodes->NodeID(airTerm.OutletNodeNum),
    1593              :                     "Air Nodes");
    1594              : 
    1595            5 :         for (ADUNum = 1; ADUNum <= (int)state.dataDefineEquipment->AirDistUnit.size(); ++ADUNum) {
    1596            5 :             if (airTerm.OutletNodeNum == state.dataDefineEquipment->AirDistUnit(ADUNum).OutletNodeNum) {
    1597            2 :                 state.dataDefineEquipment->AirDistUnit(ADUNum).InletNodeNum = airTerm.InletNodeNum;
    1598            2 :                 airTerm.ADUNum = ADUNum;
    1599            2 :                 break;
    1600              :             }
    1601              :         }
    1602              :         // one assumes if there isn't one assigned, it's an error?
    1603            2 :         if (airTerm.ADUNum == 0) {
    1604            0 :             ShowSevereError(state,
    1605            0 :                             format("{}No matching Air Distribution Unit, for System = [{},{}].", RoutineName, airTerm.sysType, airTerm.SysName));
    1606            0 :             ShowContinueError(state, format("...should have outlet node = {}", state.dataLoopNodes->NodeID(airTerm.ReheatAirOutletNode)));
    1607            0 :             ErrorsFound = true;
    1608              :         } else {
    1609              : 
    1610              :             // Fill the Zone Equipment data with the inlet node number of this unit.
    1611            4 :             for (CtrlZone = 1; CtrlZone <= state.dataGlobal->NumOfZones; ++CtrlZone) {
    1612            2 :                 if (!state.dataZoneEquip->ZoneEquipConfig(CtrlZone).IsControlled) {
    1613            1 :                     continue;
    1614              :                 }
    1615            3 :                 for (SupAirIn = 1; SupAirIn <= state.dataZoneEquip->ZoneEquipConfig(CtrlZone).NumInletNodes; ++SupAirIn) {
    1616            2 :                     if (airTerm.ReheatAirOutletNode == state.dataZoneEquip->ZoneEquipConfig(CtrlZone).InletNode(SupAirIn)) {
    1617            1 :                         if (state.dataZoneEquip->ZoneEquipConfig(CtrlZone).AirDistUnitCool(SupAirIn).OutNode > 0) {
    1618            0 :                             ShowSevereError(state, "Error in connecting a terminal unit to a zone");
    1619            0 :                             ShowContinueError(
    1620            0 :                                 state, format("{} already connects to another zone", state.dataLoopNodes->NodeID(airTerm.ReheatAirOutletNode)));
    1621            0 :                             ShowContinueError(state, format("Occurs for terminal unit {} = {}", airTerm.sysType, airTerm.SysName));
    1622            0 :                             ShowContinueError(state, "Check terminal unit node names for errors");
    1623            0 :                             ErrorsFound = true;
    1624              :                         } else {
    1625            1 :                             state.dataZoneEquip->ZoneEquipConfig(CtrlZone).AirDistUnitCool(SupAirIn).InNode = airTerm.InletNodeNum;
    1626            1 :                             state.dataZoneEquip->ZoneEquipConfig(CtrlZone).AirDistUnitCool(SupAirIn).OutNode = airTerm.ReheatAirOutletNode;
    1627            1 :                             state.dataDefineEquipment->AirDistUnit(airTerm.ADUNum).TermUnitSizingNum =
    1628            1 :                                 state.dataZoneEquip->ZoneEquipConfig(CtrlZone).AirDistUnitCool(SupAirIn).TermUnitSizingIndex;
    1629            1 :                             state.dataDefineEquipment->AirDistUnit(airTerm.ADUNum).ZoneEqNum = CtrlZone;
    1630              :                         }
    1631            1 :                         airTerm.CtrlZoneNum = CtrlZone;
    1632            1 :                         airTerm.CtrlZoneInNodeIndex = SupAirIn;
    1633            1 :                         airTerm.ZoneFloorArea = state.dataHeatBal->Zone(CtrlZone).FloorArea * state.dataHeatBal->Zone(CtrlZone).Multiplier *
    1634            1 :                                                 state.dataHeatBal->Zone(CtrlZone).ListMultiplier;
    1635              :                     }
    1636              :                 }
    1637              :             }
    1638              :         }
    1639              : 
    1640            2 :         if (lAlphaBlanks(5)) {
    1641            1 :             airTerm.ZoneTurndownMinAirFrac = 1.0;
    1642            1 :         } else if ((airTerm.zoneTurndownMinAirFracSched = Sched::GetSchedule(state, Alphas(5))) == nullptr) {
    1643            0 :             ShowSevereItemNotFound(state, eoh, cAlphaFields(5), Alphas(5));
    1644            0 :             ErrorsFound = true;
    1645              :         }
    1646              : 
    1647              :         // Setup the Average damper Position output variable
    1648            4 :         SetupOutputVariable(state,
    1649              :                             "Zone Air Terminal VAV Damper Position",
    1650              :                             Constant::Units::None,
    1651            2 :                             airTerm.DamperPosition,
    1652              :                             OutputProcessor::TimeStepType::System,
    1653              :                             OutputProcessor::StoreType::Average,
    1654            2 :                             airTerm.SysName);
    1655              : 
    1656              :     } // end Number of VAVHeatandCool:NoReheat Sys Loop
    1657              : 
    1658              :     // read in the SINGLE DUCT:VAV:REHEAT:VS FAN data
    1659           76 :     for (state.dataSingleDuct->SysIndexGSI = 1; state.dataSingleDuct->SysIndexGSI <= state.dataSingleDuct->NumVAVVSGSI;
    1660            4 :          ++state.dataSingleDuct->SysIndexGSI) {
    1661              : 
    1662            4 :         CurrentModuleObject = "AirTerminal:SingleDuct:VAV:Reheat:VariableSpeedFan";
    1663              : 
    1664            8 :         state.dataInputProcessing->inputProcessor->getObjectItem(state,
    1665              :                                                                  CurrentModuleObject,
    1666            4 :                                                                  state.dataSingleDuct->SysIndexGSI,
    1667              :                                                                  Alphas,
    1668            4 :                                                                  state.dataSingleDuct->NumAlphasGSI,
    1669              :                                                                  Numbers,
    1670            4 :                                                                  state.dataSingleDuct->NumNumsGSI,
    1671              :                                                                  IOStat,
    1672              :                                                                  lNumericBlanks,
    1673              :                                                                  lAlphaBlanks,
    1674              :                                                                  cAlphaFields,
    1675              :                                                                  cNumericFields);
    1676              : 
    1677            4 :         ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)};
    1678              : 
    1679            4 :         state.dataSingleDuct->SysNumGSI = state.dataSingleDuct->SysIndexGSI + state.dataSingleDuct->NumVAVSysGSI +
    1680            4 :                                           state.dataSingleDuct->NumCBVAVSysGSI + state.dataSingleDuct->NumConstVolSys +
    1681            4 :                                           state.dataSingleDuct->NumCVNoReheatSysGSI + state.dataSingleDuct->NumNoRHVAVSysGSI +
    1682            4 :                                           state.dataSingleDuct->NumNoRHCBVAVSysGSI;
    1683            4 :         auto &airTerm = state.dataSingleDuct->sd_airterminal(state.dataSingleDuct->SysNumGSI);
    1684            4 :         airTerm.SysNum = state.dataSingleDuct->SysNumGSI;
    1685            4 :         GlobalNames::VerifyUniqueInterObjectName(
    1686            8 :             state, state.dataSingleDuct->SysUniqueNames, Alphas(1), CurrentModuleObject, cAlphaFields(1), ErrorsFound);
    1687            4 :         airTerm.SysName = Alphas(1);
    1688            4 :         airTerm.sysType = CurrentModuleObject;
    1689            4 :         airTerm.SysType_Num = SysType::SingleDuctVAVReheatVSFan;
    1690            4 :         airTerm.ReheatComp = Alphas(7);
    1691            4 :         airTerm.ReheatName = Alphas(8);
    1692            4 :         IsNotOK = false;
    1693            4 :         if (Util::SameString(airTerm.ReheatComp, "Coil:Heating:Fuel")) {
    1694            0 :             airTerm.ReheatComp_Num = HeatingCoilType::Gas;
    1695            0 :             airTerm.ReheatAirOutletNode = GetHeatingCoilOutletNode(state, airTerm.ReheatComp, airTerm.ReheatName, IsNotOK);
    1696            0 :             airTerm.ReheatCoilMaxCapacity = GetHeatingCoilCapacity(state, airTerm.ReheatComp, airTerm.ReheatName, IsNotOK);
    1697            0 :             if (IsNotOK) {
    1698            0 :                 ShowContinueError(state, format("Occurs for terminal unit {} = {}", airTerm.sysType, airTerm.SysName));
    1699              :             }
    1700            4 :         } else if (Util::SameString(airTerm.ReheatComp, "Coil:Heating:Electric")) {
    1701            3 :             airTerm.ReheatComp_Num = HeatingCoilType::Electric;
    1702            3 :             airTerm.ReheatAirOutletNode = GetHeatingCoilOutletNode(state, airTerm.ReheatComp, airTerm.ReheatName, IsNotOK);
    1703            3 :             airTerm.ReheatCoilMaxCapacity = GetHeatingCoilCapacity(state, airTerm.ReheatComp, airTerm.ReheatName, IsNotOK);
    1704            3 :             if (IsNotOK) {
    1705            0 :                 ShowContinueError(state, format("Occurs for terminal unit {} = {}", airTerm.sysType, airTerm.SysName));
    1706              :             }
    1707            1 :         } else if (Util::SameString(airTerm.ReheatComp, "Coil:Heating:Water")) {
    1708            1 :             airTerm.ReheatComp_Num = HeatingCoilType::SimpleHeating;
    1709            1 :             airTerm.ReheatComp_PlantType = DataPlant::PlantEquipmentType::CoilWaterSimpleHeating;
    1710            0 :         } else if (Util::SameString(airTerm.ReheatComp, "Coil:Heating:Steam")) {
    1711            0 :             airTerm.ReheatComp_Num = HeatingCoilType::SteamAirHeating;
    1712            0 :             airTerm.ReheatComp_PlantType = DataPlant::PlantEquipmentType::CoilSteamAirHeating;
    1713            0 :         } else if (!airTerm.ReheatComp.empty()) {
    1714            0 :             ShowSevereError(state, format("Illegal {} = {}.", cAlphaFields(7), airTerm.ReheatComp));
    1715            0 :             ShowContinueError(state, format("Occurs in {} = {}", airTerm.sysType, airTerm.SysName));
    1716            0 :             ErrorsFound = true;
    1717              :         }
    1718              : 
    1719            4 :         if (airTerm.ReheatComp_Num == HeatingCoilType::Gas || airTerm.ReheatComp_Num == HeatingCoilType::Electric) {
    1720            3 :             HeatingCoils::GetCoilIndex(state, airTerm.ReheatName, airTerm.ReheatComp_Index, ErrorsFound);
    1721            3 :             if (airTerm.ReheatComp_Index == 0) {
    1722            0 :                 ShowSevereItemNotFound(state, eoh, cAlphaFields(8), Alphas(8));
    1723            0 :                 ErrorsFound = true;
    1724              :             }
    1725            1 :         } else if (airTerm.ReheatComp_Num == HeatingCoilType::SimpleHeating) {
    1726            1 :             airTerm.ReheatComp_Index = WaterCoils::GetWaterCoilIndex(state, airTerm.ReheatComp, airTerm.ReheatName, ErrorsFound);
    1727            1 :             if (airTerm.ReheatComp_Index == 0) {
    1728            0 :                 ShowSevereItemNotFound(state, eoh, cAlphaFields(8), Alphas(8));
    1729            0 :                 ErrorsFound = true;
    1730              :             }
    1731            0 :         } else if (airTerm.ReheatComp_Num == HeatingCoilType::SteamAirHeating) {
    1732            0 :             airTerm.ReheatComp_Index = SteamCoils::GetSteamCoilIndex(state, airTerm.ReheatComp, airTerm.ReheatName, ErrorsFound);
    1733            0 :             if (airTerm.ReheatComp_Index == 0) {
    1734            0 :                 ShowSevereItemNotFound(state, eoh, cAlphaFields(8), Alphas(8));
    1735            0 :                 ErrorsFound = true;
    1736              :             }
    1737              :         }
    1738              : 
    1739            4 :         airTerm.fanType = static_cast<HVAC::FanType>(getEnumValue(HVAC::fanTypeNamesUC, Alphas(5)));
    1740              : 
    1741            4 :         if (airTerm.fanType != HVAC::FanType::VAV && airTerm.fanType != HVAC::FanType::SystemModel) {
    1742            0 :             ShowSevereInvalidKey(state, eoh, cAlphaFields(5), Alphas(5), "Support fan types are Fan:VAV and Fan:SystemModel");
    1743              : 
    1744            0 :             ErrorsFound = true;
    1745              :         }
    1746              : 
    1747            4 :         airTerm.FanName = Alphas(6);
    1748              : 
    1749            4 :         airTerm.Fan_Index = Fans::GetFanIndex(state, airTerm.FanName);
    1750            4 :         if (airTerm.Fan_Index == 0) {
    1751            0 :             ShowSevereItemNotFound(state, eoh, cAlphaFields(6), airTerm.FanName);
    1752            0 :             ErrorsFound = true;
    1753              :         }
    1754            4 :         airTerm.OutletNodeNum = state.dataFans->fans(airTerm.Fan_Index)->outletNodeNum;
    1755            4 :         airTerm.InletNodeNum = state.dataFans->fans(airTerm.Fan_Index)->inletNodeNum;
    1756              : 
    1757            4 :         if (airTerm.fanType == HVAC::FanType::SystemModel) {
    1758            3 :             dynamic_cast<Fans::FanSystem *>(state.dataFans->fans(airTerm.Fan_Index))->isSecondaryDriver = true;
    1759              :         }
    1760              : 
    1761            4 :         if (lAlphaBlanks(2)) {
    1762            3 :             airTerm.availSched = Sched::GetScheduleAlwaysOn(state);
    1763            1 :         } else if ((airTerm.availSched = Sched::GetSchedule(state, Alphas(2))) == nullptr) {
    1764            0 :             ShowSevereItemNotFound(state, eoh, cAlphaFields(2), Alphas(2));
    1765            0 :             ErrorsFound = true;
    1766              :         }
    1767              : 
    1768            4 :         AirTermSysInletNodeName = state.dataLoopNodes->NodeID(airTerm.InletNodeNum);
    1769            4 :         if (!Util::SameString(Alphas(3), AirTermSysInletNodeName)) {
    1770            2 :             ShowWarningError(state,
    1771            2 :                              format("{}Invalid air terminal object air inlet node name in {} = {}", RoutineName, airTerm.sysType, airTerm.SysName));
    1772            1 :             ShowContinueError(state, format(" Specified air inlet node name is = {}.", Alphas(3)));
    1773            1 :             ShowContinueError(state, format(" Expected air inlet node name is = {}.", AirTermSysInletNodeName));
    1774              :             // ErrorsFound = true;
    1775              :         }
    1776              : 
    1777            4 :         airTerm.MaxAirVolFlowRate = Numbers(1);
    1778            4 :         airTerm.MaxHeatAirVolFlowRate = Numbers(2);
    1779            4 :         airTerm.ZoneMinAirFracDes = Numbers(3);
    1780              :         // The reheat coil control node is necessary for hot water reheat, but not necessary for
    1781              :         // electric or gas reheat.
    1782            4 :         if (airTerm.ReheatComp_Num == HeatingCoilType::Gas || airTerm.ReheatComp_Num == HeatingCoilType::Electric) {
    1783              :             //          IF(.NOT. lAlphaBlanks(6)) THEN
    1784              :             //            CALL ShowWarningError(state, 'In '//TRIM(sd_airterminal(SysNum)%SysType)//' = ' // TRIM(sd_airterminal(SysNum)%SysName) &
    1785              :             //                                 // ' the '//TRIM(cAlphaFields(6))//' is not needed and will be ignored.')
    1786              :             //            CALL ShowContinueError(state, '  It is used for hot water reheat coils only.')
    1787              :             //          END IF
    1788              :         } else {
    1789              :             //          IF(lAlphaBlanks(6)) THEN
    1790              :             //            CALL ShowSevereError(state, 'In '//TRIM(sd_airterminal(SysNum)%SysType)//' = ' // TRIM(sd_airterminal(SysNum)%SysName) &
    1791              :             //                                 // ' the '//TRIM(cAlphaFields(6))//' is undefined')
    1792              :             //            ErrorsFound=.TRUE.
    1793              :             //          END IF
    1794            1 :             if (airTerm.ReheatComp_Num == HeatingCoilType::SteamAirHeating) {
    1795            0 :                 IsNotOK = false;
    1796            0 :                 airTerm.ReheatControlNode = GetCoilSteamInletNode(state, airTerm.ReheatComp, airTerm.ReheatName, IsNotOK);
    1797            0 :                 if (IsNotOK) {
    1798            0 :                     ShowContinueError(state, format("..Occurs in {} = {}", airTerm.sysType, airTerm.SysName));
    1799            0 :                     ErrorsFound = true;
    1800              :                 } else {
    1801              :                     //  A4,     \field Unit supply air outlet node
    1802              :                     //          \note same as heating coil air outlet node
    1803              :                     //          \note same as zone inlet node
    1804              :                     //          \type alpha
    1805            0 :                     IsNotOK = false;
    1806            0 :                     airTerm.ReheatAirOutletNode = GetCoilAirOutletNode(state, airTerm.ReheatComp, airTerm.ReheatName, IsNotOK);
    1807            0 :                     if (IsNotOK) {
    1808            0 :                         ShowContinueError(state, format("..Occurs in {} = {}", airTerm.sysType, airTerm.SysName));
    1809            0 :                         ErrorsFound = true;
    1810              :                     }
    1811              :                 }
    1812              :                 //               GetOnlySingleNode(state, Alphas(6),ErrorsFound,sd_airterminal(SysNum)%SysType,Alphas(1), &
    1813              :                 //                                DataLoopNode::NodeFluidType::Steam,DataLoopNode::NodeConnectionType::Actuator,1,ObjectIsParent)
    1814              :             } else {
    1815            1 :                 IsNotOK = false;
    1816            1 :                 airTerm.ReheatControlNode = GetCoilWaterInletNode(state, airTerm.ReheatComp, airTerm.ReheatName, IsNotOK);
    1817            1 :                 if (IsNotOK) {
    1818            0 :                     ShowContinueError(state, format("..Occurs in {} = {}", airTerm.sysType, airTerm.SysName));
    1819            0 :                     ErrorsFound = true;
    1820              :                 } else {
    1821              :                     //  A4,     \field Unit supply air outlet node
    1822              :                     //          \note same as heating coil air outlet node
    1823              :                     //          \note same as zone inlet node
    1824              :                     //          \type alpha
    1825            1 :                     IsNotOK = false;
    1826            1 :                     airTerm.ReheatAirOutletNode = GetCoilOutletNode(state, airTerm.ReheatComp, airTerm.ReheatName, IsNotOK);
    1827            1 :                     if (IsNotOK) {
    1828            0 :                         ShowContinueError(state, format("..Occurs in {} = {}", airTerm.sysType, airTerm.SysName));
    1829            0 :                         ErrorsFound = true;
    1830              :                     }
    1831              :                 }
    1832              :                 //               GetOnlySingleNode(state, Alphas(6),ErrorsFound,sd_airterminal(SysNum)%SysType,Alphas(1), &
    1833              :                 //                                DataLoopNode::NodeFluidType::Water,DataLoopNode::NodeConnectionType::Actuator,1,ObjectIsParent)
    1834              :             }
    1835              :         }
    1836              :         //  A4,     \field Unit supply air outlet node
    1837              :         //          \note same as heating coil air outlet node
    1838              :         //          \note same as zone inlet node
    1839              :         //          \type alpha
    1840              :         //        sd_airterminal(SysNum)%ReheatAirOutletNode  = &
    1841              :         //               GetOnlySingleNode(state, Alphas(4),ErrorsFound,sd_airterminal(SysNum)%SysType,Alphas(1), &
    1842              :         //                            DataLoopNode::NodeFluidType::Air,DataLoopNode::NodeConnectionType::Outlet,1,ObjectIsParent)
    1843            4 :         AirTermSysOutletNodeName = state.dataLoopNodes->NodeID(airTerm.ReheatAirOutletNode);
    1844            4 :         if (!Util::SameString(Alphas(4), AirTermSysOutletNodeName)) {
    1845            2 :             ShowWarningError(state,
    1846            2 :                              format("{}Invalid air terminal object air outlet node name in {} = {}", RoutineName, airTerm.sysType, airTerm.SysName));
    1847            1 :             ShowContinueError(state, format(" Specified air outlet node name is = {}.", Alphas(4)));
    1848            1 :             ShowContinueError(state, format(" Expected air outlet node name is = {}.", AirTermSysOutletNodeName));
    1849              :             // ErrorsFound = true;
    1850              :         }
    1851              : 
    1852            4 :         if (airTerm.ReheatComp_Num == HeatingCoilType::SteamAirHeating) {
    1853            0 :             airTerm.MaxReheatSteamVolFlow = Numbers(4);
    1854            0 :             airTerm.MinReheatSteamVolFlow = Numbers(5);
    1855              :         } else {
    1856            4 :             airTerm.MaxReheatWaterVolFlow = Numbers(4);
    1857            4 :             airTerm.MinReheatWaterVolFlow = Numbers(5);
    1858              :         }
    1859            4 :         airTerm.ControllerOffset = Numbers(6);
    1860              :         // Set default convergence tolerance
    1861            4 :         if (airTerm.ControllerOffset <= 0.0) {
    1862            0 :             airTerm.ControllerOffset = 0.001;
    1863              :         }
    1864            4 :         airTerm.DamperHeatingAction = Action::HeatingNotUsed;
    1865              : 
    1866              :         // Register component set data
    1867            8 :         TestCompSet(state,
    1868              :                     airTerm.sysType,
    1869              :                     airTerm.SysName,
    1870            4 :                     state.dataLoopNodes->NodeID(airTerm.InletNodeNum),
    1871            4 :                     state.dataLoopNodes->NodeID(airTerm.ReheatAirOutletNode),
    1872              :                     "Air Nodes");
    1873              : 
    1874            8 :         for (ADUNum = 1; ADUNum <= (int)state.dataDefineEquipment->AirDistUnit.size(); ++ADUNum) {
    1875            8 :             if (airTerm.ReheatAirOutletNode == state.dataDefineEquipment->AirDistUnit(ADUNum).OutletNodeNum) {
    1876            4 :                 state.dataDefineEquipment->AirDistUnit(ADUNum).InletNodeNum = airTerm.InletNodeNum;
    1877            4 :                 airTerm.ADUNum = ADUNum;
    1878            4 :                 break;
    1879              :             }
    1880              :         }
    1881              :         // one assumes if there isn't one assigned, it's an error?
    1882            4 :         if (airTerm.ADUNum == 0) {
    1883            0 :             ShowSevereError(state,
    1884            0 :                             format("{}No matching Air Distribution Unit, for System = [{},{}].", RoutineName, airTerm.sysType, airTerm.SysName));
    1885            0 :             ShowContinueError(state, format("...should have outlet node = {}", state.dataLoopNodes->NodeID(airTerm.ReheatAirOutletNode)));
    1886            0 :             ErrorsFound = true;
    1887              :         } else {
    1888              : 
    1889              :             // Fill the Zone Equipment data with the inlet node number of this unit.
    1890              :             // what if not found?  error?
    1891            4 :             IsNotOK = true;
    1892            7 :             for (CtrlZone = 1; CtrlZone <= state.dataGlobal->NumOfZones; ++CtrlZone) {
    1893            3 :                 if (!state.dataZoneEquip->ZoneEquipConfig(CtrlZone).IsControlled) {
    1894            0 :                     continue;
    1895              :                 }
    1896            6 :                 for (SupAirIn = 1; SupAirIn <= state.dataZoneEquip->ZoneEquipConfig(CtrlZone).NumInletNodes; ++SupAirIn) {
    1897            3 :                     if (airTerm.ReheatAirOutletNode == state.dataZoneEquip->ZoneEquipConfig(CtrlZone).InletNode(SupAirIn)) {
    1898            3 :                         IsNotOK = false;
    1899            3 :                         if (state.dataZoneEquip->ZoneEquipConfig(CtrlZone).AirDistUnitCool(SupAirIn).OutNode > 0) {
    1900            0 :                             ShowSevereError(state, "Error in connecting a terminal unit to a zone");
    1901            0 :                             ShowContinueError(
    1902            0 :                                 state, format("{} already connects to another zone", state.dataLoopNodes->NodeID(airTerm.ReheatAirOutletNode)));
    1903            0 :                             ShowContinueError(state, format("Occurs for terminal unit {} = {}", airTerm.sysType, airTerm.SysName));
    1904            0 :                             ShowContinueError(state, "Check terminal unit node names for errors");
    1905            0 :                             ErrorsFound = true;
    1906              :                         } else {
    1907            3 :                             state.dataZoneEquip->ZoneEquipConfig(CtrlZone).AirDistUnitCool(SupAirIn).InNode = airTerm.InletNodeNum;
    1908            3 :                             state.dataZoneEquip->ZoneEquipConfig(CtrlZone).AirDistUnitCool(SupAirIn).OutNode = airTerm.ReheatAirOutletNode;
    1909            3 :                             state.dataDefineEquipment->AirDistUnit(airTerm.ADUNum).TermUnitSizingNum =
    1910            3 :                                 state.dataZoneEquip->ZoneEquipConfig(CtrlZone).AirDistUnitCool(SupAirIn).TermUnitSizingIndex;
    1911            3 :                             state.dataDefineEquipment->AirDistUnit(airTerm.ADUNum).ZoneEqNum = CtrlZone;
    1912              :                         }
    1913            3 :                         airTerm.CtrlZoneNum = CtrlZone;
    1914            3 :                         airTerm.CtrlZoneInNodeIndex = SupAirIn;
    1915            3 :                         airTerm.ZoneFloorArea = state.dataHeatBal->Zone(CtrlZone).FloorArea * state.dataHeatBal->Zone(CtrlZone).Multiplier *
    1916            3 :                                                 state.dataHeatBal->Zone(CtrlZone).ListMultiplier;
    1917              :                     }
    1918              :                 }
    1919              :             }
    1920              :         }
    1921            4 :         if (IsNotOK) {
    1922            2 :             ShowWarningError(state, "Did not Match Supply Air Outlet Node to any Zone Node");
    1923            1 :             ShowContinueError(state, format("..Occurs in {} = {}", airTerm.sysType, airTerm.SysName));
    1924              :         }
    1925              : 
    1926            4 :         if (lAlphaBlanks(9)) {
    1927            2 :             airTerm.ZoneTurndownMinAirFrac = 1.0;
    1928            2 :         } else if ((airTerm.zoneTurndownMinAirFracSched = Sched::GetSchedule(state, Alphas(9))) == nullptr) {
    1929            0 :             ShowSevereItemNotFound(state, eoh, cAlphaFields(9), Alphas(9));
    1930            0 :             ErrorsFound = true;
    1931              :         }
    1932              : 
    1933              :         // Add reheat coil to component sets array
    1934            8 :         SetUpCompSets(state,
    1935              :                       airTerm.sysType,
    1936              :                       airTerm.SysName,
    1937            4 :                       Alphas(7),
    1938            4 :                       Alphas(8),
    1939            4 :                       state.dataLoopNodes->NodeID(airTerm.OutletNodeNum),
    1940            4 :                       state.dataLoopNodes->NodeID(airTerm.ReheatAirOutletNode));
    1941              :         // Add fan to component sets array
    1942            8 :         SetUpCompSets(state,
    1943              :                       airTerm.sysType,
    1944              :                       airTerm.SysName,
    1945            4 :                       Alphas(5),
    1946            4 :                       Alphas(6),
    1947            4 :                       state.dataLoopNodes->NodeID(airTerm.InletNodeNum),
    1948            4 :                       state.dataLoopNodes->NodeID(airTerm.OutletNodeNum));
    1949              : 
    1950              :         // Setup the Average damper Position output variable
    1951            8 :         SetupOutputVariable(state,
    1952              :                             "Zone Air Terminal VAV Damper Position",
    1953              :                             Constant::Units::None,
    1954            4 :                             airTerm.DamperPosition,
    1955              :                             OutputProcessor::TimeStepType::System,
    1956              :                             OutputProcessor::StoreType::Average,
    1957            4 :                             airTerm.SysName);
    1958              :     }
    1959              : 
    1960              :     // common report variable for all single duct air terminals
    1961          170 :     for (int sdIndex = 1; sdIndex <= state.dataSingleDuct->NumSDAirTerminal; ++sdIndex) {
    1962          196 :         SetupOutputVariable(state,
    1963              :                             "Zone Air Terminal Outdoor Air Volume Flow Rate",
    1964              :                             Constant::Units::m3_s,
    1965           98 :                             state.dataSingleDuct->sd_airterminal(sdIndex).OutdoorAirFlowRate,
    1966              :                             OutputProcessor::TimeStepType::System,
    1967              :                             OutputProcessor::StoreType::Average,
    1968           98 :                             state.dataSingleDuct->sd_airterminal(sdIndex).SysName);
    1969              :     }
    1970              : 
    1971              :     // Error check to see if a single duct air terminal is assigned to zone that has zone secondary recirculation
    1972              :     // specified in the Sizing:Zone object
    1973              : 
    1974           72 :     NumZoneSiz = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Sizing:Zone");
    1975           72 :     if (NumZoneSiz > 0) {
    1976           76 :         for (state.dataSingleDuct->SysIndexGSI = 1; state.dataSingleDuct->SysIndexGSI <= state.dataSingleDuct->NumSDAirTerminal;
    1977           44 :              ++state.dataSingleDuct->SysIndexGSI) {
    1978          135 :             for (ZoneSizIndex = 1; ZoneSizIndex <= NumZoneSiz; ++ZoneSizIndex) {
    1979           91 :                 if (state.dataGlobal->DoZoneSizing) {
    1980           82 :                     if (state.dataSize->FinalZoneSizing(ZoneSizIndex).ZoneNum ==
    1981           82 :                         state.dataSingleDuct->sd_airterminal(state.dataSingleDuct->SysIndexGSI).CtrlZoneNum) {
    1982           31 :                         if (state.dataSize->FinalZoneSizing(ZoneSizIndex).ZoneSecondaryRecirculation > 0.0) {
    1983            0 :                             ShowWarningError(state,
    1984            0 :                                              format("{}A zone secondary recirculation fraction is specified for zone served by ", RoutineName));
    1985            0 :                             ShowContinueError(state,
    1986            0 :                                               format("...terminal unit \"{}\" , that indicates a single path system",
    1987            0 :                                                      state.dataSingleDuct->sd_airterminal(state.dataSingleDuct->SysIndexGSI).SysName));
    1988            0 :                             ShowContinueError(state, "...The zone secondary recirculation for that zone was set to 0.0");
    1989            0 :                             state.dataSize->FinalZoneSizing(ZoneSizIndex).ZoneSecondaryRecirculation = 0.0;
    1990            0 :                             goto SizLoop_exit;
    1991              :                         }
    1992              :                     }
    1993              :                 }
    1994              :             }
    1995           44 :         SizLoop_exit:;
    1996              :         }
    1997              :     }
    1998              : 
    1999           72 :     Alphas.deallocate();
    2000           72 :     cAlphaFields.deallocate();
    2001           72 :     cNumericFields.deallocate();
    2002           72 :     Numbers.deallocate();
    2003           72 :     lAlphaBlanks.deallocate();
    2004           72 :     lNumericBlanks.deallocate();
    2005              : 
    2006           72 :     if (ErrorsFound) {
    2007            0 :         ShowFatalError(state, format("{}Errors found in input.  Preceding condition(s) cause termination.", RoutineName));
    2008              :     }
    2009           72 : }
    2010              : 
    2011              : // End of Get Input subroutines for the Module
    2012              : //******************************************************************************
    2013              : 
    2014              : // Beginning Initialization Section of the Module
    2015              : //******************************************************************************
    2016              : 
    2017        97489 : void SingleDuctAirTerminal::InitSys(EnergyPlusData &state, bool const FirstHVACIteration)
    2018              : {
    2019              : 
    2020              :     // SUBROUTINE INFORMATION:
    2021              :     //       AUTHOR         Richard J. Liesen
    2022              :     //       DATE WRITTEN   January 2000
    2023              : 
    2024              :     // PURPOSE OF THIS SUBROUTINE:
    2025              :     // This subroutine is for  initializations of the Sys Components.
    2026              : 
    2027              :     // METHODOLOGY EMPLOYED:
    2028              :     // Uses the status flags to trigger events.
    2029              : 
    2030              :     // Using/Aliasing
    2031              : 
    2032              :     using DataZoneEquipment::CheckZoneEquipmentList;
    2033              :     using PlantUtilities::InitComponentNodes;
    2034              :     using PlantUtilities::ScanPlantLoopsForObject;
    2035        97489 :     auto &GetHeatingCoilCapacity(HeatingCoils::GetCoilCapacity);
    2036              : 
    2037              :     // SUBROUTINE PARAMETER DEFINITIONS:
    2038              :     static constexpr std::string_view RoutineName("InitSys");
    2039              :     static constexpr std::string_view RoutineNameFull("InitHVACSingleDuct");
    2040              : 
    2041              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    2042              :     int InletNode;
    2043              :     int OutletNode;
    2044              :     Real64 SteamTemp;
    2045              :     Real64 SteamDensity;
    2046              :     Real64 rho;
    2047              :     bool errFlag;
    2048              : 
    2049              :     // static Array1D_bool PlantLoopScanFlag;
    2050              : 
    2051              :     // Do the Begin Simulation initializations
    2052        97489 :     if (this->PlantLoopScanFlag && allocated(state.dataPlnt->PlantLoop)) {
    2053           28 :         if ((this->ReheatComp_PlantType == DataPlant::PlantEquipmentType::CoilWaterSimpleHeating) ||
    2054           26 :             (this->ReheatComp_PlantType == DataPlant::PlantEquipmentType::CoilSteamAirHeating)) {
    2055              :             // setup plant topology indices for plant fed heating coils
    2056            2 :             errFlag = false;
    2057            2 :             ScanPlantLoopsForObject(state, this->ReheatName, this->ReheatComp_PlantType, this->HWplantLoc, errFlag, _, _, _, _, _);
    2058              : 
    2059            2 :             if (errFlag) {
    2060            0 :                 ShowContinueError(state, format("Reference Unit=\"{}\", type={}", this->SysName, this->sysType));
    2061            0 :                 ShowFatalError(state, "InitSys: Program terminated for previous conditions.");
    2062              :             }
    2063              : 
    2064            2 :             this->ReheatCoilOutletNode = DataPlant::CompData::getPlantComponent(state, this->HWplantLoc).NodeNumOut;
    2065              : 
    2066            2 :             this->PlantLoopScanFlag = false;
    2067              :         } else {
    2068           26 :             this->PlantLoopScanFlag = false;
    2069              :         }
    2070        97461 :     } else if (this->PlantLoopScanFlag && !state.dataGlobal->AnyPlantInModel) {
    2071           26 :         this->PlantLoopScanFlag = false;
    2072              :     }
    2073              : 
    2074        97489 :     if (!state.dataSingleDuct->ZoneEquipmentListChecked && state.dataZoneEquip->ZoneEquipInputsFilled) {
    2075           29 :         state.dataSingleDuct->ZoneEquipmentListChecked = true;
    2076              :         // Check to see if there is a Air Distribution Unit on the Zone Equipment List
    2077           70 :         for (int SysIndex = 1; SysIndex <= state.dataSingleDuct->NumSDAirTerminal; ++SysIndex) {
    2078           41 :             if (state.dataSingleDuct->sd_airterminal(SysIndex).ADUNum == 0) {
    2079            0 :                 continue;
    2080              :             }
    2081           82 :             if (CheckZoneEquipmentList(state,
    2082              :                                        "ZoneHVAC:AirDistributionUnit",
    2083           41 :                                        state.dataDefineEquipment->AirDistUnit(state.dataSingleDuct->sd_airterminal(SysIndex).ADUNum).Name)) {
    2084           41 :                 continue;
    2085              :             }
    2086            0 :             ShowSevereError(state,
    2087            0 :                             format("InitSingleDuctSystems: ADU=[Air Distribution Unit,{}] is not on any ZoneHVAC:EquipmentList.",
    2088            0 :                                    state.dataDefineEquipment->AirDistUnit(state.dataSingleDuct->sd_airterminal(SysIndex).ADUNum).Name));
    2089            0 :             ShowContinueError(state,
    2090            0 :                               format("...System=[{},{}] will not be simulated.",
    2091            0 :                                      state.dataSingleDuct->sd_airterminal(SysIndex).sysType,
    2092            0 :                                      state.dataSingleDuct->sd_airterminal(SysIndex).SysName));
    2093              :         }
    2094              :     }
    2095              : 
    2096              :     // get current time step air terminal box turndown minimum flow fraction
    2097        97489 :     if (this->zoneTurndownMinAirFracSched != nullptr) {
    2098           12 :         this->ZoneTurndownMinAirFrac = this->zoneTurndownMinAirFracSched->getCurrentVal();
    2099              :     } else {
    2100        97477 :         this->ZoneTurndownMinAirFrac = 1.0;
    2101              :     }
    2102              : 
    2103        97489 :     if (!state.dataGlobal->SysSizingCalc && this->MySizeFlag) {
    2104              : 
    2105           37 :         this->SizeSys(state);
    2106              : 
    2107           37 :         this->MySizeFlag = false;
    2108              :     }
    2109              : 
    2110        97489 :     if (this->GetGasElecHeatCoilCap) {
    2111           58 :         if (this->ReheatComp_Num == HeatingCoilType::Electric || this->ReheatComp_Num == HeatingCoilType::Gas) {
    2112           20 :             if (this->ReheatCoilMaxCapacity == AutoSize) {
    2113            6 :                 errFlag = false;
    2114            6 :                 this->ReheatCoilMaxCapacity = GetHeatingCoilCapacity(state, this->ReheatComp, this->ReheatName, errFlag);
    2115            6 :                 if (errFlag) {
    2116            0 :                     ShowContinueError(state, format("Occurs for terminal unit {} = {}", this->sysType, this->SysName));
    2117              :                 }
    2118              :             }
    2119           20 :             if (this->ReheatCoilMaxCapacity != AutoSize) {
    2120           16 :                 this->GetGasElecHeatCoilCap = false;
    2121              :             }
    2122              :         } else {
    2123           38 :             this->GetGasElecHeatCoilCap = false;
    2124              :         }
    2125              :     }
    2126              : 
    2127              :     // Do the Begin Environment initializations
    2128        97489 :     if (state.dataGlobal->BeginEnvrnFlag && this->MyEnvrnFlag) {
    2129              : 
    2130              :         // Set the outlet node max mass flow rate to the Max Air Flow specified for the Sys
    2131          119 :         OutletNode = this->OutletNodeNum;
    2132          119 :         InletNode = this->InletNodeNum;
    2133          119 :         state.dataLoopNodes->Node(OutletNode).MassFlowRateMax = this->MaxAirVolFlowRate * state.dataEnvrn->StdRhoAir;
    2134          119 :         this->AirMassFlowRateMax = this->MaxAirVolFlowRate * state.dataEnvrn->StdRhoAir;
    2135          119 :         this->HeatAirMassFlowRateMax = this->MaxHeatAirVolFlowRate * state.dataEnvrn->StdRhoAir;
    2136          119 :         state.dataLoopNodes->Node(InletNode).MassFlowRateMax = this->MaxAirVolFlowRate * state.dataEnvrn->StdRhoAir;
    2137          119 :         this->MassFlowDiff = 1.0e-10 * this->AirMassFlowRateMax;
    2138              : 
    2139          119 :         if (this->HWplantLoc.loopNum > 0 && this->ReheatComp_Num != HeatingCoilType::SteamAirHeating) { // protect early calls before plant is setup
    2140            8 :             rho = state.dataPlnt->PlantLoop(this->HWplantLoc.loopNum).glycol->getDensity(state, Constant::HWInitConvTemp, RoutineName);
    2141              :         } else {
    2142          111 :             rho = 1000.0;
    2143              :         }
    2144              : 
    2145          119 :         this->MaxReheatWaterFlow = rho * this->MaxReheatWaterVolFlow;
    2146          119 :         this->MinReheatWaterFlow = rho * this->MinReheatWaterVolFlow;
    2147              : 
    2148          119 :         this->AirMassFlowDuringReheatMax = this->MaxAirVolFlowRateDuringReheat * state.dataEnvrn->StdRhoAir;
    2149              : 
    2150              :         // set the upstream leakage flowrate - remove from here - done in ZoneAirLoopEquipmentManager::SimZoneAirLoopEquipment
    2151              : 
    2152          119 :         if (this->ReheatComp_Num == HeatingCoilType::SteamAirHeating) {
    2153            0 :             SteamTemp = 100.0;
    2154            0 :             SteamDensity = Fluid::GetSteam(state)->getSatDensity(state, SteamTemp, 1.0, RoutineNameFull);
    2155            0 :             this->MaxReheatSteamFlow = SteamDensity * this->MaxReheatSteamVolFlow;
    2156            0 :             this->MinReheatSteamFlow = SteamDensity * this->MinReheatSteamVolFlow;
    2157              :         }
    2158              : 
    2159              :         // get current environment air terminal box turndown minimum flow fraction
    2160          119 :         Real64 CurrentEnvZoneTurndownMinAirFrac = 1.0;
    2161          119 :         if (this->zoneTurndownMinAirFracSched != nullptr) {
    2162            6 :             CurrentEnvZoneTurndownMinAirFrac = this->zoneTurndownMinAirFracSched->getCurrentVal();
    2163              :         }
    2164          119 :         if ((this->SysType_Num == SysType::SingleDuctVAVReheat || this->SysType_Num == SysType::SingleDuctCBVAVReheat) ||
    2165           92 :             (this->SysType_Num == SysType::SingleDuctCBVAVNoReheat)) {
    2166              :             // need the lowest schedule value
    2167           27 :             if (this->ZoneMinAirFracMethod == MinFlowFraction::Scheduled) {
    2168            0 :                 this->ZoneMinAirFracDes = this->zoneMinAirFracSched->getCurrentVal();
    2169              :             }
    2170           27 :             state.dataLoopNodes->Node(OutletNode).MassFlowRateMin =
    2171           27 :                 state.dataLoopNodes->Node(OutletNode).MassFlowRateMax * this->ZoneMinAirFracDes * CurrentEnvZoneTurndownMinAirFrac;
    2172           27 :             state.dataLoopNodes->Node(InletNode).MassFlowRateMin =
    2173           27 :                 state.dataLoopNodes->Node(InletNode).MassFlowRateMax * this->ZoneMinAirFracDes * CurrentEnvZoneTurndownMinAirFrac;
    2174              :         } else {
    2175           92 :             state.dataLoopNodes->Node(OutletNode).MassFlowRateMin = 0.0;
    2176           92 :             state.dataLoopNodes->Node(InletNode).MassFlowRateMin = 0.0;
    2177              :         }
    2178          119 :         if ((this->ReheatControlNode > 0) && !this->PlantLoopScanFlag) {
    2179            8 :             if (this->ReheatComp_Num == HeatingCoilType::SteamAirHeating) {
    2180            0 :                 InitComponentNodes(state, this->MinReheatSteamFlow, this->MaxReheatSteamFlow, this->ReheatControlNode, this->ReheatCoilOutletNode);
    2181              :             } else {
    2182            8 :                 InitComponentNodes(state, this->MinReheatWaterFlow, this->MaxReheatWaterFlow, this->ReheatControlNode, this->ReheatCoilOutletNode);
    2183              :             }
    2184              :         }
    2185              :         // Find air loop associated with terminal unit
    2186          119 :         if ((this->CtrlZoneNum > 0) && (this->CtrlZoneInNodeIndex > 0)) {
    2187          119 :             this->AirLoopNum = state.dataZoneEquip->ZoneEquipConfig(this->CtrlZoneNum).InletNodeAirLoopNum(this->CtrlZoneInNodeIndex);
    2188          119 :             state.dataDefineEquipment->AirDistUnit(this->ADUNum).AirLoopNum = this->AirLoopNum;
    2189              :         }
    2190              : 
    2191          119 :         this->MyEnvrnFlag = false;
    2192              :     }
    2193              : 
    2194        97489 :     if (!state.dataGlobal->BeginEnvrnFlag) {
    2195        96567 :         this->MyEnvrnFlag = true;
    2196              :     }
    2197              : 
    2198              :     // Initialize the Inlet Nodes of the air side of air terminal
    2199        97489 :     InletNode = this->InletNodeNum;
    2200        97489 :     OutletNode = this->OutletNodeNum;
    2201              : 
    2202        97489 :     Real64 mDotFromOARequirement(0.0);
    2203              : 
    2204        97489 :     if (this->SysType_Num == SysType::SingleDuctConstVolNoReheat) {
    2205        30642 :         if (!this->NoOAFlowInputFromUser) {
    2206           11 :             mDotFromOARequirement = this->AirMassFlowRateMax;
    2207           11 :             int airLoopNum(0);
    2208           11 :             Real64 airLoopOAFrac(0.0);
    2209           11 :             airLoopNum = this->AirLoopNum;
    2210           11 :             if (airLoopNum > 0) {
    2211            7 :                 airLoopOAFrac = state.dataAirLoop->AirLoopFlow(airLoopNum).OAFrac;
    2212            7 :                 bool UseOccSchFlag = false;
    2213            7 :                 if (this->OAPerPersonMode == DataZoneEquipment::PerPersonVentRateMode::DCVByCurrentLevel) {
    2214            7 :                     UseOccSchFlag = true;
    2215              :                 }
    2216            7 :                 if (airLoopOAFrac > 0.0) {
    2217              :                     Real64 vDotOAReq =
    2218            6 :                         DataSizing::calcDesignSpecificationOutdoorAir(state, this->OARequirementsPtr, this->CtrlZoneNum, UseOccSchFlag, true);
    2219            6 :                     mDotFromOARequirement = vDotOAReq * state.dataEnvrn->StdRhoAir / airLoopOAFrac;
    2220            6 :                     mDotFromOARequirement = min(mDotFromOARequirement, this->AirMassFlowRateMax);
    2221              :                 } else {
    2222            1 :                     mDotFromOARequirement = this->AirMassFlowRateMax;
    2223              :                 }
    2224              :             }
    2225              :         }
    2226              :     }
    2227              : 
    2228        97489 :     if (this->ZoneMinAirFracMethod == MinFlowFraction::Scheduled) {
    2229            0 :         this->ZoneMinAirFracDes = this->zoneMinAirFracSched->getCurrentVal();
    2230              :         // now reset inlet node min avail
    2231            0 :         state.dataLoopNodes->Node(InletNode).MassFlowRateMinAvail = this->AirMassFlowRateMax * this->ZoneMinAirFracDes * this->ZoneTurndownMinAirFrac;
    2232              :     }
    2233              : 
    2234        97489 :     if (FirstHVACIteration) {
    2235              :         // The first time through set the mass flow rate to the Max
    2236        44630 :         if ((state.dataLoopNodes->Node(InletNode).MassFlowRate > 0.0) && (this->availSched->getCurrentVal() > 0.0)) {
    2237        42204 :             if (!(state.afn->distribution_simulated && state.afn->AirflowNetworkFanActivated)) {
    2238        42203 :                 state.dataLoopNodes->Node(InletNode).MassFlowRate = this->AirMassFlowRateMax;
    2239              :             }
    2240              :         } else {
    2241         2426 :             state.dataLoopNodes->Node(InletNode).MassFlowRate = 0.0;
    2242              :         }
    2243        44630 :         if ((state.dataLoopNodes->Node(InletNode).MassFlowRateMaxAvail > 0.0) && (this->availSched->getCurrentVal() > 0.0)) {
    2244        42207 :             if (!(state.afn->distribution_simulated && state.afn->AirflowNetworkFanActivated)) {
    2245        42206 :                 if (this->SysType_Num == SysType::SingleDuctConstVolNoReheat) {
    2246        10260 :                     if (this->NoOAFlowInputFromUser) {
    2247        10259 :                         state.dataLoopNodes->Node(InletNode).MassFlowRate = this->AirMassFlowRateMax;
    2248        10259 :                         state.dataLoopNodes->Node(InletNode).MassFlowRateMaxAvail = this->AirMassFlowRateMax;
    2249              :                     } else {
    2250            1 :                         state.dataLoopNodes->Node(InletNode).MassFlowRate = mDotFromOARequirement;
    2251            1 :                         state.dataLoopNodes->Node(InletNode).MassFlowRateMaxAvail = mDotFromOARequirement;
    2252              :                     }
    2253        10260 :                     if (this->EMSOverrideAirFlow) {
    2254            0 :                         state.dataLoopNodes->Node(InletNode).MassFlowRate = this->EMSMassFlowRateValue;
    2255            0 :                         state.dataLoopNodes->Node(InletNode).MassFlowRateMaxAvail = this->EMSMassFlowRateValue;
    2256              :                     }
    2257              :                 } else {
    2258        31946 :                     state.dataLoopNodes->Node(InletNode).MassFlowRateMaxAvail = this->AirMassFlowRateMax;
    2259              :                 }
    2260              :             }
    2261              :         } else {
    2262         2423 :             state.dataLoopNodes->Node(InletNode).MassFlowRateMaxAvail = 0.0;
    2263              :         }
    2264              : 
    2265        44630 :         if ((state.dataLoopNodes->Node(InletNode).MassFlowRate > 0.0) && (this->availSched->getCurrentVal() > 0.0)) {
    2266        42207 :             if (!(state.afn->distribution_simulated && state.afn->AirflowNetworkFanActivated)) {
    2267        42206 :                 state.dataLoopNodes->Node(InletNode).MassFlowRateMinAvail =
    2268        42206 :                     this->AirMassFlowRateMax * this->ZoneMinAirFracDes * this->ZoneTurndownMinAirFrac;
    2269              :             }
    2270              :         } else {
    2271         2423 :             state.dataLoopNodes->Node(InletNode).MassFlowRateMinAvail = 0.0;
    2272              :         }
    2273              :         // reset the mass flow rate histories
    2274        44630 :         this->MassFlow1 = 0.0;
    2275        44630 :         this->MassFlow2 = 0.0;
    2276        44630 :         this->MassFlow3 = 0.0;
    2277        44630 :         this->MassFlow3 = 0.0;
    2278              : 
    2279              :     } else {
    2280        52859 :         if (this->SysType_Num == SysType::SingleDuctConstVolNoReheat) {
    2281        18069 :             if (!this->EMSOverrideAirFlow) {
    2282        18068 :                 if ((state.dataLoopNodes->Node(InletNode).MassFlowRateMaxAvail > 0.0) && (this->availSched->getCurrentVal() > 0.0)) {
    2283        15792 :                     if (this->NoOAFlowInputFromUser) {
    2284        15785 :                         if (state.dataLoopNodes->Node(InletNode).MassFlowRateMaxAvail < state.dataLoopNodes->Node(InletNode).MassFlowRateMax) {
    2285         5065 :                             state.dataLoopNodes->Node(InletNode).MassFlowRate = state.dataLoopNodes->Node(InletNode).MassFlowRateMaxAvail;
    2286        10720 :                         } else if (state.dataLoopNodes->Node(InletNode).MassFlowRateMinAvail > state.dataLoopNodes->Node(InletNode).MassFlowRateMin) {
    2287            0 :                             state.dataLoopNodes->Node(InletNode).MassFlowRate = state.dataLoopNodes->Node(InletNode).MassFlowRateMinAvail;
    2288              :                         } else {
    2289        10720 :                             state.dataLoopNodes->Node(InletNode).MassFlowRate = state.dataLoopNodes->Node(InletNode).MassFlowRateMaxAvail;
    2290              :                         }
    2291              :                     } else {
    2292            7 :                         state.dataLoopNodes->Node(InletNode).MassFlowRate = mDotFromOARequirement;
    2293              :                         // but also apply constraints
    2294            7 :                         state.dataLoopNodes->Node(InletNode).MassFlowRate =
    2295            7 :                             min(state.dataLoopNodes->Node(InletNode).MassFlowRate, state.dataLoopNodes->Node(InletNode).MassFlowRateMaxAvail);
    2296            7 :                         state.dataLoopNodes->Node(InletNode).MassFlowRate =
    2297            7 :                             min(state.dataLoopNodes->Node(InletNode).MassFlowRate, state.dataLoopNodes->Node(InletNode).MassFlowRateMax);
    2298            7 :                         state.dataLoopNodes->Node(InletNode).MassFlowRate =
    2299            7 :                             max(state.dataLoopNodes->Node(InletNode).MassFlowRate, state.dataLoopNodes->Node(InletNode).MassFlowRateMinAvail);
    2300            7 :                         state.dataLoopNodes->Node(InletNode).MassFlowRate =
    2301            7 :                             max(state.dataLoopNodes->Node(InletNode).MassFlowRate, state.dataLoopNodes->Node(InletNode).MassFlowRateMin);
    2302              :                     }
    2303              :                 } else {
    2304         2276 :                     state.dataLoopNodes->Node(InletNode).MassFlowRate = 0.0;
    2305         2276 :                     state.dataLoopNodes->Node(InletNode).MassFlowRateMaxAvail = 0.0;
    2306         2276 :                     state.dataLoopNodes->Node(InletNode).MassFlowRateMinAvail = 0.0;
    2307              :                 }
    2308              :             } else { // EMS override on
    2309            1 :                 state.dataLoopNodes->Node(InletNode).MassFlowRate = this->EMSMassFlowRateValue;
    2310              :                 // but also apply constraints
    2311            1 :                 state.dataLoopNodes->Node(InletNode).MassFlowRate =
    2312            1 :                     min(state.dataLoopNodes->Node(InletNode).MassFlowRate, state.dataLoopNodes->Node(InletNode).MassFlowRateMaxAvail);
    2313            1 :                 state.dataLoopNodes->Node(InletNode).MassFlowRate =
    2314            1 :                     min(state.dataLoopNodes->Node(InletNode).MassFlowRate, state.dataLoopNodes->Node(InletNode).MassFlowRateMax);
    2315            1 :                 state.dataLoopNodes->Node(InletNode).MassFlowRate =
    2316            1 :                     max(state.dataLoopNodes->Node(InletNode).MassFlowRate, state.dataLoopNodes->Node(InletNode).MassFlowRateMinAvail);
    2317            1 :                 state.dataLoopNodes->Node(InletNode).MassFlowRate =
    2318            1 :                     max(state.dataLoopNodes->Node(InletNode).MassFlowRate, state.dataLoopNodes->Node(InletNode).MassFlowRateMin);
    2319              :             }
    2320              :         }
    2321              :     }
    2322              : 
    2323              :     // Do a check and make sure that the max and min available(control) flow is
    2324              :     //  between the physical max and min while operating.
    2325        97489 :     this->sd_airterminalInlet.AirMassFlowRateMaxAvail = min(this->AirMassFlowRateMax, state.dataLoopNodes->Node(InletNode).MassFlowRateMaxAvail);
    2326        97489 :     this->sd_airterminalInlet.AirMassFlowRateMinAvail =
    2327        97489 :         min(max(state.dataLoopNodes->Node(OutletNode).MassFlowRateMin, state.dataLoopNodes->Node(InletNode).MassFlowRateMinAvail),
    2328              :             this->sd_airterminalInlet.AirMassFlowRateMaxAvail);
    2329              : 
    2330              :     // Do the following initializations (every time step): This should be the info from
    2331              :     // the previous components outlets or the node data in this section.
    2332              :     // Load the node data in this section for the component simulation
    2333        97489 :     this->sd_airterminalInlet.AirMassFlowRate = state.dataLoopNodes->Node(InletNode).MassFlowRate;
    2334        97489 :     this->sd_airterminalInlet.AirTemp = state.dataLoopNodes->Node(InletNode).Temp;
    2335        97489 :     this->sd_airterminalInlet.AirHumRat = state.dataLoopNodes->Node(InletNode).HumRat;
    2336        97489 :     this->sd_airterminalInlet.AirEnthalpy = state.dataLoopNodes->Node(InletNode).Enthalpy;
    2337              : 
    2338              :     // update to the current minimum air flow fraction
    2339        97489 :     this->ZoneMinAirFrac = this->ZoneMinAirFracDes * this->ZoneTurndownMinAirFrac;
    2340        97489 : }
    2341              : 
    2342           56 : void SingleDuctAirTerminal::SizeSys(EnergyPlusData &state)
    2343              : {
    2344              : 
    2345              :     // SUBROUTINE INFORMATION:
    2346              :     //       AUTHOR         Fred Buhl
    2347              :     //       DATE WRITTEN   September 2001
    2348              :     //       MODIFIED       August 2013 Daeho Kang, add component sizing table entries
    2349              : 
    2350              :     // PURPOSE OF THIS SUBROUTINE:
    2351              :     // This subroutine is for sizing Sys Components for which flow rates have not been
    2352              :     // specified in the input.
    2353              : 
    2354              :     // METHODOLOGY EMPLOYED:
    2355              :     // Obtains flow rates from the zone or system sizing arrays.
    2356              : 
    2357              :     // Using/Aliasing
    2358              :     using General::SafeDivide;
    2359              :     using PlantUtilities::MyPlantSizingIndex;
    2360              :     using SteamCoils::GetCoilSteamInletNode;
    2361              :     using SteamCoils::GetCoilSteamOutletNode;
    2362              :     using WaterCoils::GetCoilWaterInletNode;
    2363              :     using WaterCoils::GetCoilWaterOutletNode;
    2364              :     using WaterCoils::SetCoilDesFlow;
    2365              : 
    2366              :     // SUBROUTINE PARAMETER DEFINITIONS:
    2367              :     static constexpr std::string_view RoutineName("SizeSys");
    2368              :     static constexpr std::string_view RoutineNameFull("SizeHVACSingleDuct");
    2369              : 
    2370              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    2371              :     int PltSizHeatNum; // index of plant sizing object for 1st heating loop
    2372              :     Real64 TempSteamIn;
    2373              :     Real64 EnthSteamOutWet;
    2374              :     Real64 EnthSteamInDry;
    2375              :     Real64 LatentHeatSteam;
    2376              :     Real64 SteamDensity;
    2377              : 
    2378              :     bool PlantSizingErrorsFound;
    2379              :     Real64 rho; // local fluid density
    2380              :     Real64 Cp;  // local fluid specific heat
    2381              : 
    2382           56 :     Real64 DesMassFlow = 0.0;
    2383           56 :     bool ErrorsFound = false;
    2384           56 :     bool IsAutoSize = false;
    2385           56 :     bool IsMaxFlowAutoSize = false;
    2386           56 :     Real64 MaxAirVolFlowRateDes = 0.0;              // Autosized maximum air flow rate for reporting
    2387           56 :     Real64 MaxAirVolFlowRateUser = 0.0;             // Hardsized maximum air flow rate for reporting
    2388           56 :     Real64 MaxHeatAirVolFlowRateDes = 0.0;          // Autosized maximum heating air flow rate for reporting
    2389           56 :     Real64 MaxHeatAirVolFlowRateUser = 0.0;         // Hardsized maximum heating air flow rate for reporting
    2390           56 :     Real64 MinAirFlowFracDes = 0.0;                 // Autosized minimum cooling air flow fraction for reporting
    2391           56 :     Real64 MinAirFlowFracUser = 0.0;                // User input minimum cooling air flow fraction for reporting
    2392           56 :     Real64 FixedMinAirDes = 0.0;                    // Autosized minimum cooling air flow rate for reporting [m3/s]
    2393           56 :     Real64 FixedMinAirUser = 0.0;                   // User input minimum cooling air flow rate for reporting [m3/s]
    2394           56 :     Real64 MaxAirVolFlowRateDuringReheatDes = 0.0;  // Autosized maximum air flow durign reheat for reporting
    2395           56 :     Real64 MaxAirVolFlowRateDuringReheatUser = 0.0; // Hardsized maximum air flow durign reheat for reporting
    2396           56 :     Real64 MaxAirVolFractionDuringReheatDes = 0.0;  // Autosized maximum air fraction durign reheat for reporting
    2397           56 :     Real64 MaxAirVolFractionDuringReheatUser = 0.0; // Hardsized maximum air flow durign reheat for reporting
    2398           56 :     Real64 MaxReheatWaterVolFlowDes = 0.0;          // Autosized reheat water flow or reporting
    2399           56 :     Real64 MaxReheatWaterVolFlowUser = 0.0;         // Hardsized reheat water flow for reporting
    2400           56 :     Real64 MaxReheatSteamVolFlowDes = 0.0;          // Autosized reheat steam flow for reporting
    2401           56 :     Real64 MaxReheatSteamVolFlowUser = 0.0;         // Hardsized reheat steam flow for reporting
    2402           56 :     Real64 MinMinFlowRatio = 0.0;                   // the minimum minimum flow ratio
    2403           56 :     int SysSizNum = 0;                              // System sizing number
    2404              : 
    2405           56 :     int ZoneNum = this->CtrlZoneNum;
    2406              : 
    2407           56 :     auto &TermUnitSizing(state.dataSize->TermUnitSizing);
    2408              : 
    2409           56 :     if (this->MaxAirVolFlowRate == AutoSize) {
    2410           34 :         IsAutoSize = true;
    2411              :     }
    2412              : 
    2413           56 :     if (state.dataSize->CurTermUnitSizingNum > 0) {
    2414           48 :         if (!IsAutoSize && !state.dataSize->ZoneSizingRunDone) { // simulation continue
    2415            7 :             if (this->MaxAirVolFlowRate > 0.0) {
    2416            7 :                 BaseSizer::reportSizerOutput(
    2417              :                     state, this->sysType, this->SysName, "User-Specified Maximum Air Flow Rate [m3/s]", this->MaxAirVolFlowRate);
    2418              :             }
    2419              :         } else { // Autosize or hard-size with sizing run
    2420              : 
    2421           41 :             CheckZoneSizing(state, this->sysType, this->SysName);
    2422              : 
    2423              :             Real64 heatingMaxFlow;
    2424           58 :             if (this->DamperHeatingAction == Action::ReverseWithLimits &&
    2425           17 :                 state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).DesHeatVolFlow >
    2426           17 :                     state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).DesHeatVolFlowMax) {
    2427            5 :                 heatingMaxFlow = state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).DesHeatVolFlowMax;
    2428              :             } else {
    2429           36 :                 heatingMaxFlow = state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).DesHeatVolFlow;
    2430              :             }
    2431           41 :             MaxAirVolFlowRateDes = max(state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).DesCoolVolFlow, heatingMaxFlow);
    2432              : 
    2433           41 :             if (MaxAirVolFlowRateDes < SmallAirVolFlow) {
    2434            4 :                 MaxAirVolFlowRateDes = 0.0;
    2435              :             }
    2436           41 :             if (IsAutoSize) {
    2437           34 :                 this->MaxAirVolFlowRate = MaxAirVolFlowRateDes;
    2438           34 :                 IsMaxFlowAutoSize = true;
    2439           34 :                 BaseSizer::reportSizerOutput(state, this->sysType, this->SysName, "Design Size Maximum Air Flow Rate [m3/s]", MaxAirVolFlowRateDes);
    2440              :             } else { // Hard-size with sizing data
    2441            7 :                 if (this->MaxAirVolFlowRate > 0.0 && MaxAirVolFlowRateDes > 0.0) {
    2442            3 :                     MaxAirVolFlowRateUser = this->MaxAirVolFlowRate;
    2443            3 :                     BaseSizer::reportSizerOutput(state,
    2444              :                                                  this->sysType,
    2445              :                                                  this->SysName,
    2446              :                                                  "Design Size Maximum Air Flow Rate [m3/s]",
    2447              :                                                  MaxAirVolFlowRateDes,
    2448              :                                                  "User-Specified Maximum Air Flow Rate [m3/s]",
    2449              :                                                  MaxAirVolFlowRateUser);
    2450            3 :                     if (state.dataGlobal->DisplayExtraWarnings) {
    2451            1 :                         if ((std::abs(MaxAirVolFlowRateDes - MaxAirVolFlowRateUser) / MaxAirVolFlowRateUser) >
    2452            1 :                             state.dataSize->AutoVsHardSizingThreshold) {
    2453            2 :                             ShowMessage(
    2454              :                                 state,
    2455            2 :                                 format("SizeHVACSingleDuct: Potential issue with equipment sizing for {} = \"{}\".", this->sysType, this->SysName));
    2456            1 :                             ShowContinueError(state, format("User-Specified Maximum Air Flow Rate of {:.5R} [m3/s]", MaxAirVolFlowRateUser));
    2457            1 :                             ShowContinueError(state, format("differs from Design Size Maximum Air Flow Rate of {:.5R} [m3/s]", MaxAirVolFlowRateDes));
    2458            2 :                             ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
    2459            3 :                             ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
    2460              :                         }
    2461              :                     }
    2462              :                 }
    2463              :             }
    2464              :         }
    2465              :     }
    2466              : 
    2467           56 :     IsAutoSize = false;
    2468           56 :     if (this->MaxHeatAirVolFlowRate == AutoSize) {
    2469            0 :         IsAutoSize = true;
    2470              :     }
    2471           56 :     if (state.dataSize->CurTermUnitSizingNum > 0) {
    2472           48 :         if (!IsAutoSize && !state.dataSize->ZoneSizingRunDone) { // simulation should continue
    2473            7 :             state.dataSingleDuct->UserInputMaxHeatAirVolFlowRateSS = this->MaxHeatAirVolFlowRate;
    2474            7 :             if (this->MaxHeatAirVolFlowRate > 0.0) {
    2475            0 :                 BaseSizer::reportSizerOutput(
    2476              :                     state, this->sysType, this->SysName, "User-Specified Maximum Heating Air Flow Rate [m3/s]", this->MaxHeatAirVolFlowRate);
    2477              :             }
    2478              :         } else {
    2479           41 :             CheckZoneSizing(state, this->sysType, this->SysName);
    2480           58 :             if (this->DamperHeatingAction == Action::ReverseWithLimits &&
    2481           17 :                 state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).DesHeatVolFlow >
    2482           17 :                     state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).DesHeatVolFlowMax) {
    2483            5 :                 MaxHeatAirVolFlowRateDes = state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).DesHeatVolFlowMax;
    2484              :             } else {
    2485           36 :                 MaxHeatAirVolFlowRateDes = state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).DesHeatVolFlow;
    2486              :             }
    2487           41 :             if (MaxHeatAirVolFlowRateDes < SmallAirVolFlow) {
    2488            6 :                 MaxHeatAirVolFlowRateDes = 0.0;
    2489              :             }
    2490           41 :             if (IsAutoSize) {
    2491            0 :                 this->MaxHeatAirVolFlowRate = MaxHeatAirVolFlowRateDes;
    2492            0 :                 state.dataSingleDuct->UserInputMaxHeatAirVolFlowRateSS = 0.0;
    2493            0 :                 BaseSizer::reportSizerOutput(
    2494              :                     state, this->sysType, this->SysName, "Design Size Maximum Heating Air Flow Rate [m3/s]", MaxHeatAirVolFlowRateDes);
    2495              :             } else { // Hard-size with sizing data
    2496           41 :                 if (this->MaxHeatAirVolFlowRate > 0.0 && MaxHeatAirVolFlowRateDes > 0.0) {
    2497            0 :                     MaxHeatAirVolFlowRateUser = this->MaxHeatAirVolFlowRate;
    2498            0 :                     state.dataSingleDuct->UserInputMaxHeatAirVolFlowRateSS = this->MaxHeatAirVolFlowRate;
    2499            0 :                     BaseSizer::reportSizerOutput(state,
    2500              :                                                  this->sysType,
    2501              :                                                  this->SysName,
    2502              :                                                  "Design Size Maximum Heating Air Flow Rate [m3/s]",
    2503              :                                                  MaxHeatAirVolFlowRateDes,
    2504              :                                                  "User-Specified Maximum Heating Air Flow Rate [m3/s]",
    2505              :                                                  MaxHeatAirVolFlowRateUser);
    2506            0 :                     if (state.dataGlobal->DisplayExtraWarnings) {
    2507            0 :                         if ((std::abs(MaxHeatAirVolFlowRateDes - MaxHeatAirVolFlowRateUser) / MaxHeatAirVolFlowRateUser) >
    2508            0 :                             state.dataSize->AutoVsHardSizingThreshold) {
    2509            0 :                             ShowMessage(
    2510              :                                 state,
    2511            0 :                                 format("SizeHVACSingleDuct: Potential issue with equipment sizing for {} = \"{}\".", this->sysType, this->SysName));
    2512            0 :                             ShowContinueError(state,
    2513            0 :                                               format("User-Specified Maximum Heating Air Flow Rate of {:.5R} [m3/s]", MaxHeatAirVolFlowRateUser));
    2514            0 :                             ShowContinueError(
    2515            0 :                                 state, format("differs from Design Size Maximum Heating Air Flow Rate of {:.5R} [m3/s]", MaxHeatAirVolFlowRateDes));
    2516            0 :                             ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
    2517            0 :                             ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
    2518              :                         }
    2519              :                     }
    2520              :                 }
    2521              :             }
    2522              :         }
    2523              :     }
    2524              : 
    2525              :     // get design day terminal unit turndown minimum flow fraction
    2526           56 :     if (this->zoneTurndownMinAirFracSched != nullptr) {
    2527            3 :         this->ZoneTurndownMinAirFrac = this->zoneTurndownMinAirFracSched->getCurrentVal();
    2528              :     } else {
    2529           53 :         this->ZoneTurndownMinAirFrac = 1.0;
    2530              :     }
    2531              : 
    2532              :     // if a sizing run has been done, check if system sizing has been done for this system
    2533           56 :     bool SizingDesRunThisAirSys = false;
    2534           56 :     if (state.dataSize->SysSizingRunDone) {
    2535           24 :         int AirLoopNum = state.dataZoneEquip->ZoneEquipConfig(this->CtrlZoneNum).InletNodeAirLoopNum(this->CtrlZoneInNodeIndex);
    2536           24 :         if (AirLoopNum > 0) {
    2537           24 :             CheckThisAirSystemForSizing(state, AirLoopNum, SizingDesRunThisAirSys);
    2538              :         }
    2539              : 
    2540              :         // get system sizing id if a sizing run has been done for this system
    2541           24 :         if (SizingDesRunThisAirSys) {
    2542           24 :             SysSizNum = Util::FindItemInList(
    2543           24 :                 state.dataSize->FinalSysSizing(AirLoopNum).AirPriLoopName, state.dataSize->SysSizInput, &SystemSizingInputData::AirPriLoopName);
    2544           24 :             if (SysSizNum == 0) {
    2545            0 :                 SysSizNum = 1; // use first when none applicable
    2546              :             }
    2547              :         }
    2548              :     }
    2549              : 
    2550           56 :     IsAutoSize = false;
    2551           56 :     if (this->ZoneMinAirFracDes == AutoSize) {
    2552           16 :         IsAutoSize = true;
    2553              :     }
    2554           56 :     if (this->ZoneMinAirFracMethod == MinFlowFraction::Constant) {
    2555           41 :         if (state.dataSize->ZoneSizingRunDone) {
    2556           28 :             if (state.dataSize->CurTermUnitSizingNum > 0) {
    2557              :                 // use the combined defaults or other user inputs stored in DesCoolVolFlowMin
    2558           28 :                 if (this->MaxAirVolFlowRate > 0.0) {
    2559           28 :                     MinAirFlowFracDes = min(1.0,
    2560           28 :                                             state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).DesCoolVolFlowMin /
    2561           28 :                                                 this->MaxAirVolFlowRate);
    2562              :                 } else {
    2563            0 :                     MinAirFlowFracDes = 0.0;
    2564              :                 }
    2565              :             }
    2566              :         } else {
    2567              :             // if no zone sizing values available; use max of min frac = 0.2 and 0.000762 [m3/s-m2]
    2568           13 :             if (this->MaxAirVolFlowRate > 0.0) {
    2569           13 :                 MinMinFlowRatio = (0.000762 * state.dataHeatBal->Zone(ZoneNum).FloorArea * state.dataHeatBal->Zone(ZoneNum).Multiplier *
    2570           13 :                                    state.dataHeatBal->Zone(ZoneNum).ListMultiplier) /
    2571           13 :                                   this->MaxAirVolFlowRate;
    2572           13 :                 MinAirFlowFracDes = max(0.2, MinMinFlowRatio);
    2573              :             } else {
    2574            0 :                 MinAirFlowFracDes = 0.0;
    2575              :             }
    2576              :         }
    2577           41 :         if (SizingDesRunThisAirSys) {
    2578           16 :             if (state.dataSize->SysSizInput(SysSizNum).SystemOAMethod == SysOAMethod::SP) { // 62.1 simplified procedure
    2579            3 :                 if (this->MaxAirVolFlowRate > 0.0) {
    2580            3 :                     MinAirFlowFracDes = 1.5 *
    2581            3 :                                         max(state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).VozClgByZone,
    2582            3 :                                             state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).VozHtgByZone) /
    2583            3 :                                         this->MaxAirVolFlowRate;
    2584              : 
    2585              :                     // adjust maximum flow rate
    2586            3 :                     if (MinAirFlowFracDes > 1.0 && IsMaxFlowAutoSize) {
    2587            3 :                         this->MaxAirVolFlowRate *= MinAirFlowFracDes;
    2588            3 :                         MinAirFlowFracDes = 1.0;
    2589            6 :                         ShowWarningError(state,
    2590            6 :                                          format("SingleDuctSystem:SizeSys: Autosized maximum air flow rate for {} was increased to meet the zone "
    2591              :                                                 "primary air flow determined according to the ASHRAE Standard 62.1 Simplified Procedure.",
    2592            3 :                                                 this->SysName));
    2593            0 :                     } else if (MinAirFlowFracDes > 1.0) {
    2594            0 :                         ShowWarningError(state,
    2595            0 :                                          format("SingleDuctSystem:SizeSys: Maximum air flow rate for {} is potentially too low.", this->SysName));
    2596            0 :                         ShowContinueError(
    2597              :                             state,
    2598              :                             "The flow is lower than the minimum flow rate calculated following the ASHRAE Standard 62.1 Simplified Procedure:");
    2599            0 :                         ShowContinueError(state, format(" User-specified maximum air flow rate: {:.3R} m3/s.", this->MaxAirVolFlowRate));
    2600            0 :                         ShowContinueError(state,
    2601            0 :                                           format(" Calculated minimum air flow rate: {:.3R} m3/s.", this->MaxAirVolFlowRate * MinAirFlowFracDes));
    2602            0 :                         MinAirFlowFracDes = 1.0;
    2603              :                     }
    2604              :                 }
    2605              :             }
    2606              :         }
    2607           41 :         if (IsAutoSize) {
    2608              :             // report out autosized result and save value in Sys array
    2609           30 :             BaseSizer::reportSizerOutput(state,
    2610              :                                          this->sysType,
    2611              :                                          this->SysName,
    2612              :                                          "Design Size Constant Minimum Air Flow Fraction",
    2613           15 :                                          MinAirFlowFracDes * this->ZoneTurndownMinAirFrac);
    2614           15 :             if (SizingDesRunThisAirSys) {
    2615            3 :                 if (state.dataSize->SysSizInput(SysSizNum).SystemOAMethod == SysOAMethod::SP) {
    2616            3 :                     state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).VpzMinByZoneSPSized = true;
    2617              :                 }
    2618              :             }
    2619           15 :             this->ZoneMinAirFracDes = MinAirFlowFracDes;
    2620              :         } else {
    2621              :             // report out hard (user set) value and issue warning if appropriate
    2622           26 :             MinAirFlowFracUser = this->ZoneMinAirFracDes;
    2623           52 :             BaseSizer::reportSizerOutput(state,
    2624              :                                          this->sysType,
    2625              :                                          this->SysName,
    2626              :                                          "Design Size Constant Minimum Air Flow Fraction",
    2627           26 :                                          MinAirFlowFracDes * this->ZoneTurndownMinAirFrac,
    2628              :                                          "User-Specified Constant Minimum Air Flow Fraction",
    2629           26 :                                          MinAirFlowFracUser * this->ZoneTurndownMinAirFrac);
    2630           26 :             if (state.dataGlobal->DisplayExtraWarnings) {
    2631           10 :                 if ((MinAirFlowFracUser > 0.0) &&
    2632            4 :                     ((std::abs(MinAirFlowFracDes - MinAirFlowFracUser) / MinAirFlowFracUser) > state.dataSize->AutoVsHardSizingThreshold)) {
    2633            8 :                     ShowMessage(state,
    2634            8 :                                 format("SizeHVACSingleDuct: Potential issue with equipment sizing for {} = \"{}\".", this->sysType, this->SysName));
    2635            4 :                     ShowContinueError(state, format("User-Specified Minimum Cooling Air Flow Fraction of {:.5R}", MinAirFlowFracUser));
    2636            4 :                     ShowContinueError(state, format("differs from Design Size Minimum Cooling Air Flow Fraction of {:.5R}", MinAirFlowFracDes));
    2637            8 :                     ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
    2638           12 :                     ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
    2639              :                 }
    2640              :             }
    2641              :         }
    2642              :         // report out the min air flow rate set by min air flow frac
    2643           82 :         BaseSizer::reportSizerOutput(state,
    2644              :                                      this->sysType,
    2645              :                                      this->SysName,
    2646              :                                      "Design Size Minimum Air Flow Rate [m3/s]",
    2647           41 :                                      this->MaxAirVolFlowRate * this->ZoneMinAirFracDes * this->ZoneTurndownMinAirFrac);
    2648              :     } else {
    2649           15 :         if (IsAutoSize) {
    2650            1 :             this->ZoneMinAirFracDes = 0.0;
    2651              :         }
    2652              :     }
    2653              : 
    2654           56 :     IsAutoSize = false;
    2655           56 :     if (this->ZoneFixedMinAir == AutoSize) {
    2656           32 :         IsAutoSize = true;
    2657              :     }
    2658           56 :     if (this->ZoneMinAirFracMethod == MinFlowFraction::Fixed) {
    2659            3 :         if (state.dataSize->ZoneSizingRunDone) {
    2660            3 :             if (state.dataSize->CurTermUnitSizingNum > 0) {
    2661              :                 // use the combined defaults or other user inputs stored in DesCoolVolFlowMin
    2662            3 :                 if (this->MaxAirVolFlowRate > 0.0) {
    2663            3 :                     FixedMinAirDes = state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).DesCoolVolFlowMin;
    2664              :                 } else {
    2665            0 :                     MinAirFlowFracDes = 0.0;
    2666              :                 }
    2667              :             }
    2668              :         } else {
    2669              :             // if no zone sizing values available; use max of min frac = 0.2 and 0.000762 [m3/s-m2]
    2670            0 :             if (this->MaxAirVolFlowRate > 0.0) {
    2671            0 :                 FixedMinAirDes = max(0.2 * this->MaxAirVolFlowRate,
    2672            0 :                                      0.000762 * state.dataHeatBal->Zone(ZoneNum).FloorArea * state.dataHeatBal->Zone(ZoneNum).Multiplier *
    2673            0 :                                          state.dataHeatBal->Zone(ZoneNum).ListMultiplier);
    2674              :             } else {
    2675            0 :                 MinAirFlowFracDes = 0.0;
    2676              :             }
    2677              :         }
    2678            3 :         if (SizingDesRunThisAirSys) {
    2679            2 :             if (state.dataSize->SysSizInput(SysSizNum).SystemOAMethod == SysOAMethod::SP) { // 62.1 simplified procedure
    2680            2 :                 if (this->MaxAirVolFlowRate > 0.0) {
    2681            2 :                     FixedMinAirDes = 1.5 * max(state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).VozClgByZone,
    2682            2 :                                                state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).VozHtgByZone);
    2683              : 
    2684              :                     // adjust maximum flow rate
    2685            2 :                     if (FixedMinAirDes > this->MaxAirVolFlowRate && IsMaxFlowAutoSize) {
    2686            1 :                         this->MaxAirVolFlowRate = FixedMinAirDes;
    2687            2 :                         ShowWarningError(state,
    2688            2 :                                          format("SingleDuctSystem:SizeSys: Autosized maximum air flow rate for {} was increased to meet the zone "
    2689              :                                                 "primary air flow determined according to the ASHRAE Standard 62.1 Simplified Procedure.",
    2690            1 :                                                 this->SysName));
    2691            1 :                     } else if (FixedMinAirDes > this->MaxAirVolFlowRate) {
    2692            2 :                         ShowWarningError(state,
    2693            2 :                                          format("SingleDuctSystem:SizeSys: Maximum air flow rate for {} is potentially too low.", this->SysName));
    2694            2 :                         ShowContinueError(
    2695              :                             state,
    2696              :                             "The flow is lower than the minimum flow rate calculated following the ASHRAE Standard 62.1 Simplified Procedure:");
    2697            1 :                         ShowContinueError(state, format(" User-specified maximum air flow rate: {:.3R} m3/s.", this->MaxAirVolFlowRate));
    2698            1 :                         ShowContinueError(state, format(" Calculated minimum air flow rate: {:.3R} m3/s.", FixedMinAirDes));
    2699            1 :                         FixedMinAirDes = this->MaxAirVolFlowRate;
    2700              :                     }
    2701              :                 }
    2702              :             }
    2703              :         }
    2704            3 :         if (IsAutoSize) {
    2705              :             // report out autosized result and save value in Sys array
    2706            6 :             BaseSizer::reportSizerOutput(
    2707            3 :                 state, this->sysType, this->SysName, "Design Size Fixed Minimum Air Flow Rate [m3/s]", FixedMinAirDes * this->ZoneTurndownMinAirFrac);
    2708            3 :             if (SizingDesRunThisAirSys) {
    2709            2 :                 if (state.dataSize->SysSizInput(SysSizNum).SystemOAMethod == SysOAMethod::SP) {
    2710            2 :                     state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).VpzMinByZoneSPSized = true;
    2711              :                 }
    2712              :             }
    2713            3 :             this->ZoneFixedMinAir = FixedMinAirDes;
    2714              :         } else {
    2715              :             // report out hard (user set) value and issue warning if appropriate
    2716            0 :             FixedMinAirUser = this->ZoneFixedMinAir;
    2717            0 :             BaseSizer::reportSizerOutput(state,
    2718              :                                          this->sysType,
    2719              :                                          this->SysName,
    2720              :                                          "Design Size Fixed Minimum Air Flow Rate [m3/s]",
    2721            0 :                                          FixedMinAirDes * this->ZoneTurndownMinAirFrac,
    2722              :                                          "User-Specified Fixed Minimum Air Flow Rate [m3/s]",
    2723            0 :                                          FixedMinAirUser * this->ZoneTurndownMinAirFrac);
    2724            0 :             if (state.dataGlobal->DisplayExtraWarnings) {
    2725            0 :                 if ((std::abs(FixedMinAirDes - FixedMinAirUser) / FixedMinAirUser) > state.dataSize->AutoVsHardSizingThreshold) {
    2726            0 :                     ShowMessage(state,
    2727            0 :                                 format("SizeHVACSingleDuct: Potential issue with equipment sizing for {} = \"{}\".", this->sysType, this->SysName));
    2728            0 :                     ShowContinueError(state, format("User-Specified Minimum Cooling Air Flow Rate of {:.5R} [m3/s]", FixedMinAirUser));
    2729            0 :                     ShowContinueError(state, format("differs from Design Size Minimum Cooling Air Flow Rate of {:.5R} [m3/s]", FixedMinAirDes));
    2730            0 :                     ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
    2731            0 :                     ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
    2732              :                 }
    2733              :             }
    2734              :         }
    2735              :         // report out the min air flow frac set by the min air flow rate
    2736            3 :         if (this->MaxAirVolFlowRate > 0.0) {
    2737            6 :             BaseSizer::reportSizerOutput(state,
    2738              :                                          this->sysType,
    2739              :                                          this->SysName,
    2740              :                                          "Design Size Minimum Air Flow Fraction [m3/s]",
    2741            3 :                                          this->ZoneFixedMinAir * this->ZoneTurndownMinAirFrac / this->MaxAirVolFlowRate);
    2742              :         }
    2743              :     } else {
    2744           53 :         if (IsAutoSize) {
    2745           29 :             this->ZoneFixedMinAir = 0.0;
    2746              :         }
    2747              :     }
    2748              : 
    2749           56 :     if (this->ZoneMinAirFracMethod == MinFlowFraction::Scheduled) {
    2750              :         // need a value for sizing.
    2751            0 :         if (this->ConstantMinAirFracSetByUser) {
    2752            0 :             this->ZoneMinAirFracDes = this->DesignMinAirFrac;
    2753              :             // if both inputs are defined, use the max
    2754            0 :             if (this->FixedMinAirSetByUser) {
    2755            0 :                 this->ZoneMinAirFracDes = min(1.0, max(this->ZoneMinAirFracDes, SafeDivide(this->DesignFixedMinAir, this->MaxAirVolFlowRate)));
    2756              :             }
    2757              :             // if only fixed is defined, use the value
    2758            0 :         } else if (this->FixedMinAirSetByUser) {
    2759            0 :             this->ZoneMinAirFracDes = min(1.0, SafeDivide(this->DesignFixedMinAir, this->MaxAirVolFlowRate));
    2760              :         } else {
    2761              :             // use an average of min and max in schedule
    2762            0 :             this->ZoneMinAirFracDes = (this->zoneMinAirFracSched->getMinVal(state) + this->zoneMinAirFracSched->getMaxVal(state)) / 2.0;
    2763              :         }
    2764              :     }
    2765              : 
    2766           56 :     if (this->ZoneMinAirFracMethod == MinFlowFraction::Fixed) {
    2767              :         // need a value for sizing.
    2768            3 :         this->ZoneMinAirFracDes = min(1.0, SafeDivide(this->ZoneFixedMinAir, this->MaxAirVolFlowRate));
    2769              :     }
    2770              : 
    2771           56 :     if (this->DamperHeatingAction == Action::ReverseWithLimits) {
    2772           20 :         if (state.dataSize->ZoneSizingRunDone) {
    2773           17 :             if (state.dataSize->CurTermUnitSizingNum > 0) {
    2774              :                 // if zone sizing run done, set the design max reheat air flow to the value from the design calcs
    2775           17 :                 if (state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).DesHeatVolFlow >
    2776           17 :                     state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).DesHeatVolFlowMax) {
    2777            5 :                     MaxAirVolFlowRateDuringReheatDes =
    2778            5 :                         state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).DesHeatVolFlowMax;
    2779              :                 } else {
    2780           12 :                     MaxAirVolFlowRateDuringReheatDes = state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).DesHeatVolFlow;
    2781              :                 }
    2782              :             }
    2783              :         } else {
    2784              :             // if no design calc use 0.002032 [m3/s-m2] times floor area. That's .40 cfm/ft2
    2785            3 :             MaxAirVolFlowRateDuringReheatDes = min(0.002032 * this->ZoneFloorArea, this->MaxAirVolFlowRate);
    2786              :         }
    2787              :         // check that result is not greater than the max flow or less than the min flow.
    2788           20 :         MaxAirVolFlowRateDuringReheatDes = min(MaxAirVolFlowRateDuringReheatDes, this->MaxAirVolFlowRate);
    2789           20 :         MaxAirVolFlowRateDuringReheatDes = max(MaxAirVolFlowRateDuringReheatDes, (this->MaxAirVolFlowRate * this->ZoneMinAirFracDes));
    2790           20 :         if (this->MaxAirVolFlowRate > 0.0) {
    2791           20 :             MaxAirVolFractionDuringReheatDes = MaxAirVolFlowRateDuringReheatDes / this->MaxAirVolFlowRate;
    2792              :         } else {
    2793            0 :             MaxAirVolFractionDuringReheatDes = 0.0;
    2794              :         }
    2795           20 :         if (this->MaxAirVolFlowRateDuringReheat == Constant::AutoCalculate && this->MaxAirVolFractionDuringReheat == Constant::AutoCalculate) {
    2796              :             // if both inputs are autosize (the default) report both out and save in the Sys array.
    2797           18 :             BaseSizer::reportSizerOutput(
    2798              :                 state, this->sysType, this->SysName, "Design Size Maximum Flow Fraction during Reheat []", MaxAirVolFractionDuringReheatDes);
    2799           18 :             if (this->ZoneFloorArea > 0.0) {
    2800           24 :                 BaseSizer::reportSizerOutput(state,
    2801              :                                              this->sysType,
    2802              :                                              this->SysName,
    2803              :                                              "Design Size Maximum Flow per Zone Floor Area during Reheat [m3/s-m2]",
    2804           12 :                                              MaxAirVolFlowRateDuringReheatDes / this->ZoneFloorArea);
    2805              :             }
    2806           18 :             this->MaxAirVolFlowRateDuringReheat = MaxAirVolFlowRateDuringReheatDes;
    2807           18 :             this->MaxAirVolFractionDuringReheat = MaxAirVolFractionDuringReheatDes;
    2808            2 :         } else if (this->MaxAirVolFlowRateDuringReheat == Constant::AutoCalculate && this->MaxAirVolFractionDuringReheat != Constant::AutoCalculate) {
    2809              :             // if max reheat flow fraction was input, set the max reheat flow design value correspondingly, report both out.
    2810              :             // Check for optional caution message that user input value is not within 10% of the design value.
    2811            1 :             MaxAirVolFlowRateDuringReheatDes = this->MaxAirVolFractionDuringReheat * this->MaxAirVolFlowRate;
    2812            1 :             MaxAirVolFractionDuringReheatUser = this->MaxAirVolFractionDuringReheat;
    2813            1 :             BaseSizer::reportSizerOutput(state,
    2814              :                                          this->sysType,
    2815              :                                          this->SysName,
    2816              :                                          "Design Size Maximum Flow Fraction during Reheat []",
    2817              :                                          MaxAirVolFractionDuringReheatDes,
    2818              :                                          "User-Specified Maximum Flow Fraction during Reheat []",
    2819              :                                          MaxAirVolFractionDuringReheatUser);
    2820            1 :             if (this->ZoneFloorArea > 0.0) {
    2821            2 :                 BaseSizer::reportSizerOutput(state,
    2822              :                                              this->sysType,
    2823              :                                              this->SysName,
    2824              :                                              "Design Size Maximum Flow per Zone Floor Area during Reheat [m3/s-m2]",
    2825            1 :                                              MaxAirVolFlowRateDuringReheatDes / this->ZoneFloorArea);
    2826              :             }
    2827            1 :             this->MaxAirVolFlowRateDuringReheat = MaxAirVolFlowRateDuringReheatDes;
    2828            1 :             if (state.dataGlobal->DisplayExtraWarnings) {
    2829            0 :                 if ((std::abs(MaxAirVolFractionDuringReheatDes - MaxAirVolFractionDuringReheatUser) / MaxAirVolFractionDuringReheatUser) >
    2830            0 :                     state.dataSize->AutoVsHardSizingThreshold) {
    2831            0 :                     ShowMessage(state,
    2832            0 :                                 format("SizeHVACSingleDuct: Potential issue with equipment sizing for {} = \"{}\".", this->sysType, this->SysName));
    2833            0 :                     ShowContinueError(state,
    2834            0 :                                       format("User-Specified Maximum Flow Fraction during Reheat of {:.5R} []", MaxAirVolFractionDuringReheatUser));
    2835            0 :                     ShowContinueError(
    2836            0 :                         state, format("differs from Design Size Maximum Flow Fraction during Reheat of {:.5R} []", MaxAirVolFractionDuringReheatDes));
    2837            0 :                     ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
    2838            0 :                     ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
    2839              :                 }
    2840              :             }
    2841            1 :         } else if (this->MaxAirVolFlowRateDuringReheat != Constant::AutoCalculate && this->MaxAirVolFractionDuringReheat == Constant::AutoCalculate) {
    2842              :             // if max reheat flow was input set the design max reheat flow frac to the corresponding value, report both out, save the design value
    2843              :             // of the flow frac in Sys. Check for optional caution message that user input value is not within 10% of the design value.
    2844            0 :             if (this->MaxAirVolFlowRate > 0.0) {
    2845            0 :                 MaxAirVolFractionDuringReheatDes = MaxAirVolFlowRateDuringReheatDes / this->MaxAirVolFlowRate;
    2846              :             } else {
    2847            0 :                 MaxAirVolFractionDuringReheatDes = 0.0;
    2848              :             }
    2849            0 :             MaxAirVolFlowRateDuringReheatUser = this->MaxAirVolFlowRateDuringReheat;
    2850            0 :             BaseSizer::reportSizerOutput(
    2851              :                 state, this->sysType, this->SysName, "Design Size Maximum Flow Fraction during Reheat []", MaxAirVolFractionDuringReheatDes);
    2852            0 :             if (this->ZoneFloorArea > 0.0) {
    2853            0 :                 BaseSizer::reportSizerOutput(state,
    2854              :                                              this->sysType,
    2855              :                                              this->SysName,
    2856              :                                              "Design Size Maximum Flow per Zone Floor Area during Reheat [ m3/s-m2 ]",
    2857            0 :                                              MaxAirVolFlowRateDuringReheatDes / this->ZoneFloorArea,
    2858              :                                              "User-Specified Maximum Flow per Zone Floor Area during Reheat [m3/s-m2]",
    2859            0 :                                              MaxAirVolFlowRateDuringReheatUser / this->ZoneFloorArea);
    2860              :             }
    2861            0 :             this->MaxAirVolFractionDuringReheat = MaxAirVolFractionDuringReheatDes;
    2862            0 :             if (state.dataGlobal->DisplayExtraWarnings) {
    2863            0 :                 if ((std::abs(MaxAirVolFlowRateDuringReheatDes - MaxAirVolFlowRateDuringReheatUser) / MaxAirVolFlowRateDuringReheatUser) >
    2864            0 :                     state.dataSize->AutoVsHardSizingThreshold) {
    2865            0 :                     ShowMessage(state,
    2866            0 :                                 format("SizeHVACSingleDuct: Potential issue with equipment sizing for {} = \"{}\".", this->sysType, this->SysName));
    2867            0 :                     ShowContinueError(state,
    2868            0 :                                       format("User-Specified Maximum Flow per Zone Floor Area during Reheat of {:.5R} [m3/s-m2]",
    2869              :                                              MaxAirVolFlowRateDuringReheatUser));
    2870            0 :                     ShowContinueError(state,
    2871            0 :                                       format("differs from Design Size Maximum Flow per Zone Floor Area during Reheat of {:.5R} [m3/s-m2]",
    2872              :                                              MaxAirVolFlowRateDuringReheatDes));
    2873            0 :                     ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
    2874            0 :                     ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
    2875              :                 }
    2876              :             }
    2877              :         } else {
    2878              :             // both fields have user input. Report both out, use the larger of the 2 values. Note that only sd_airterminal( SysNum
    2879              :             // ).MaxAirVolFlowRateDuringReheat is used subsequently. Check both inputs for optional caution message that user input value is not
    2880              :             // within 10% of the design value.
    2881            1 :             MaxAirVolFlowRateDuringReheatUser = this->MaxAirVolFlowRateDuringReheat;
    2882            1 :             MaxAirVolFractionDuringReheatUser = this->MaxAirVolFractionDuringReheat;
    2883            1 :             BaseSizer::reportSizerOutput(state,
    2884              :                                          this->sysType,
    2885              :                                          this->SysName,
    2886              :                                          "Design Size Maximum Flow Fraction during Reheat []",
    2887              :                                          MaxAirVolFractionDuringReheatDes,
    2888              :                                          "User-Specified Maximum Flow Fraction during Reheat []",
    2889              :                                          MaxAirVolFractionDuringReheatUser);
    2890            1 :             if (this->ZoneFloorArea > 0.0) {
    2891            0 :                 BaseSizer::reportSizerOutput(state,
    2892              :                                              this->sysType,
    2893              :                                              this->SysName,
    2894              :                                              "Design Size Maximum Flow per Zone Floor Area during Reheat [m3/s-m2]",
    2895            0 :                                              MaxAirVolFlowRateDuringReheatDes / this->ZoneFloorArea,
    2896              :                                              "User-Specified Maximum Flow per Zone Floor Area during Reheat [m3/s-m2]",
    2897            0 :                                              MaxAirVolFlowRateDuringReheatUser / this->ZoneFloorArea);
    2898              :             }
    2899            1 :             this->MaxAirVolFlowRateDuringReheat =
    2900            1 :                 max(this->MaxAirVolFlowRateDuringReheat, this->MaxAirVolFractionDuringReheat * this->MaxAirVolFlowRate);
    2901            1 :             if (state.dataGlobal->DisplayExtraWarnings) {
    2902            0 :                 if ((std::abs(MaxAirVolFractionDuringReheatDes - MaxAirVolFractionDuringReheatUser) / MaxAirVolFractionDuringReheatUser) >
    2903            0 :                     state.dataSize->AutoVsHardSizingThreshold) {
    2904            0 :                     ShowMessage(state,
    2905            0 :                                 format("SizeHVACSingleDuct: Potential issue with equipment sizing for {} = \"{}\".", this->sysType, this->SysName));
    2906            0 :                     ShowContinueError(state,
    2907            0 :                                       format("User-Specified Maximum Flow Fraction during Reheat of {:.5R} []", MaxAirVolFractionDuringReheatUser));
    2908            0 :                     ShowContinueError(
    2909            0 :                         state, format("differs from Design Size Maximum Flow Fraction during Reheat of {:.5R} []", MaxAirVolFractionDuringReheatDes));
    2910            0 :                     ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
    2911            0 :                     ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
    2912              :                 }
    2913              :             }
    2914            1 :             if (state.dataGlobal->DisplayExtraWarnings) {
    2915            0 :                 if ((std::abs(MaxAirVolFlowRateDuringReheatDes - MaxAirVolFlowRateDuringReheatUser) / MaxAirVolFlowRateDuringReheatUser) >
    2916            0 :                     state.dataSize->AutoVsHardSizingThreshold) {
    2917            0 :                     ShowMessage(state,
    2918            0 :                                 format("SizeHVACSingleDuct: Potential issue with equipment sizing for {} = \"{}\".", this->sysType, this->SysName));
    2919            0 :                     ShowContinueError(state,
    2920            0 :                                       format("User-Specified Maximum Flow per Zone Floor Area during Reheat of {:.5R} [m3/s-m2]",
    2921              :                                              MaxAirVolFlowRateDuringReheatUser));
    2922            0 :                     ShowContinueError(state,
    2923            0 :                                       format("differs from Design Size Maximum Flow per Zone Floor Area during Reheat of {:.5R} [m3/s-m2]",
    2924              :                                              MaxAirVolFlowRateDuringReheatDes));
    2925            0 :                     ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
    2926            0 :                     ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
    2927              :                 }
    2928              :             }
    2929              :         }
    2930              :         // check that MaxAirVolFlowRateDuringReheat is greater than the min and less than the max
    2931           20 :         this->MaxAirVolFlowRateDuringReheat = min(MaxAirVolFlowRateDuringReheatDes, this->MaxAirVolFlowRate);
    2932           20 :         this->MaxAirVolFlowRateDuringReheat = max(MaxAirVolFlowRateDuringReheatDes, (this->MaxAirVolFlowRate * this->ZoneMinAirFracDes));
    2933           36 :     } else if (this->DamperHeatingAction == Action::Normal) {
    2934              :         // for Normal action, max reheat flow is equal to the minimum. Report it.
    2935            1 :         if (this->ZoneFloorArea > 0.0) {
    2936            0 :             BaseSizer::reportSizerOutput(state,
    2937              :                                          this->sysType,
    2938              :                                          this->SysName,
    2939              :                                          "Design Size Maximum Flow per Zone Floor Area during Reheat [m3/s-m2]",
    2940            0 :                                          (this->MaxAirVolFlowRate * this->ZoneMinAirFracDes) / this->ZoneFloorArea);
    2941              :         }
    2942            1 :         BaseSizer::reportSizerOutput(
    2943              :             state, this->sysType, this->SysName, "Design Size Maximum Flow Fraction during Reheat []", this->ZoneMinAirFracDes);
    2944              :         // zero the ReverseActioWithLimits inputs
    2945            1 :         this->MaxAirVolFlowRateDuringReheat = max(this->MaxAirVolFlowRateDuringReheat, 0.0);
    2946            1 :         this->MaxAirVolFractionDuringReheat = max(this->MaxAirVolFractionDuringReheat, 0.0);
    2947           35 :     } else if (this->DamperHeatingAction == Action::Reverse) {
    2948              :         // for ReverseAction, max reheat flow is equal to the maximum. Report it.
    2949            4 :         if (this->ZoneFloorArea > 0.0) {
    2950            4 :             BaseSizer::reportSizerOutput(state,
    2951              :                                          this->sysType,
    2952              :                                          this->SysName,
    2953              :                                          "Design Size Maximum Flow per Zone Floor Area during Reheat [m3/s-m2]",
    2954            2 :                                          this->MaxAirVolFlowRate / this->ZoneFloorArea);
    2955              :         }
    2956            4 :         BaseSizer::reportSizerOutput(state, this->sysType, this->SysName, "Design Size Maximum Flow Fraction during Reheat []", 1.0);
    2957              :         // zero the ReverseActioWithLimits inputs
    2958            4 :         this->MaxAirVolFlowRateDuringReheat = max(this->MaxAirVolFlowRateDuringReheat, 0.0);
    2959            4 :         this->MaxAirVolFractionDuringReheat = max(this->MaxAirVolFractionDuringReheat, 0.0);
    2960              :     }
    2961              : 
    2962           56 :     if (state.dataSize->CurTermUnitSizingNum > 0) {
    2963           48 :         TermUnitSizing(state.dataSize->CurTermUnitSizingNum).ReheatAirFlowMult = 1.0;
    2964           48 :         TermUnitSizing(state.dataSize->CurTermUnitSizingNum).ReheatLoadMult = 1.0;
    2965           48 :         if (state.dataSize->ZoneSizingRunDone) {
    2966              :             // set air flow rate used to size heating coils, ZoneTurndownMinAirFrac defaults to 1 for those TU types that do not use it
    2967           41 :             if (this->SysType_Num == SysType::SingleDuctVAVReheatVSFan) {
    2968            0 :                 TermUnitSizing(state.dataSize->CurTermUnitSizingNum).AirVolFlow =
    2969            0 :                     max(state.dataSingleDuct->UserInputMaxHeatAirVolFlowRateSS,
    2970            0 :                         state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).NonAirSysDesHeatVolFlow,
    2971            0 :                         this->MaxAirVolFlowRate * this->ZoneMinAirFracDes * this->ZoneTurndownMinAirFrac);
    2972           41 :             } else if (this->SysType_Num == SysType::SingleDuctConstVolReheat || this->SysType_Num == SysType::SingleDuctConstVolNoReheat) {
    2973           10 :                 TermUnitSizing(state.dataSize->CurTermUnitSizingNum).AirVolFlow =
    2974           10 :                     max(state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).NonAirSysDesHeatVolFlow,
    2975           10 :                         this->MaxAirVolFlowRate * this->ZoneTurndownMinAirFrac);
    2976              :             } else {
    2977           31 :                 if (this->SysType_Num == SysType::SingleDuctVAVReheat && this->DamperHeatingAction == Action::ReverseWithLimits) {
    2978           17 :                     TermUnitSizing(state.dataSize->CurTermUnitSizingNum).AirVolFlow = this->MaxAirVolFlowRateDuringReheat;
    2979              :                 } else {
    2980           14 :                     TermUnitSizing(state.dataSize->CurTermUnitSizingNum).AirVolFlow =
    2981           14 :                         max(state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).NonAirSysDesHeatVolFlow,
    2982           14 :                             this->MaxAirVolFlowRate * this->ZoneMinAirFracDes * this->ZoneTurndownMinAirFrac);
    2983              :                 }
    2984              :             }
    2985              :         } else {
    2986            7 :             if (this->SysType_Num == SysType::SingleDuctVAVReheatVSFan) {
    2987            0 :                 TermUnitSizing(state.dataSize->CurTermUnitSizingNum).AirVolFlow =
    2988            0 :                     max(this->MaxHeatAirVolFlowRate, this->MaxAirVolFlowRate * this->ZoneMinAirFracDes * this->ZoneTurndownMinAirFrac);
    2989            7 :             } else if (this->SysType_Num == SysType::SingleDuctConstVolReheat || this->SysType_Num == SysType::SingleDuctConstVolNoReheat) {
    2990            2 :                 TermUnitSizing(state.dataSize->CurTermUnitSizingNum).AirVolFlow = this->MaxAirVolFlowRate;
    2991              :             } else {
    2992            5 :                 if (this->DamperHeatingAction == Action::Reverse) {
    2993            2 :                     TermUnitSizing(state.dataSize->CurTermUnitSizingNum).AirVolFlow = this->MaxAirVolFlowRate;
    2994            3 :                 } else if (this->DamperHeatingAction == Action::ReverseWithLimits) {
    2995            1 :                     TermUnitSizing(state.dataSize->CurTermUnitSizingNum).AirVolFlow =
    2996            1 :                         max(this->MaxAirVolFlowRateDuringReheat, (this->MaxAirVolFlowRate * this->ZoneMinAirFracDes * this->ZoneTurndownMinAirFrac));
    2997              :                 } else {
    2998            2 :                     TermUnitSizing(state.dataSize->CurTermUnitSizingNum).AirVolFlow =
    2999            2 :                         this->MaxAirVolFlowRate * this->ZoneMinAirFracDes * this->ZoneTurndownMinAirFrac;
    3000              :                 }
    3001              :             }
    3002              :         }
    3003              : 
    3004           48 :         if (TermUnitSizing(state.dataSize->CurTermUnitSizingNum).AirVolFlow > SmallAirVolFlow) {
    3005           45 :             if (this->DamperHeatingAction == Action::ReverseWithLimits) {
    3006           18 :                 TermUnitSizing(state.dataSize->CurTermUnitSizingNum).ReheatAirFlowMult =
    3007           18 :                     min(this->MaxAirVolFlowRateDuringReheat, this->MaxAirVolFlowRate) /
    3008           18 :                     TermUnitSizing(state.dataSize->CurTermUnitSizingNum).AirVolFlow;
    3009           18 :                 TermUnitSizing(state.dataSize->CurTermUnitSizingNum).ReheatLoadMult =
    3010           18 :                     TermUnitSizing(state.dataSize->CurTermUnitSizingNum).ReheatAirFlowMult;
    3011           27 :             } else if (this->DamperHeatingAction == Action::Reverse) {
    3012            2 :                 TermUnitSizing(state.dataSize->CurTermUnitSizingNum).ReheatAirFlowMult =
    3013            2 :                     this->MaxAirVolFlowRate / TermUnitSizing(state.dataSize->CurTermUnitSizingNum).AirVolFlow;
    3014            2 :                 TermUnitSizing(state.dataSize->CurTermUnitSizingNum).ReheatLoadMult =
    3015            2 :                     TermUnitSizing(state.dataSize->CurTermUnitSizingNum).ReheatAirFlowMult;
    3016           25 :             } else if (this->DamperHeatingAction == Action::Normal && this->MaxAirVolFlowRateDuringReheat > 0.0) {
    3017            0 :                 TermUnitSizing(state.dataSize->CurTermUnitSizingNum).ReheatAirFlowMult =
    3018            0 :                     min(this->MaxAirVolFlowRateDuringReheat, (this->MaxAirVolFlowRate * this->ZoneMinAirFracDes * this->ZoneTurndownMinAirFrac)) /
    3019            0 :                     TermUnitSizing(state.dataSize->CurTermUnitSizingNum).AirVolFlow;
    3020            0 :                 TermUnitSizing(state.dataSize->CurTermUnitSizingNum).ReheatLoadMult = 1.0;
    3021           25 :             } else if (this->DamperHeatingAction == Action::Normal && this->MaxAirVolFlowRateDuringReheat == 0.0) {
    3022            0 :                 TermUnitSizing(state.dataSize->CurTermUnitSizingNum).ReheatAirFlowMult =
    3023            0 :                     (this->MaxAirVolFlowRate * this->ZoneMinAirFracDes * this->ZoneTurndownMinAirFrac) /
    3024            0 :                     TermUnitSizing(state.dataSize->CurTermUnitSizingNum).AirVolFlow;
    3025            0 :                 TermUnitSizing(state.dataSize->CurTermUnitSizingNum).ReheatLoadMult = 1.0;
    3026              :             } else {
    3027           25 :                 TermUnitSizing(state.dataSize->CurTermUnitSizingNum).ReheatAirFlowMult =
    3028           25 :                     this->MaxAirVolFlowRate / TermUnitSizing(state.dataSize->CurTermUnitSizingNum).AirVolFlow;
    3029           25 :                 TermUnitSizing(state.dataSize->CurTermUnitSizingNum).ReheatLoadMult =
    3030           25 :                     TermUnitSizing(state.dataSize->CurTermUnitSizingNum).ReheatAirFlowMult;
    3031              :             }
    3032           45 :             TermUnitSizing(state.dataSize->CurTermUnitSizingNum).ReheatAirFlowMult =
    3033           45 :                 max(1.0, TermUnitSizing(state.dataSize->CurTermUnitSizingNum).ReheatAirFlowMult);
    3034           45 :             TermUnitSizing(state.dataSize->CurTermUnitSizingNum).ReheatLoadMult =
    3035           45 :                 max(1.0, TermUnitSizing(state.dataSize->CurTermUnitSizingNum).ReheatLoadMult);
    3036              :         } else {
    3037            3 :             TermUnitSizing(state.dataSize->CurTermUnitSizingNum).ReheatAirFlowMult = 1.0;
    3038            3 :             TermUnitSizing(state.dataSize->CurTermUnitSizingNum).ReheatLoadMult = 1.0;
    3039              :         }
    3040           48 :         if (this->ReheatComp_Index > 0) {
    3041           22 :             state.dataRptCoilSelection->coilSelectionReportObj->setCoilReheatMultiplier(
    3042           22 :                 state, this->ReheatName, this->ReheatComp, TermUnitSizing(state.dataSize->CurTermUnitSizingNum).ReheatLoadMult);
    3043              :         }
    3044              :     }
    3045              : 
    3046           56 :     IsAutoSize = false;
    3047           56 :     if (this->MaxReheatWaterVolFlow == AutoSize) {
    3048            8 :         IsAutoSize = true;
    3049              :     }
    3050           56 :     if (state.dataSize->CurTermUnitSizingNum > 0) {
    3051           48 :         if (!IsAutoSize && !state.dataSize->ZoneSizingRunDone) {
    3052            7 :             if (this->MaxReheatWaterVolFlow > 0.0) {
    3053            2 :                 BaseSizer::reportSizerOutput(
    3054              :                     state, this->sysType, this->SysName, "User-Specified Maximum Reheat Water Flow Rate [m3/s]", this->MaxReheatWaterVolFlow);
    3055              :             }
    3056              :         } else {
    3057           41 :             CheckZoneSizing(state, this->sysType, this->SysName);
    3058           41 :             if (Util::SameString(this->ReheatComp, "Coil:Heating:Water")) {
    3059            5 :                 state.dataSingleDuct->CoilWaterInletNodeSS = GetCoilWaterInletNode(state, "Coil:Heating:Water", this->ReheatName, ErrorsFound);
    3060            5 :                 state.dataSingleDuct->CoilWaterOutletNodeSS = GetCoilWaterOutletNode(state, "Coil:Heating:Water", this->ReheatName, ErrorsFound);
    3061            5 :                 if (IsAutoSize) {
    3062            5 :                     PlantSizingErrorsFound = false;
    3063            5 :                     PltSizHeatNum = MyPlantSizingIndex(state,
    3064              :                                                        "Coil:Heating:Water",
    3065              :                                                        this->ReheatName,
    3066            5 :                                                        state.dataSingleDuct->CoilWaterInletNodeSS,
    3067            5 :                                                        state.dataSingleDuct->CoilWaterOutletNodeSS,
    3068              :                                                        PlantSizingErrorsFound);
    3069            5 :                     if (PlantSizingErrorsFound) {
    3070            0 :                         ShowContinueError(state, format("...Occurs in {}:{}", this->sysType, this->SysName));
    3071            0 :                         ErrorsFound = true;
    3072              :                     }
    3073            5 :                     if (PltSizHeatNum > 0) {
    3074           10 :                         state.dataSingleDuct->CoilInTempSS =
    3075            5 :                             state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).DesHeatCoilInTempTU;
    3076            5 :                         DesMassFlow = state.dataEnvrn->StdRhoAir * TermUnitSizing(state.dataSize->CurTermUnitSizingNum).AirVolFlow;
    3077           10 :                         state.dataSingleDuct->DesZoneHeatLoadSS =
    3078            5 :                             state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).NonAirSysDesHeatLoad;
    3079           10 :                         state.dataSingleDuct->ZoneDesTempSS =
    3080            5 :                             state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).ZoneTempAtHeatPeak;
    3081           10 :                         state.dataSingleDuct->ZoneDesHumRatSS =
    3082            5 :                             state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).ZoneHumRatAtHeatPeak;
    3083              :                         // the coil load is the zone design heating load plus (or minus!) the reheat load
    3084           10 :                         state.dataSingleDuct->DesCoilLoadSS =
    3085            5 :                             state.dataSingleDuct->DesZoneHeatLoadSS + PsyCpAirFnW(state.dataSingleDuct->ZoneDesHumRatSS) * DesMassFlow *
    3086            5 :                                                                           (state.dataSingleDuct->ZoneDesTempSS - state.dataSingleDuct->CoilInTempSS);
    3087            5 :                         if (state.dataSingleDuct->DesCoilLoadSS >= SmallLoad) {
    3088              : 
    3089              :                             rho =
    3090            5 :                                 state.dataPlnt->PlantLoop(this->HWplantLoc.loopNum).glycol->getDensity(state, Constant::HWInitConvTemp, RoutineName);
    3091              : 
    3092            5 :                             Cp = state.dataPlnt->PlantLoop(this->HWplantLoc.loopNum)
    3093            5 :                                      .glycol->getSpecificHeat(state, Constant::HWInitConvTemp, RoutineName);
    3094              : 
    3095            5 :                             MaxReheatWaterVolFlowDes =
    3096            5 :                                 state.dataSingleDuct->DesCoilLoadSS / (state.dataSize->PlantSizData(PltSizHeatNum).DeltaT * Cp * rho);
    3097              :                         } else {
    3098            0 :                             MaxReheatWaterVolFlowDes = 0.0;
    3099              :                         }
    3100              :                     } else {
    3101            0 :                         ShowSevereError(state, "Autosizing of water flow requires a heating loop Sizing:Plant object");
    3102            0 :                         ShowContinueError(state, format("Occurs in AirTerminal Object={}", this->SysName));
    3103            0 :                         ErrorsFound = true;
    3104              :                     }
    3105            5 :                     this->MaxReheatWaterVolFlow = MaxReheatWaterVolFlowDes;
    3106            5 :                     BaseSizer::reportSizerOutput(
    3107              :                         state, this->sysType, this->SysName, "Design Size Maximum Reheat Water Flow Rate [m3/s]", MaxReheatWaterVolFlowDes);
    3108           10 :                     BaseSizer::reportSizerOutput(state,
    3109              :                                                  this->sysType,
    3110              :                                                  this->SysName,
    3111              :                                                  "Design Size Reheat Coil Sizing Air Volume Flow Rate [m3/s]",
    3112            5 :                                                  TermUnitSizing(state.dataSize->CurTermUnitSizingNum).AirVolFlow);
    3113           10 :                     BaseSizer::reportSizerOutput(state,
    3114              :                                                  this->sysType,
    3115              :                                                  this->SysName,
    3116              :                                                  "Design Size Reheat Coil Sizing Inlet Air Temperature [C]",
    3117            5 :                                                  state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).DesHeatCoilInTempTU);
    3118           10 :                     BaseSizer::reportSizerOutput(state,
    3119              :                                                  this->sysType,
    3120              :                                                  this->SysName,
    3121              :                                                  "Design Size Reheat Coil Sizing Inlet Air Humidity Ratio [kgWater/kgDryAir]",
    3122            5 :                                                  state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).DesHeatCoilInHumRatTU);
    3123              :                 } else { // Hard-size with sizing data
    3124            0 :                     if (this->MaxReheatWaterVolFlow > 0.0 && MaxReheatWaterVolFlowDes > 0.0) {
    3125            0 :                         MaxReheatWaterVolFlowUser = this->MaxReheatWaterVolFlow;
    3126            0 :                         BaseSizer::reportSizerOutput(state,
    3127              :                                                      this->sysType,
    3128              :                                                      this->SysName,
    3129              :                                                      "Design Size Maximum Reheat Water Flow Rate [m3/s]",
    3130              :                                                      MaxReheatWaterVolFlowDes,
    3131              :                                                      "User-Specified Maximum Reheat Water Flow Rate [m3/s]",
    3132              :                                                      MaxReheatWaterVolFlowUser);
    3133            0 :                         if (state.dataGlobal->DisplayExtraWarnings) {
    3134            0 :                             if ((std::abs(MaxReheatWaterVolFlowDes - MaxReheatWaterVolFlowUser) / MaxReheatWaterVolFlowUser) >
    3135            0 :                                 state.dataSize->AutoVsHardSizingThreshold) {
    3136            0 :                                 ShowMessage(state,
    3137            0 :                                             format("SizeHVACSingleDuct: Potential issue with equipment sizing for {} = \"{}\".",
    3138            0 :                                                    this->sysType,
    3139            0 :                                                    this->SysName));
    3140            0 :                                 ShowContinueError(
    3141            0 :                                     state, format("User-Specified Maximum Reheat Water Flow Rate of {:.5R} [m3/s]", MaxReheatWaterVolFlowUser));
    3142            0 :                                 ShowContinueError(
    3143              :                                     state,
    3144            0 :                                     format("differs from Design Size Maximum Reheat Water Flow Rate of {:.5R} [m3/s]", MaxReheatWaterVolFlowDes));
    3145            0 :                                 ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
    3146            0 :                                 ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
    3147              :                             }
    3148              :                         }
    3149              :                     }
    3150              :                 }
    3151              :             }
    3152              :         }
    3153              :     } else {
    3154            8 :         this->MaxReheatWaterVolFlow = 0.0;
    3155              :     }
    3156              : 
    3157           56 :     IsAutoSize = false;
    3158           56 :     if (this->MaxReheatSteamVolFlow == AutoSize) {
    3159            0 :         IsAutoSize = true;
    3160              :     }
    3161           56 :     if (state.dataSize->CurTermUnitSizingNum > 0) {
    3162           48 :         if (!IsAutoSize && !state.dataSize->ZoneSizingRunDone) {
    3163            7 :             if (this->MaxReheatSteamVolFlow > 0.0) {
    3164            0 :                 BaseSizer::reportSizerOutput(
    3165              :                     state, this->sysType, this->SysName, "User-Specified Maximum Reheat Steam Flow Rate [m3/s]", this->MaxReheatSteamVolFlow);
    3166              :             }
    3167              :         } else {
    3168           41 :             CheckZoneSizing(state, this->sysType, this->SysName);
    3169           41 :             if (Util::SameString(this->ReheatComp, "Coil:Heating:Steam")) {
    3170            0 :                 state.dataSingleDuct->CoilSteamInletNodeSS = GetCoilSteamInletNode(state, "Coil:Heating:Steam", this->ReheatName, ErrorsFound);
    3171            0 :                 state.dataSingleDuct->CoilSteamOutletNodeSS = GetCoilSteamOutletNode(state, "Coil:Heating:Steam", this->ReheatName, ErrorsFound);
    3172            0 :                 if (IsAutoSize) {
    3173            0 :                     PlantSizingErrorsFound = false;
    3174            0 :                     PltSizHeatNum = MyPlantSizingIndex(state,
    3175              :                                                        "Coil:Heating:Steam",
    3176              :                                                        this->ReheatName,
    3177            0 :                                                        state.dataSingleDuct->CoilSteamInletNodeSS,
    3178            0 :                                                        state.dataSingleDuct->CoilSteamOutletNodeSS,
    3179              :                                                        PlantSizingErrorsFound);
    3180            0 :                     if (PlantSizingErrorsFound) {
    3181            0 :                         ShowContinueError(state, format("...Occurs in {}:{}", this->sysType, this->SysName));
    3182            0 :                         ErrorsFound = true;
    3183              :                     }
    3184            0 :                     if (PltSizHeatNum > 0) {
    3185            0 :                         state.dataSingleDuct->CoilInTempSS =
    3186            0 :                             state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).DesHeatCoilInTempTU;
    3187            0 :                         DesMassFlow = state.dataEnvrn->StdRhoAir * TermUnitSizing(state.dataSize->CurTermUnitSizingNum).AirVolFlow;
    3188            0 :                         state.dataSingleDuct->DesZoneHeatLoadSS =
    3189            0 :                             state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).NonAirSysDesHeatLoad;
    3190            0 :                         state.dataSingleDuct->ZoneDesTempSS =
    3191            0 :                             state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).ZoneTempAtHeatPeak;
    3192            0 :                         state.dataSingleDuct->ZoneDesHumRatSS =
    3193            0 :                             state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).ZoneHumRatAtHeatPeak;
    3194              :                         // the coil load is the zone design heating load plus (or minus!) the reheat load
    3195            0 :                         state.dataSingleDuct->DesCoilLoadSS =
    3196            0 :                             state.dataSingleDuct->DesZoneHeatLoadSS + PsyCpAirFnW(state.dataSingleDuct->ZoneDesHumRatSS) * DesMassFlow *
    3197            0 :                                                                           (state.dataSingleDuct->ZoneDesTempSS - state.dataSingleDuct->CoilInTempSS);
    3198            0 :                         if (state.dataSingleDuct->DesCoilLoadSS >= SmallLoad) {
    3199            0 :                             TempSteamIn = 100.00;
    3200            0 :                             auto *steam = Fluid::GetSteam(state);
    3201            0 :                             EnthSteamInDry = steam->getSatEnthalpy(state, TempSteamIn, 1.0, RoutineNameFull);
    3202            0 :                             EnthSteamOutWet = steam->getSatEnthalpy(state, TempSteamIn, 0.0, RoutineNameFull);
    3203            0 :                             LatentHeatSteam = EnthSteamInDry - EnthSteamOutWet;
    3204            0 :                             SteamDensity = steam->getSatDensity(state, TempSteamIn, 1.0, RoutineNameFull);
    3205              : 
    3206            0 :                             Cp = Fluid::GetWater(state)->getSpecificHeat(state, state.dataSize->PlantSizData(PltSizHeatNum).ExitTemp, RoutineName);
    3207            0 :                             MaxReheatSteamVolFlowDes = state.dataSingleDuct->DesCoilLoadSS /
    3208            0 :                                                        (SteamDensity * (LatentHeatSteam + state.dataSize->PlantSizData(PltSizHeatNum).DeltaT * Cp));
    3209              :                         } else {
    3210            0 :                             MaxReheatSteamVolFlowDes = 0.0;
    3211              :                         }
    3212              :                     } else {
    3213            0 :                         ShowSevereError(state, "Autosizing of Steam flow requires a heating loop Sizing:Plant object");
    3214            0 :                         ShowContinueError(state, format("Occurs in AirTerminal:SingleDuct:ConstantVolume:Reheat Object={}", this->SysName));
    3215            0 :                         ErrorsFound = true;
    3216              :                     }
    3217            0 :                     this->MaxReheatSteamVolFlow = MaxReheatSteamVolFlowDes;
    3218            0 :                     BaseSizer::reportSizerOutput(
    3219              :                         state, this->sysType, this->SysName, "Design Size Maximum Reheat Steam Flow Rate [m3/s]", MaxReheatSteamVolFlowDes);
    3220              :                 } else {
    3221            0 :                     if (this->MaxReheatSteamVolFlow > 0.0 && MaxReheatSteamVolFlowDes > 0.0) {
    3222            0 :                         MaxReheatSteamVolFlowUser = this->MaxReheatSteamVolFlow;
    3223            0 :                         BaseSizer::reportSizerOutput(state,
    3224              :                                                      this->sysType,
    3225              :                                                      this->SysName,
    3226              :                                                      "Design Size Maximum Reheat Steam Flow Rate [m3/s]",
    3227              :                                                      MaxReheatSteamVolFlowDes,
    3228              :                                                      "User-Specified Maximum Reheat Steam Flow Rate [m3/s]",
    3229              :                                                      MaxReheatSteamVolFlowUser);
    3230            0 :                         if (state.dataGlobal->DisplayExtraWarnings) {
    3231            0 :                             if ((std::abs(MaxReheatSteamVolFlowDes - MaxReheatSteamVolFlowUser) / MaxReheatSteamVolFlowUser) >
    3232            0 :                                 state.dataSize->AutoVsHardSizingThreshold) {
    3233            0 :                                 ShowMessage(state,
    3234            0 :                                             format("SizeHVACSingleDuct: Potential issue with equipment sizing for {} = \"{}\".",
    3235            0 :                                                    this->sysType,
    3236            0 :                                                    this->SysName));
    3237            0 :                                 ShowContinueError(
    3238            0 :                                     state, format("User-Specified Maximum Reheat Steam Flow Rate of {:.5R} [m3/s]", MaxReheatSteamVolFlowUser));
    3239            0 :                                 ShowContinueError(
    3240              :                                     state,
    3241            0 :                                     format("differs from Design Size Maximum Reheat Steam Flow Rate of {:.5R} [m3/s]", MaxReheatSteamVolFlowDes));
    3242            0 :                                 ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
    3243            0 :                                 ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
    3244              :                             }
    3245              :                         }
    3246              :                     }
    3247              :                 }
    3248              :             }
    3249              :         }
    3250              :     } else {
    3251            8 :         this->MaxReheatSteamVolFlow = 0.0;
    3252              :     }
    3253              : 
    3254           56 :     if (state.dataSize->CurTermUnitSizingNum > 0) {
    3255           48 :         TermUnitSizing(state.dataSize->CurTermUnitSizingNum).MinPriFlowFrac = this->ZoneMinAirFracDes * this->ZoneTurndownMinAirFrac;
    3256           48 :         TermUnitSizing(state.dataSize->CurTermUnitSizingNum).MaxHWVolFlow = this->MaxReheatWaterVolFlow;
    3257           48 :         TermUnitSizing(state.dataSize->CurTermUnitSizingNum).MaxSTVolFlow = this->MaxReheatSteamVolFlow;
    3258           48 :         TermUnitSizing(state.dataSize->CurTermUnitSizingNum).DesHeatingLoad = state.dataSingleDuct->DesCoilLoadSS; // Coil Summary report
    3259           48 :         if (this->ReheatComp_Num == HeatingCoilType::SimpleHeating) {
    3260            7 :             if (this->DamperHeatingAction == Action::Normal) {
    3261            0 :                 SetCoilDesFlow(state, this->ReheatComp, this->ReheatName, this->ZoneMinAirFracDes * this->MaxAirVolFlowRate, ErrorsFound);
    3262              :             } else {
    3263            7 :                 SetCoilDesFlow(
    3264            7 :                     state, this->ReheatComp, this->ReheatName, TermUnitSizing(state.dataSize->CurTermUnitSizingNum).AirVolFlow, ErrorsFound);
    3265              :             }
    3266              :         }
    3267              :     }
    3268              : 
    3269           56 :     if (this->MaxAirVolFlowRateDuringReheat > 0.0) {
    3270              :         // check for inconsistent dual max input
    3271           20 :         if (this->MaxAirVolFlowRateDuringReheat < (this->ZoneMinAirFracDes * this->MaxAirVolFlowRate)) {
    3272              :             // Only warn when really out of bounds
    3273            0 :             if ((this->ZoneMinAirFracDes * this->MaxAirVolFlowRate) - this->MaxAirVolFlowRateDuringReheat > 1.e-8) {
    3274            0 :                 ShowWarningError(state,
    3275              :                                  "SingleDuctSystem:SizeSys: Air Terminal Unit flow limits are not consistent, minimum flow limit is larger than "
    3276              :                                  "reheat maximum");
    3277            0 :                 ShowContinueError(state, format("Air Terminal Unit name = {}", this->SysName));
    3278            0 :                 ShowContinueError(state,
    3279            0 :                                   format("Maximum terminal flow during reheat = {:.6R} [m3/s] or flow fraction = {:.4R}",
    3280            0 :                                          this->MaxAirVolFlowRateDuringReheat,
    3281            0 :                                          (this->MaxAirVolFlowRateDuringReheat / this->MaxAirVolFlowRate)));
    3282            0 :                 ShowContinueError(state,
    3283            0 :                                   format("Minimum terminal flow = {:.6R} [m3/s] or flow fraction = {:.4R}",
    3284            0 :                                          (this->ZoneMinAirFracDes * this->MaxAirVolFlowRate),
    3285            0 :                                          this->ZoneMinAirFracDes));
    3286            0 :                 ShowContinueError(state, "The reheat maximum flow limit will be replaced by the minimum limit, and the simulation continues");
    3287              :             }
    3288            0 :             this->MaxAirVolFlowRateDuringReheat = (this->ZoneMinAirFracDes * this->MaxAirVolFlowRate);
    3289              :         }
    3290              :     }
    3291              : 
    3292           56 :     if (ErrorsFound) {
    3293            0 :         ShowFatalError(state, "Preceding sizing errors cause program termination");
    3294              :     }
    3295           56 : }
    3296              : 
    3297              : // End Initialization Section of the Module
    3298              : //******************************************************************************
    3299              : 
    3300              : // Begin Algorithm Section of the Module
    3301              : //******************************************************************************
    3302              : 
    3303        63351 : void SingleDuctAirTerminal::SimVAV(EnergyPlusData &state, bool const FirstHVACIteration, int const ZoneNum, int const ZoneNodeNum)
    3304              : {
    3305              : 
    3306              :     // SUBROUTINE INFORMATION:
    3307              :     //       AUTHOR         Richard J. Liesen
    3308              :     //       DATE WRITTEN   January 2000
    3309              :     //       MODIFIED       Fred Buhl: added reverse action damper heating action: August 2001
    3310              :     //                      KHL/TH 7/2010: revise to support dual max
    3311              :     //                      FB/KHL/TH 9/2010: added maximum supply air temperature leaving reheat coil
    3312              :     //                      TH 3/2012: added supply air flow adjustment based on zone maximum outdoor
    3313              :     //                                 air fraction - a TRACE feature
    3314              :     //                      Brent Griffith, 5/2012, general cleanup, fix negatives CR 8767, fix phantom coil flows CR 8854
    3315              : 
    3316              :     // PURPOSE OF THIS SUBROUTINE:
    3317              :     // This subroutine simulates the simple single duct volume VAV.
    3318              : 
    3319              :     // METHODOLOGY EMPLOYED:
    3320              :     // There is method to this madness.
    3321              : 
    3322              :     // Using/Aliasing
    3323              :     using namespace DataZoneEnergyDemands;
    3324              :     // unused   USE DataHeatBalFanSys, ONLY: Mat
    3325              :     using HeatingCoils::SimulateHeatingCoilComponents;
    3326              :     using HVAC::SmallLoad;
    3327              :     using PlantUtilities::SetActuatedBranchFlowRate;
    3328              :     using SteamCoils::SimulateSteamCoilComponents;
    3329              :     using WaterCoils::SimulateWaterCoilComponents;
    3330              : 
    3331              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    3332              :     Real64 MassFlow;     // [kg/sec]   Total Mass Flow Rate from Hot & Cold Inlets
    3333              :     Real64 QTotLoad;     // [Watts] Remaining load required for this zone
    3334              :     Real64 QZnReq;       // [Watts] Load calculated for heating coil
    3335              :     Real64 QToHeatSetPt; // [W]  remaining load to heating setpoint
    3336              :     Real64 CpAirAvg;
    3337              :     Real64 DeltaTemp;
    3338              :     int SysOutletNode;        // The node number of the terminal unit outlet node
    3339              :     int SysInletNode;         // the node number of the terminal unit inlet node
    3340              :     Real64 MaxFlowWater;      // This is the value passed to the Controller depending if FirstHVACIteration or not
    3341              :     Real64 MinFlowWater;      // This is the value passed to the Controller depending if FirstHVACIteration or not
    3342              :     Real64 QActualHeating;    // the heating load seen by the reheat coil
    3343              :     Real64 QHeatingDelivered; // the actual output from heating coil
    3344              :     Real64 LeakLoadMult;      // load multiplier to adjust for downstream leaks
    3345              :     Real64 MinFlowFrac;       // minimum flow fraction (and minimum damper position)
    3346              :     Real64 MassFlowBasedOnOA; // supply air mass flow rate based on zone OA requirements
    3347              :     Real64 AirLoopOAFrac;     // fraction of outside air entering air loop
    3348              :     Real64 DummyMdot;         // temporary mass flow rate argument
    3349              : 
    3350              :     // Note to the perplexed
    3351              :     // The SINGLE DUCT:VAV:REHEAT terminal unit originally contained 2 components: a damper
    3352              :     // and a reheat coil. The damper has become a virtual component - it consists only of
    3353              :     // an air inlet node and an air outlet node. The damper is upstream of the heating coil.
    3354              :     // sd_airterminal(SysNum)%InletNodeNum is the inlet node to the terminal unit and the damper
    3355              :     // sd_airterminal(SysNum)%OutletNodeNum is the outlet node of the damper and the inlet node of the heating coil
    3356              :     // sd_airterminal(SysNum)%ReheatAirOutletNode is the outlet node of the terminal unit and the heating coil
    3357              : 
    3358              :     // The calculated load from the Heat Balance
    3359        63351 :     LeakLoadMult = state.dataDefineEquipment->AirDistUnit(this->ADUNum).LeakLoadMult;
    3360        63351 :     QTotLoad = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ZoneNum).RemainingOutputRequired * LeakLoadMult;
    3361        63351 :     QToHeatSetPt = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ZoneNum).RemainingOutputReqToHeatSP * LeakLoadMult;
    3362        63351 :     SysOutletNode = this->ReheatAirOutletNode;
    3363        63351 :     SysInletNode = this->InletNodeNum;
    3364        63351 :     CpAirAvg = PsyCpAirFnW(0.5 * (state.dataLoopNodes->Node(ZoneNodeNum).HumRat + this->sd_airterminalInlet.AirHumRat));
    3365        63351 :     MinFlowFrac = this->ZoneMinAirFrac;
    3366        63351 :     MassFlowBasedOnOA = 0.0;
    3367        63351 :     state.dataSingleDuct->ZoneTempSDAT = state.dataLoopNodes->Node(ZoneNodeNum).Temp;
    3368        63351 :     state.dataSingleDuct->MinMassAirFlowSDAT = MinFlowFrac * state.dataEnvrn->StdRhoAir * this->MaxAirVolFlowRate;
    3369              : 
    3370              :     // Then depending on if the Load is for heating or cooling it is handled differently.  First
    3371              :     // the massflow rate for cooling is determined to meet the entire load.  Then
    3372              :     // if the massflow is below the minimum or greater than the Max it is set to either the Min
    3373              :     // or the Max as specified for the VAV model.
    3374        26190 :     if ((QTotLoad < 0.0) && (this->sd_airterminalInlet.AirMassFlowRateMaxAvail > 0.0) &&
    3375        89541 :         (state.dataHeatBalFanSys->TempControlType(ZoneNum) != HVAC::SetptType::SingleHeat) && (this->availSched->getCurrentVal() > 0.0)) {
    3376              :         // Calculate the flow required for cooling
    3377              : 
    3378        25765 :         DeltaTemp = CpAirAvg * (this->sd_airterminalInlet.AirTemp - state.dataSingleDuct->ZoneTempSDAT);
    3379              : 
    3380              :         // Need to check DeltaTemp and ensure that it is not zero
    3381        25765 :         if (DeltaTemp != 0.0) {
    3382        25754 :             MassFlow = QTotLoad / DeltaTemp;
    3383              :         } else {
    3384           11 :             MassFlow = this->sd_airterminalInlet.AirMassFlowRateMaxAvail;
    3385              :         }
    3386              : 
    3387              :         // Apply the zone maximum outdoor air fraction FOR VAV boxes - a TRACE feature
    3388        25765 :         if (state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ZoneNum).SupplyAirAdjustFactor > 1.0) {
    3389            0 :             MassFlow *= state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ZoneNum).SupplyAirAdjustFactor;
    3390              :         }
    3391              : 
    3392              :         // calculate supply air flow rate based on user specified OA requirement
    3393        25765 :         this->CalcOAMassFlow(state, MassFlowBasedOnOA, AirLoopOAFrac);
    3394        25765 :         MassFlow = max(MassFlow, MassFlowBasedOnOA);
    3395              : 
    3396              :         // used for normal acting damper
    3397        25765 :         state.dataSingleDuct->MinMassAirFlowSDAT = max(state.dataSingleDuct->MinMassAirFlowSDAT, MassFlowBasedOnOA);
    3398        25765 :         state.dataSingleDuct->MinMassAirFlowSDAT = max(state.dataSingleDuct->MinMassAirFlowSDAT, this->sd_airterminalInlet.AirMassFlowRateMinAvail);
    3399        25765 :         state.dataSingleDuct->MinMassAirFlowSDAT = min(state.dataSingleDuct->MinMassAirFlowSDAT, this->sd_airterminalInlet.AirMassFlowRateMaxAvail);
    3400              : 
    3401              :         // limit the OA based supply air flow rate based on optional user input
    3402              :         // Check to see if the flow is < the Min or > the Max air Fraction to the zone; then set to min or max
    3403        25765 :         MassFlow = max(MassFlow, this->sd_airterminalInlet.AirMassFlowRateMinAvail);
    3404        25765 :         MassFlow = min(MassFlow, this->sd_airterminalInlet.AirMassFlowRateMaxAvail);
    3405              : 
    3406        25765 :         if (state.afn->distribution_simulated && state.afn->AirflowNetworkFanActivated && state.afn->VAVTerminalRatio > 0.0) {
    3407            0 :             MassFlow *= state.afn->VAVTerminalRatio;
    3408            0 :             if (MassFlow > state.dataLoopNodes->Node(this->InletNodeNum).MassFlowRate) {
    3409            0 :                 MassFlow = state.dataLoopNodes->Node(this->InletNodeNum).MassFlowRate;
    3410              :             }
    3411              :         }
    3412              : 
    3413        34966 :     } else if ((this->sd_airterminalInlet.AirMassFlowRateMaxAvail > 0.0) &&
    3414        72552 :                (QTotLoad >= 0.0 || state.dataHeatBalFanSys->TempControlType(ZoneNum) == HVAC::SetptType::SingleHeat) &&
    3415        34966 :                (this->availSched->getCurrentVal() > 0.0)) {
    3416              :         //     IF (sd_airterminal(SysNum)%DamperHeatingAction .EQ. ReverseAction .AND. this->sd_airterminalInlet%AirMassFlowRateMinAvail <=
    3417              :         //     SmallMassFlow) THEN
    3418              :         // special case for heating: reverse action and damper allowed to close - set the minimum flow rate to a small but nonzero value
    3419              :         //       MassFlow = 0.01d0*this->sd_airterminalInlet%AirMassFlowRateMaxAvail
    3420              :         //     ELSE
    3421              :         // usual case for heating: set the air mass flow rate to the minimum
    3422        34966 :         MassFlow = this->sd_airterminalInlet.AirMassFlowRateMinAvail;
    3423              :         //     END IF
    3424              : 
    3425              :         // Apply the zone maximum outdoor air fraction for VAV boxes - a TRACE feature
    3426        34966 :         if (state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ZoneNum).SupplyAirAdjustFactor > 1.0) {
    3427            0 :             MassFlow *= state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ZoneNum).SupplyAirAdjustFactor;
    3428              :         }
    3429              : 
    3430              :         // calculate supply air flow rate based on user specified OA requirement
    3431        34966 :         this->CalcOAMassFlow(state, MassFlowBasedOnOA, AirLoopOAFrac);
    3432        34966 :         MassFlow = max(MassFlow, MassFlowBasedOnOA);
    3433              : 
    3434              :         // Check to see if the flow is < the Min or > the Max air Fraction to the zone; then set to min or max
    3435        34966 :         if (MassFlow <= this->sd_airterminalInlet.AirMassFlowRateMinAvail) {
    3436        34966 :             MassFlow = this->sd_airterminalInlet.AirMassFlowRateMinAvail;
    3437            0 :         } else if (MassFlow >= this->sd_airterminalInlet.AirMassFlowRateMaxAvail) {
    3438            0 :             MassFlow = this->sd_airterminalInlet.AirMassFlowRateMaxAvail;
    3439              :         }
    3440              : 
    3441              :         // the AirflowNetwork model overrids the mass flow rate value
    3442        34966 :         if (state.afn->distribution_simulated && state.afn->AirflowNetworkFanActivated && state.afn->VAVTerminalRatio > 0.0) {
    3443            0 :             MassFlow *= state.afn->VAVTerminalRatio;
    3444            0 :             if (MassFlow > state.dataLoopNodes->Node(this->InletNodeNum).MassFlowRate) {
    3445            0 :                 MassFlow = state.dataLoopNodes->Node(this->InletNodeNum).MassFlowRate;
    3446              :             }
    3447              :         }
    3448              : 
    3449              :     } else {
    3450              :         // System is Off set massflow to 0.0
    3451         2620 :         MassFlow = 0.0;
    3452         2620 :         AirLoopOAFrac = 0.0;
    3453              :     }
    3454              : 
    3455              :     // look for bang-bang condition: flow rate oscillating between 2 values during the air loop / zone
    3456              :     // equipment iteration. If detected, set flow rate to previous value.
    3457        69663 :     if (((std::abs(MassFlow - this->MassFlow2) < this->MassFlowDiff) || (std::abs(MassFlow - this->MassFlow3) < this->MassFlowDiff)) &&
    3458         6312 :         (std::abs(MassFlow - this->MassFlow1) >= this->MassFlowDiff)) {
    3459           14 :         if (MassFlow > 0.0) {
    3460           14 :             MassFlow = this->MassFlow1;
    3461              :         }
    3462              :     }
    3463              : 
    3464              :     // Move data to the damper outlet node
    3465        63351 :     this->sd_airterminalOutlet.AirTemp = this->sd_airterminalInlet.AirTemp;
    3466        63351 :     this->sd_airterminalOutlet.AirHumRat = this->sd_airterminalInlet.AirHumRat;
    3467        63351 :     this->sd_airterminalOutlet.AirMassFlowRate = MassFlow;
    3468        63351 :     this->sd_airterminalOutlet.AirMassFlowRateMaxAvail = this->sd_airterminalInlet.AirMassFlowRateMaxAvail;
    3469        63351 :     this->sd_airterminalOutlet.AirMassFlowRateMinAvail = this->sd_airterminalInlet.AirMassFlowRateMinAvail;
    3470        63351 :     this->sd_airterminalOutlet.AirEnthalpy = this->sd_airterminalInlet.AirEnthalpy;
    3471              : 
    3472              :     //   ! Calculate the Damper Position when there is a Max air flow specified.
    3473              :     //  If (MassFlow == 0.0D0) THEN
    3474              :     //    sd_airterminal(SysNum)%DamperPosition = 0.0D0
    3475              :     //  ELSE IF (this->sd_airterminalInlet%AirMassFlowRateMaxAvail > this->sd_airterminalInlet%AirMassFlowRateMinAvail) THEN
    3476              :     //    sd_airterminal(SysNum)%DamperPosition = ((MassFlow-this->sd_airterminalInlet%AirMassFlowRateMinAvail) / &
    3477              :     //                                   (this->sd_airterminalInlet%AirMassFlowRateMaxAvail-this->sd_airterminalInlet%AirMassFlowRateMinAvail)) *
    3478              :     //                                   &
    3479              :     //                                  (1.0d0-MinFlowFrac) + MinFlowFrac
    3480              :     //  ELSE
    3481              :     //    sd_airterminal(SysNum)%DamperPosition = 1.0D0
    3482              :     //  END IF
    3483              : 
    3484        63351 :     if (MassFlow == 0.0) {
    3485         5153 :         this->DamperPosition = 0.0;
    3486         5153 :         this->ZoneMinAirFracReport = 0.0;
    3487        58198 :     } else if ((MassFlow > 0.0) && (MassFlow < this->AirMassFlowRateMax)) {
    3488        18402 :         this->DamperPosition = MassFlow / this->AirMassFlowRateMax;
    3489        18402 :         this->ZoneMinAirFracReport = this->ZoneMinAirFrac;
    3490        39796 :     } else if (MassFlow == this->AirMassFlowRateMax) {
    3491        39796 :         this->DamperPosition = 1.0;
    3492        39796 :         this->ZoneMinAirFracReport = this->ZoneMinAirFrac;
    3493              :     }
    3494              : 
    3495              :     // Need to make sure that the damper outlets are passed to the coil inlet
    3496        63351 :     this->UpdateSys(state);
    3497              : 
    3498              :     // At the current air mass flow rate, calculate heating coil load
    3499        63351 :     QActualHeating = QToHeatSetPt - MassFlow * CpAirAvg * (this->sd_airterminalInlet.AirTemp - state.dataSingleDuct->ZoneTempSDAT); // reheat needed
    3500              : 
    3501              :     // do the reheat calculation if there's some air nass flow (or the damper action is "reverse action"), the flow is <= minimum ,
    3502              :     // there's a heating requirement, and there's a thermostat with a heating setpoint
    3503              :     // Reverse damper option is working only for water coils for now.
    3504        63351 :     if ((MassFlow > SmallMassFlow) && (QActualHeating > 0.0) && (state.dataHeatBalFanSys->TempControlType(ZoneNum) != HVAC::SetptType::SingleCool)) {
    3505              :         // At this point we know that there is a heating requirement: i.e., the heating coil needs to
    3506              :         // be activated (there's a zone heating load or there's a reheat requirement). There are 3 possible
    3507              :         // situations: 1) the coil load can be met by variable temperature air (below the max heat temp) at
    3508              :         // the minimum air mass flow rate; 2) the coil load can be met by variable air flow rate with the air
    3509              :         // temperature fixed at the max heat temp; 3) the load cannot be met (we will run at max air temp and
    3510              :         // max air flow rate). We check for condition 2 by assuming the air temperatute is at the max heat temp
    3511              :         // and solving for the air mass flow rate that will meet the load. If the flow rate is between the min and
    3512              :         // max we are in condition 2.
    3513              : 
    3514        18177 :         state.dataSingleDuct->QZoneMax2SDAT = QToHeatSetPt;
    3515              : 
    3516              :         // fill dual-max reheat flow limit, if any
    3517        18177 :         if (this->DamperHeatingAction == Action::Reverse) {
    3518          348 :             state.dataSingleDuct->MaxDeviceAirMassFlowReheatSDAT = this->AirMassFlowRateMax;
    3519        17829 :         } else if (this->DamperHeatingAction == Action::ReverseWithLimits) {
    3520         3897 :             state.dataSingleDuct->MaxDeviceAirMassFlowReheatSDAT = this->AirMassFlowDuringReheatMax;
    3521        13932 :         } else if (this->DamperHeatingAction == Action::Normal) {
    3522            1 :             state.dataSingleDuct->MaxDeviceAirMassFlowReheatSDAT = this->ZoneMinAirFrac * this->AirMassFlowRateMax;
    3523              :         } else {
    3524              :             // used for AIRTERMINAL_SINGLEDUCT_VAV_NOREHEAT or SingleDuctVAVNoReheat
    3525        13931 :             state.dataSingleDuct->MaxDeviceAirMassFlowReheatSDAT = this->AirMassFlowRateMax;
    3526              :         }
    3527              : 
    3528              :         // determine flow based on leaving reheat temperature limit
    3529        18177 :         if (this->MaxReheatTempSetByUser) {
    3530              : 
    3531            1 :             state.dataSingleDuct->MaxHeatTempSDAT = this->MaxReheatTemp;
    3532            1 :             if (QToHeatSetPt > SmallLoad) { // zone has a positive load to heating setpoint
    3533            1 :                 state.dataSingleDuct->MassFlowReqToLimitLeavingTempSDAT =
    3534            1 :                     QToHeatSetPt / (CpAirAvg * (state.dataSingleDuct->MaxHeatTempSDAT - state.dataSingleDuct->ZoneTempSDAT));
    3535              :             } else {
    3536            0 :                 state.dataSingleDuct->MassFlowReqToLimitLeavingTempSDAT = 0.0;
    3537              :             }
    3538              :         }
    3539              : 
    3540              :         // (re)apply limits to find air mass flow
    3541        18177 :         MassFlow = max(MassFlow, state.dataSingleDuct->MassFlowReqToLimitLeavingTempSDAT);
    3542        18177 :         MassFlow = min(MassFlow, state.dataSingleDuct->MaxDeviceAirMassFlowReheatSDAT);
    3543        18177 :         MassFlow = max(MassFlow, MassFlowBasedOnOA);
    3544        18177 :         MassFlow = min(MassFlow, this->sd_airterminalInlet.AirMassFlowRateMaxAvail);
    3545        18177 :         MassFlow = max(MassFlow, this->sd_airterminalInlet.AirMassFlowRateMinAvail);
    3546              : 
    3547        18177 :         if (state.afn->distribution_simulated && state.afn->AirflowNetworkFanActivated && state.afn->VAVTerminalRatio > 0.0) {
    3548            0 :             MassFlow *= state.afn->VAVTerminalRatio;
    3549            0 :             if (MassFlow > state.dataLoopNodes->Node(this->InletNodeNum).MassFlowRate) {
    3550            0 :                 MassFlow = state.dataLoopNodes->Node(this->InletNodeNum).MassFlowRate;
    3551              :             }
    3552              :         }
    3553              : 
    3554              :         // now make any corrections to heating coil loads
    3555        18177 :         if (this->MaxReheatTempSetByUser) {
    3556            2 :             state.dataSingleDuct->QZoneMaxRHTempLimitSDAT =
    3557            1 :                 MassFlow * CpAirAvg * (state.dataSingleDuct->MaxHeatTempSDAT - state.dataSingleDuct->ZoneTempSDAT);
    3558            1 :             state.dataSingleDuct->QZoneMax2SDAT = min(state.dataSingleDuct->QZoneMaxRHTempLimitSDAT, QToHeatSetPt);
    3559              :         }
    3560              : 
    3561        18177 :         this->sd_airterminalOutlet.AirMassFlowRate = MassFlow;
    3562              : 
    3563        18177 :         this->UpdateSys(state);
    3564              : 
    3565              :         // Now do the heating coil calculation for each heating coil type
    3566        18177 :         switch (this->ReheatComp_Num) { // Reverse damper option is working only for water coils for now.
    3567              :             // hot water heating coil
    3568          150 :         case HeatingCoilType::SimpleHeating: { // COIL:WATER:SIMPLEHEATING
    3569              :             // Determine the load required to pass to the Component controller
    3570              :             // Although this equation looks strange (using temp instead of deltaT), it is corrected later in ControlCompOutput
    3571              :             // and is working as-is, temperature setpoints are maintained as expected.
    3572          150 :             QZnReq = state.dataSingleDuct->QZoneMax2SDAT + MassFlow * CpAirAvg * state.dataSingleDuct->ZoneTempSDAT;
    3573              : 
    3574              :             // Initialize hot water flow rate to zero.
    3575          150 :             DummyMdot = 0.0;
    3576          150 :             SetActuatedBranchFlowRate(state, DummyMdot, this->ReheatControlNode, this->HWplantLoc, true);
    3577              :             // On the first HVAC iteration the system values are given to the controller, but after that
    3578              :             // the demand limits are in place and there needs to be feedback to the Zone Equipment
    3579          150 :             if (FirstHVACIteration) {
    3580           75 :                 MaxFlowWater = this->MaxReheatWaterFlow;
    3581           75 :                 MinFlowWater = this->MinReheatWaterFlow;
    3582              :             } else {
    3583           75 :                 int WaterControlNode = this->ReheatControlNode;
    3584           75 :                 MaxFlowWater = state.dataLoopNodes->Node(WaterControlNode).MassFlowRateMaxAvail;
    3585           75 :                 MinFlowWater = state.dataLoopNodes->Node(WaterControlNode).MassFlowRateMinAvail;
    3586              :             }
    3587              : 
    3588              :             // Simulate the reheat coil at constant air flow. Control by varying the
    3589              :             // hot water flow rate.
    3590              :             // FB use QActualHeating, change ControlCompOutput to use new
    3591          450 :             ControlCompOutput(state,
    3592          150 :                               this->ReheatName,
    3593          150 :                               this->ReheatComp,
    3594          150 :                               this->ReheatComp_Index,
    3595              :                               FirstHVACIteration,
    3596              :                               QZnReq,
    3597              :                               this->ReheatControlNode,
    3598              :                               MaxFlowWater,
    3599              :                               MinFlowWater,
    3600              :                               this->ControllerOffset,
    3601          150 :                               this->ControlCompTypeNum,
    3602          150 :                               this->CompErrIndex,
    3603              :                               _,
    3604              :                               SysOutletNode,
    3605              :                               MassFlow,
    3606              :                               _,
    3607              :                               _,
    3608          150 :                               this->HWplantLoc);
    3609              : 
    3610              :             // If reverse action damper and the hot water flow is at maximum, simulate the
    3611              :             // hot water coil with fixed (maximum) hot water flow but allow the air flow to
    3612              :             // vary up to the maximum (air damper opens to try to meet zone load)
    3613          150 :             if (this->DamperHeatingAction == Action::Reverse || this->DamperHeatingAction == Action::ReverseWithLimits) {
    3614          150 :                 if (state.dataLoopNodes->Node(this->ReheatControlNode).MassFlowRate == MaxFlowWater) {
    3615              :                     // fill limits for air flow for controller
    3616          126 :                     state.dataSingleDuct->MinAirMassFlowRevActSVAV = this->AirMassFlowRateMax * this->ZoneMinAirFrac;
    3617          126 :                     state.dataSingleDuct->MinAirMassFlowRevActSVAV =
    3618          126 :                         min(state.dataSingleDuct->MinAirMassFlowRevActSVAV, this->sd_airterminalInlet.AirMassFlowRateMaxAvail);
    3619          126 :                     state.dataSingleDuct->MinAirMassFlowRevActSVAV =
    3620          126 :                         max(state.dataSingleDuct->MinAirMassFlowRevActSVAV, this->sd_airterminalInlet.AirMassFlowRateMinAvail);
    3621              : 
    3622          126 :                     state.dataSingleDuct->MaxAirMassFlowRevActSVAV = this->AirMassFlowRateMax;
    3623          126 :                     state.dataSingleDuct->MaxAirMassFlowRevActSVAV =
    3624          126 :                         min(state.dataSingleDuct->MaxAirMassFlowRevActSVAV, state.dataSingleDuct->MaxDeviceAirMassFlowReheatSDAT);
    3625          126 :                     state.dataSingleDuct->MaxAirMassFlowRevActSVAV =
    3626          126 :                         max(state.dataSingleDuct->MaxAirMassFlowRevActSVAV, state.dataSingleDuct->MinAirMassFlowRevActSVAV);
    3627          126 :                     state.dataSingleDuct->MaxAirMassFlowRevActSVAV =
    3628          126 :                         min(state.dataSingleDuct->MaxAirMassFlowRevActSVAV, this->sd_airterminalInlet.AirMassFlowRateMaxAvail);
    3629              : 
    3630          126 :                     state.dataLoopNodes->Node(this->OutletNodeNum).MassFlowRateMaxAvail =
    3631          126 :                         state.dataSingleDuct->MaxAirMassFlowRevActSVAV; // suspect, check how/if used in ControlCompOutput
    3632          252 :                     ControlCompOutput(state,
    3633          126 :                                       this->ReheatName,
    3634          126 :                                       this->ReheatComp,
    3635          126 :                                       this->ReheatComp_Index,
    3636              :                                       FirstHVACIteration,
    3637          126 :                                       state.dataSingleDuct->QZoneMax2SDAT,
    3638              :                                       this->OutletNodeNum,
    3639          126 :                                       state.dataSingleDuct->MaxAirMassFlowRevActSVAV,
    3640          126 :                                       state.dataSingleDuct->MinAirMassFlowRevActSVAV,
    3641              :                                       this->ControllerOffset,
    3642          126 :                                       this->ControlCompTypeNum,
    3643          126 :                                       this->CompErrIndex,
    3644              :                                       ZoneNodeNum,
    3645              :                                       SysOutletNode);
    3646              :                     // air flow controller, not on plant, don't pass plant topology info
    3647              :                     // reset terminal unit inlet air mass flow to new value.
    3648          126 :                     state.dataLoopNodes->Node(this->OutletNodeNum).MassFlowRateMaxAvail = this->sd_airterminalInlet.AirMassFlowRateMaxAvail;
    3649          126 :                     MassFlow = state.dataLoopNodes->Node(SysOutletNode).MassFlowRate;
    3650              : 
    3651              :                     //         ! look for bang-bang condition: flow rate oscillating between 2 values during the air loop / zone
    3652              :                     //         ! equipment iteration. If detected, set flow rate to previous value and recalc HW flow.
    3653          126 :                     if (((std::abs(MassFlow - this->MassFlow2) < this->MassFlowDiff) ||
    3654          126 :                          (std::abs(MassFlow - this->MassFlow3) < this->MassFlowDiff)) &&
    3655            0 :                         (std::abs(MassFlow - this->MassFlow1) >= this->MassFlowDiff)) {
    3656            0 :                         if (MassFlow > 0.0) {
    3657            0 :                             MassFlow = this->MassFlow1;
    3658              :                         }
    3659            0 :                         this->sd_airterminalOutlet.AirMassFlowRate = MassFlow;
    3660            0 :                         this->UpdateSys(state);
    3661              : 
    3662              :                         // Although this equation looks strange (using temp instead of deltaT), it is corrected later in ControlCompOutput
    3663              :                         // and is working as-is, temperature setpoints are maintained as expected.
    3664            0 :                         QZnReq = state.dataSingleDuct->QZoneMax2SDAT + MassFlow * CpAirAvg * state.dataSingleDuct->ZoneTempSDAT;
    3665            0 :                         ControlCompOutput(state,
    3666            0 :                                           this->ReheatName,
    3667            0 :                                           this->ReheatComp,
    3668            0 :                                           this->ReheatComp_Index,
    3669              :                                           FirstHVACIteration,
    3670              :                                           QZnReq,
    3671              :                                           this->ReheatControlNode,
    3672              :                                           MaxFlowWater,
    3673              :                                           MinFlowWater,
    3674              :                                           this->ControllerOffset,
    3675            0 :                                           this->ControlCompTypeNum,
    3676            0 :                                           this->CompErrIndex,
    3677              :                                           _,
    3678              :                                           SysOutletNode,
    3679              :                                           MassFlow,
    3680              :                                           _,
    3681              :                                           _,
    3682            0 :                                           this->HWplantLoc);
    3683              :                     }
    3684              : 
    3685          126 :                     this->sd_airterminalOutlet.AirMassFlowRate = MassFlow;
    3686              :                     // reset OA report variable
    3687          126 :                     this->UpdateSys(state);
    3688              :                 } // IF (Node(sd_airterminal(SysNum)%ReheatControlNode)%MassFlowRate .EQ. MaxFlowWater) THEN
    3689              :             } // IF (sd_airterminal(SysNum)%DamperHeatingAction .EQ. ReverseAction) THEN
    3690              : 
    3691              :             // Recalculate the Damper Position.
    3692          150 :             if (MassFlow == 0.0) {
    3693            0 :                 this->DamperPosition = 0.0;
    3694            0 :                 this->ZoneMinAirFracReport = 0.0;
    3695          150 :             } else if ((MassFlow > 0.0) && (MassFlow < this->AirMassFlowRateMax)) {
    3696          150 :                 this->DamperPosition = MassFlow / this->AirMassFlowRateMax;
    3697          150 :                 this->ZoneMinAirFracReport = this->ZoneMinAirFrac;
    3698            0 :             } else if (MassFlow == this->AirMassFlowRateMax) {
    3699            0 :                 this->DamperPosition = 1.0;
    3700            0 :                 this->ZoneMinAirFracReport = this->ZoneMinAirFrac;
    3701              :             }
    3702          150 :         } break;
    3703            0 :         case HeatingCoilType::SteamAirHeating: { // ! COIL:STEAM:AIRHEATING
    3704              :             // Determine the load required to pass to the Component controller
    3705            0 :             QZnReq =
    3706            0 :                 state.dataSingleDuct->QZoneMax2SDAT - MassFlow * CpAirAvg * (this->sd_airterminalInlet.AirTemp - state.dataSingleDuct->ZoneTempSDAT);
    3707              : 
    3708              :             // Simulate reheat coil for the VAV system
    3709            0 :             SimulateSteamCoilComponents(state, this->ReheatName, FirstHVACIteration, this->ReheatComp_Index, QZnReq);
    3710            0 :         } break;
    3711          349 :         case HeatingCoilType::Electric: { // COIL:ELECTRIC:HEATING
    3712              :             // Determine the load required to pass to the Component controller
    3713          349 :             QZnReq =
    3714          349 :                 state.dataSingleDuct->QZoneMax2SDAT - MassFlow * CpAirAvg * (this->sd_airterminalInlet.AirTemp - state.dataSingleDuct->ZoneTempSDAT);
    3715              : 
    3716              :             // Simulate reheat coil for the VAV system
    3717          349 :             SimulateHeatingCoilComponents(state, this->ReheatName, FirstHVACIteration, QZnReq, this->ReheatComp_Index);
    3718          349 :         } break;
    3719         3747 :         case HeatingCoilType::Gas: { // COIL:GAS:HEATING
    3720              :             // Determine the load required to pass to the Component controller
    3721         3747 :             QZnReq =
    3722         3747 :                 state.dataSingleDuct->QZoneMax2SDAT - MassFlow * CpAirAvg * (this->sd_airterminalInlet.AirTemp - state.dataSingleDuct->ZoneTempSDAT);
    3723              : 
    3724              :             // Simulate reheat coil for the VAV system
    3725         3747 :             SimulateHeatingCoilComponents(state, this->ReheatName, FirstHVACIteration, QZnReq, this->ReheatComp_Index, QHeatingDelivered);
    3726         3747 :         } break;
    3727        13931 :         case HeatingCoilType::None: { // blank
    3728              :                                       // I no reheat is defined then assume that the damper is the only component.
    3729              :             // If something else is there that is not a reheat coil or a blank then give the error message
    3730        13931 :         } break;
    3731            0 :         default: {
    3732            0 :             ShowFatalError(state, format("Invalid Reheat Component={}", this->ReheatComp));
    3733            0 :         } break;
    3734              :         }
    3735              : 
    3736              :         // the COIL is OFF the properties are calculated for this special case.
    3737              :     } else {
    3738        45174 :         switch (this->ReheatComp_Num) {
    3739         3640 :         case HeatingCoilType::SimpleHeating: { // COIL:WATER:SIMPLEHEATING
    3740              :             // Simulate reheat coil for the Const Volume system
    3741         3640 :             DummyMdot = 0.0;
    3742         3640 :             SetActuatedBranchFlowRate(state, DummyMdot, this->ReheatControlNode, this->HWplantLoc, true);
    3743              :             // call the reheat coil with the NO FLOW condition to make sure that the Node values
    3744              :             // are passed through to the coil outlet correctly
    3745         3640 :             SimulateWaterCoilComponents(state, this->ReheatName, FirstHVACIteration, this->ReheatComp_Index);
    3746         3640 :         } break;
    3747            0 :         case HeatingCoilType::SteamAirHeating: { // COIL:STEAM:AIRHEATING
    3748              :             // Simulate reheat coil for the VAV system
    3749            0 :             SimulateSteamCoilComponents(state, this->ReheatName, FirstHVACIteration, this->ReheatComp_Index, 0.0);
    3750            0 :         } break;
    3751           19 :         case HeatingCoilType::Electric: { // COIL:ELECTRIC:HEATING
    3752              :             // Simulate reheat coil for the VAV system
    3753           19 :             SimulateHeatingCoilComponents(state, this->ReheatName, FirstHVACIteration, 0.0, this->ReheatComp_Index);
    3754           19 :         } break;
    3755         8849 :         case HeatingCoilType::Gas: { // COIL:GAS:HEATING
    3756              :             // Simulate reheat coil for the VAV system
    3757         8849 :             SimulateHeatingCoilComponents(state, this->ReheatName, FirstHVACIteration, 0.0, this->ReheatComp_Index);
    3758         8849 :         } break;
    3759        32666 :         case HeatingCoilType::None: { // blank
    3760              :                                       // If no reheat is defined then assume that the damper is the only component.
    3761              :                                       // If something else is that is not a reheat coil or a blank then give the error message
    3762        32666 :         } break;
    3763            0 :         default: {
    3764            0 :             ShowFatalError(state, format("Invalid Reheat Component={}", this->ReheatComp));
    3765            0 :         } break;
    3766              :         }
    3767              :     }
    3768              : 
    3769              :     // push the flow rate history
    3770        63351 :     this->MassFlow3 = this->MassFlow2;
    3771        63351 :     this->MassFlow2 = this->MassFlow1;
    3772        63351 :     this->MassFlow1 = MassFlow;
    3773        63351 : }
    3774              : 
    3775        60732 : void SingleDuctAirTerminal::CalcOAMassFlow(EnergyPlusData &state,
    3776              :                                            Real64 &SAMassFlow,   // outside air based on optional user input
    3777              :                                            Real64 &AirLoopOAFrac // outside air based on optional user input
    3778              : ) const
    3779              : {
    3780              : 
    3781              :     // FUNCTION INFORMATION:
    3782              :     //       AUTHOR         R. Raustad (FSEC)
    3783              :     //       DATE WRITTEN   Jan 2010
    3784              :     //       MODIFIED       Mangesh Basarkar, 06/2011: Modifying outside air based on airloop DCV flag
    3785              : 
    3786              :     // PURPOSE OF THIS FUNCTION:
    3787              :     // Calculates the amount of outside air required based on optional user input.
    3788              :     // Zone multipliers are included and are applied in GetInput.
    3789              : 
    3790              :     // METHODOLOGY EMPLOYED:
    3791              :     // User input defines method used to calculate OA.
    3792              : 
    3793              :     // Using/Aliasing
    3794              :     using Psychrometrics::PsyRhoAirFnPbTdbW;
    3795              : 
    3796              :     // FUNCTION PARAMETER DEFINITIONS:
    3797        60732 :     bool constexpr UseMinOASchFlag(true); // Always use min OA schedule in calculations.
    3798              : 
    3799              :     // FUNCTION LOCAL VARIABLE DECLARATIONS:
    3800              :     Real64 OAVolumeFlowRate; // outside air volume flow rate (m3/s)
    3801              :     Real64 OAMassFlow;       // outside air mass flow rate (kg/s)
    3802              : 
    3803              :     // initialize OA flow rate and OA report variable
    3804        60732 :     SAMassFlow = 0.0;
    3805        60732 :     AirLoopOAFrac = 0.0;
    3806        60732 :     int AirLoopNum = this->AirLoopNum;
    3807              : 
    3808              :     // Calculate the amount of OA based on optional user inputs
    3809        60732 :     if (AirLoopNum > 0) {
    3810        60712 :         AirLoopOAFrac = state.dataAirLoop->AirLoopFlow(AirLoopNum).OAFrac;
    3811              :         // If no additional input from user, RETURN from subroutine
    3812        60712 :         if (this->NoOAFlowInputFromUser) {
    3813        60711 :             return;
    3814              :         }
    3815              :         // Calculate outdoor air flow rate, zone multipliers are applied in GetInput
    3816            1 :         if (AirLoopOAFrac > 0.0) {
    3817            2 :             OAVolumeFlowRate = DataSizing::calcDesignSpecificationOutdoorAir(
    3818            1 :                 state, this->OARequirementsPtr, this->CtrlZoneNum, state.dataAirLoop->AirLoopControlInfo(AirLoopNum).AirLoopDCVFlag, UseMinOASchFlag);
    3819            1 :             OAMassFlow = OAVolumeFlowRate * state.dataEnvrn->StdRhoAir;
    3820              : 
    3821              :             // convert OA mass flow rate to supply air flow rate based on air loop OA fraction
    3822            1 :             SAMassFlow = OAMassFlow / AirLoopOAFrac;
    3823              :         }
    3824              :     }
    3825              : }
    3826              : 
    3827            4 : void SingleDuctAirTerminal::SimCBVAV(EnergyPlusData &state, bool const FirstHVACIteration, int const ZoneNum, int const ZoneNodeNum)
    3828              : {
    3829              : 
    3830              :     // SUBROUTINE INFORMATION:
    3831              :     //       AUTHOR         Richard Raustad
    3832              :     //       DATE WRITTEN   August 2006
    3833              :     //       MODIFIED       KHL/TH 10/2010: added maximum supply air temperature leaving reheat coil
    3834              : 
    3835              :     // PURPOSE OF THIS SUBROUTINE:
    3836              :     // This subroutine simulates the VAV box with varying airflow in heating and cooling.
    3837              :     // Modified version of SimVAV.
    3838              : 
    3839              :     // Using/Aliasing
    3840              :     using namespace DataZoneEnergyDemands;
    3841              :     using HVAC::SmallLoad;
    3842              :     // unused   USE DataHeatBalFanSys,    ONLY: Mat
    3843              :     using HeatingCoils::SimulateHeatingCoilComponents;
    3844              :     using SteamCoils::SimulateSteamCoilComponents;
    3845              :     using WaterCoils::SimulateWaterCoilComponents;
    3846              :     // unused   USE DataHeatBalFanSys,    ONLY: ZoneThermostatSetPointHi, ZoneThermostatSetPointLo
    3847              :     using PlantUtilities::SetActuatedBranchFlowRate;
    3848              : 
    3849              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    3850              :     Real64 MassFlow;     // Total Mass Flow Rate from Hot & Cold Inlets [kg/sec]
    3851              :     Real64 QTotLoad;     // Total load based on thermostat setpoint temperature [Watts]
    3852              :     Real64 QZnReq;       // Total load to be met by terminal heater [Watts]
    3853              :     Real64 QToHeatSetPt; // Remaining load to heating setpoint [W]
    3854              :     Real64 QSupplyAir;   // Zone load met by VAVHeatandCool system
    3855              :     Real64 CpAirZn;      // Specific heat of zone air [J/kg-C]
    3856              :     Real64 CpAirSysIn;   // Specific heat of VAVHeatandCool box entering air [J/kg-C]
    3857              :     Real64 DeltaTemp;    // Temperature difference multiplied by specific heat [J/kg]
    3858              :     Real64 MaxFlowWater; // This is the value passed to the Controller depending if FirstHVACIteration or not
    3859              :     Real64 MinFlowWater; // This is the value passed to the Controller depending if FirstHVACIteration or not
    3860              :     Real64 LeakLoadMult; // Load multiplier to adjust for downstream leaks
    3861              :     int SysOutletNode;   // The node number of the terminal unit outlet node
    3862              :     int SysInletNode;    // The node number of the terminal unit inlet node
    3863              :     Real64 DummyMdot;
    3864              :     Real64 QActualHeating;
    3865              :     Real64 MinFlowFrac; // minimum flow fraction (and minimum damper position)
    3866              : 
    3867              :     // sd_airterminal(SysNum)%InletNodeNum is the inlet node to the terminal unit and the damper
    3868              :     // sd_airterminal(SysNum)%OutletNodeNum is the outlet node of the damper and the inlet node of the heating coil
    3869              :     // sd_airterminal(SysNum)%ReheatAirOutletNode is the outlet node of the terminal unit and the heating coil
    3870              : 
    3871              :     // The calculated load from the Heat Balance
    3872            4 :     LeakLoadMult = state.dataDefineEquipment->AirDistUnit(this->ADUNum).LeakLoadMult;
    3873            4 :     QTotLoad = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ZoneNum).RemainingOutputRequired * LeakLoadMult;
    3874            4 :     QToHeatSetPt = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ZoneNum).RemainingOutputReqToHeatSP * LeakLoadMult;
    3875            4 :     SysOutletNode = this->ReheatAirOutletNode;
    3876            4 :     SysInletNode = this->InletNodeNum;
    3877            4 :     CpAirZn = PsyCpAirFnW(state.dataLoopNodes->Node(ZoneNodeNum).HumRat);
    3878            4 :     MinFlowFrac = this->ZoneMinAirFrac;
    3879            4 :     state.dataSingleDuct->MinMassAirFlowSCBVAV = MinFlowFrac * state.dataEnvrn->StdRhoAir * this->MaxAirVolFlowRate;
    3880            4 :     state.dataSingleDuct->ZoneTempSCBVAV = state.dataLoopNodes->Node(ZoneNodeNum).Temp;
    3881              : 
    3882              :     // Then depending on if the Load is for heating or cooling it is handled differently.  First
    3883              :     // the massflow rate for cooling is determined to meet the entire load.  Then
    3884              :     // if the massflow is below the minimum or greater than the Max it is set to either the Min
    3885              :     // or the Max as specified for the VAV model.
    3886            4 :     if (this->sd_airterminalInlet.AirMassFlowRateMaxAvail > 0.0) {
    3887              :         // Calculate the flow required for cooling
    3888            2 :         CpAirSysIn = PsyCpAirFnW(this->sd_airterminalInlet.AirHumRat);
    3889            2 :         DeltaTemp = CpAirSysIn * this->sd_airterminalInlet.AirTemp - CpAirZn * state.dataSingleDuct->ZoneTempSCBVAV;
    3890              : 
    3891              :         // Need to check DeltaTemp and ensure that it is not zero
    3892            2 :         if (DeltaTemp != 0.0) {
    3893            2 :             MassFlow = QTotLoad / DeltaTemp;
    3894              :         } else {
    3895            0 :             MassFlow = this->sd_airterminalInlet.AirMassFlowRateMaxAvail;
    3896              :         }
    3897              : 
    3898              :         // Check to see if the flow is < the Min or > the Max air Fraction to the zone; then set to min or max
    3899            2 :         MassFlow = max(MassFlow, this->sd_airterminalInlet.AirMassFlowRateMinAvail);
    3900            2 :         MassFlow = min(MassFlow, this->sd_airterminalInlet.AirMassFlowRateMaxAvail);
    3901              :     } else {
    3902              :         // System is Off set massflow to 0.0
    3903            2 :         MassFlow = 0.0;
    3904              :     }
    3905              :     // look for bang-bang condition: flow rate oscillating between 2 values during the air loop / zone
    3906              :     // equipment iteration. If detected, set flow rate to previous value.
    3907            4 :     if (((std::abs(MassFlow - this->MassFlow2) < this->MassFlowDiff) || (std::abs(MassFlow - this->MassFlow3) < this->MassFlowDiff)) &&
    3908            0 :         (std::abs(MassFlow - this->MassFlow1) >= this->MassFlowDiff)) {
    3909            0 :         MassFlow = this->MassFlow1;
    3910              :     }
    3911              : 
    3912              :     // Move data to the damper outlet node
    3913            4 :     this->sd_airterminalOutlet.AirTemp = this->sd_airterminalInlet.AirTemp;
    3914            4 :     this->sd_airterminalOutlet.AirHumRat = this->sd_airterminalInlet.AirHumRat;
    3915            4 :     this->sd_airterminalOutlet.AirMassFlowRate = MassFlow;
    3916            4 :     this->sd_airterminalOutlet.AirMassFlowRateMaxAvail = this->sd_airterminalInlet.AirMassFlowRateMaxAvail;
    3917            4 :     this->sd_airterminalOutlet.AirMassFlowRateMinAvail = this->sd_airterminalInlet.AirMassFlowRateMinAvail;
    3918            4 :     this->sd_airterminalOutlet.AirEnthalpy = this->sd_airterminalInlet.AirEnthalpy;
    3919              : 
    3920              :     // Calculate the Damper Position when there is a Max air flow specified.
    3921            4 :     if (this->AirMassFlowRateMax == 0.0) {
    3922            2 :         this->DamperPosition = 0.0;
    3923              :     } else {
    3924            2 :         this->DamperPosition = MassFlow / this->AirMassFlowRateMax;
    3925              :     }
    3926              : 
    3927              :     // Need to make sure that the damper outlets are passed to the coil inlet
    3928            4 :     this->UpdateSys(state);
    3929              : 
    3930            4 :     QActualHeating = QToHeatSetPt - MassFlow * CpAirZn * (this->sd_airterminalInlet.AirTemp - state.dataSingleDuct->ZoneTempSCBVAV);
    3931              : 
    3932            4 :     if ((MassFlow > SmallMassFlow) && (QActualHeating > 0.0) && (state.dataHeatBalFanSys->TempControlType(ZoneNum) != HVAC::SetptType::SingleCool)) {
    3933              :         //   VAVHeatandCool boxes operate at varying mass flow rates when reheating, VAV boxes operate at min flow
    3934              :         //      (MassFlow <= this->sd_airterminalInlet%AirMassFlowRateMinAvail) .AND. &
    3935              :         //   Per Fred Buhl, don't use DeadBandOrSetback to determine if heaters operate
    3936              :         //      (.NOT. DeadBandOrSetback(ZoneNum))) Then
    3937              : 
    3938              :         // At this point we know that there is a heating requirement: i.e., the heating coil needs to
    3939              :         // be activated (there's a zone heating load or there's a reheat requirement). There are 3 possible
    3940              :         // situations: 1) the coil load can be met by variable temperature air (below the max heat temp) at
    3941              :         // the minimum air mass flow rate; 2) the coil load can be met by variable air flow rate with the air
    3942              :         // temperature fixed at the max heat temp; 3) the load cannot be met (we will run at max air temp and
    3943              :         // max air flow rate). We check for condition 2 by assuming the air temperatute is at the max heat temp
    3944              :         // and solving for the air mass flow rate that will meet the load. If the flow rate is between the min and
    3945              :         // max we are in condition 2.
    3946              : 
    3947            2 :         state.dataSingleDuct->QZoneMax2SCBVAV = QToHeatSetPt;
    3948              : 
    3949            2 :         if (this->MaxReheatTempSetByUser) {
    3950              : 
    3951            2 :             state.dataSingleDuct->MaxHeatTempSCBVAV = this->MaxReheatTemp;
    3952            2 :             if (QToHeatSetPt > SmallLoad) { // zone has a positive load to heating setpoint
    3953            0 :                 state.dataSingleDuct->MassFlowReqSCBVAV =
    3954            0 :                     QToHeatSetPt / (CpAirZn * (state.dataSingleDuct->MaxHeatTempSCBVAV - state.dataSingleDuct->ZoneTempSCBVAV));
    3955              :             } else {
    3956            2 :                 state.dataSingleDuct->MassFlowReqSCBVAV = MassFlow;
    3957              :             }
    3958              : 
    3959            4 :             state.dataSingleDuct->QZoneMax3SCBVAV =
    3960            2 :                 CpAirZn * (state.dataSingleDuct->MaxHeatTempSCBVAV - state.dataSingleDuct->ZoneTempSCBVAV) * MassFlow;
    3961              : 
    3962            2 :             state.dataSingleDuct->MassFlowActualSCBVAV = MassFlow;
    3963              : 
    3964            2 :             if (state.dataSingleDuct->QZoneMax3SCBVAV < QToHeatSetPt) {
    3965            0 :                 state.dataSingleDuct->MassFlowActualSCBVAV = state.dataSingleDuct->MassFlowReqSCBVAV;
    3966              :                 // QZoneMax3 = CpAirZn * (MaxHeatTemp - ZoneTemp) * MassFlowActual
    3967              :             }
    3968              : 
    3969            2 :             if (state.dataSingleDuct->MassFlowActualSCBVAV <= state.dataSingleDuct->MinMassAirFlowSCBVAV) {
    3970            1 :                 state.dataSingleDuct->MassFlowActualSCBVAV = state.dataSingleDuct->MinMassAirFlowSCBVAV;
    3971            1 :             } else if (state.dataSingleDuct->MassFlowActualSCBVAV >= this->AirMassFlowRateMax) {
    3972            1 :                 state.dataSingleDuct->MassFlowActualSCBVAV = this->AirMassFlowRateMax;
    3973              :             }
    3974              : 
    3975            2 :             state.dataSingleDuct->QZoneMaxSCBVAV = CpAirZn * state.dataSingleDuct->MassFlowActualSCBVAV *
    3976            2 :                                                    (state.dataSingleDuct->MaxHeatTempSCBVAV - state.dataSingleDuct->ZoneTempSCBVAV);
    3977              : 
    3978              :             // temporary variable
    3979            2 :             state.dataSingleDuct->QZoneMax2SCBVAV = min(state.dataSingleDuct->QZoneMaxSCBVAV, QToHeatSetPt);
    3980              : 
    3981            2 :             MassFlow = state.dataSingleDuct->MassFlowActualSCBVAV;
    3982              : 
    3983              :         } // IF (sd_airterminal(SysNum)%MaxReheatTempSetByUser) THEN
    3984              : 
    3985            2 :         this->sd_airterminalOutlet.AirMassFlowRate = MassFlow;
    3986              : 
    3987            2 :         this->UpdateSys(state);
    3988              : 
    3989            2 :         switch (this->ReheatComp_Num) {        // hot water heating coil
    3990            0 :         case HeatingCoilType::SimpleHeating: { // COIL:WATER:SIMPLEHEATING
    3991              :             // Determine the load required to pass to the Component controller
    3992              :             // Although this equation looks strange (using temp instead of deltaT), it is corrected later in ControlCompOutput
    3993              :             // and is working as-is, temperature setpoints are maintained as expected.
    3994            0 :             QZnReq = state.dataSingleDuct->QZoneMax2SCBVAV + MassFlow * CpAirZn * state.dataLoopNodes->Node(ZoneNodeNum).Temp;
    3995            0 :             if (QZnReq < SmallLoad) {
    3996            0 :                 QZnReq = 0.0;
    3997              :             }
    3998              : 
    3999              :             // Initialize hot water flow rate to zero.
    4000              :             // Node(sd_airterminal(SysNum)%ReheatControlNode)%MassFlowRate = 0.0D0
    4001            0 :             DummyMdot = 0.0;
    4002            0 :             SetActuatedBranchFlowRate(state, DummyMdot, this->ReheatControlNode, this->HWplantLoc, true);
    4003              :             // On the first HVAC iteration the system values are given to the controller, but after that
    4004              :             // the demand limits are in place and there needs to be feedback to the Zone Equipment
    4005            0 :             if (FirstHVACIteration) {
    4006            0 :                 MaxFlowWater = this->MaxReheatWaterFlow;
    4007            0 :                 MinFlowWater = this->MinReheatWaterFlow;
    4008              :             } else {
    4009            0 :                 int WaterControlNode = this->ReheatControlNode;
    4010            0 :                 MaxFlowWater = state.dataLoopNodes->Node(WaterControlNode).MassFlowRateMaxAvail;
    4011            0 :                 MinFlowWater = state.dataLoopNodes->Node(WaterControlNode).MassFlowRateMinAvail;
    4012              :             }
    4013              : 
    4014              :             // Simulate the reheat coil at constant air flow. Control by varying the
    4015              :             // hot water flow rate.
    4016            0 :             ControlCompOutput(state,
    4017            0 :                               this->ReheatName,
    4018            0 :                               this->ReheatComp,
    4019            0 :                               this->ReheatComp_Index,
    4020              :                               FirstHVACIteration,
    4021              :                               QZnReq,
    4022              :                               this->ReheatControlNode,
    4023              :                               MaxFlowWater,
    4024              :                               MinFlowWater,
    4025              :                               this->ControllerOffset,
    4026            0 :                               this->ControlCompTypeNum,
    4027            0 :                               this->CompErrIndex,
    4028              :                               _,
    4029              :                               SysOutletNode,
    4030              :                               MassFlow,
    4031              :                               _,
    4032              :                               _,
    4033            0 :                               this->HWplantLoc);
    4034              : 
    4035              :             // If reverse action damper and the hot water flow is at maximum, simulate the
    4036              :             // hot water coil with fixed (maximum) hot water flow but allow the air flow to
    4037              :             // vary up to the maximum (air damper opens to try to meet zone load).
    4038            0 :             if (this->DamperHeatingAction == Action::Reverse) {
    4039            0 :                 if (state.dataLoopNodes->Node(this->ReheatControlNode).MassFlowRate == this->MaxReheatWaterFlow) {
    4040            0 :                     ControlCompOutput(state,
    4041            0 :                                       this->ReheatName,
    4042            0 :                                       this->ReheatComp,
    4043            0 :                                       this->ReheatComp_Index,
    4044              :                                       FirstHVACIteration,
    4045            0 :                                       state.dataSingleDuct->QZoneMax2SCBVAV,
    4046              :                                       this->OutletNodeNum,
    4047              :                                       this->sd_airterminalInlet.AirMassFlowRateMaxAvail,
    4048              :                                       this->sd_airterminalInlet.AirMassFlowRateMinAvail,
    4049              :                                       this->ControllerOffset,
    4050            0 :                                       this->ControlCompTypeNum,
    4051            0 :                                       this->CompErrIndex,
    4052              :                                       ZoneNodeNum,
    4053              :                                       SysOutletNode);
    4054              :                     //                                   ! air flow controller, not on plant, don't pass plant topology info
    4055              : 
    4056              :                     // reset terminal unit inlet air mass flow to new value.
    4057            0 :                     MassFlow = state.dataLoopNodes->Node(SysOutletNode).MassFlowRate;
    4058            0 :                     this->sd_airterminalOutlet.AirMassFlowRate = MassFlow;
    4059            0 :                     this->UpdateSys(state);
    4060              :                 }
    4061              :                 // look for bang-bang condition: flow rate oscillating between 2 values during the air loop / zone
    4062              :                 // equipment iteration. If detected, set flow rate to previous value and recalc HW flow.
    4063            0 :                 if (((std::abs(MassFlow - this->MassFlow2) < this->MassFlowDiff) || (std::abs(MassFlow - this->MassFlow3) < this->MassFlowDiff)) &&
    4064            0 :                     (std::abs(MassFlow - this->MassFlow1) >= this->MassFlowDiff)) {
    4065            0 :                     MassFlow = this->MassFlow1;
    4066            0 :                     this->sd_airterminalOutlet.AirMassFlowRate = MassFlow;
    4067            0 :                     this->UpdateSys(state);
    4068            0 :                     ControlCompOutput(state,
    4069            0 :                                       this->ReheatName,
    4070            0 :                                       this->ReheatComp,
    4071            0 :                                       this->ReheatComp_Index,
    4072              :                                       FirstHVACIteration,
    4073              :                                       QZnReq,
    4074              :                                       this->ReheatControlNode,
    4075              :                                       MaxFlowWater,
    4076              :                                       MinFlowWater,
    4077              :                                       this->ControllerOffset,
    4078            0 :                                       this->ControlCompTypeNum,
    4079            0 :                                       this->CompErrIndex,
    4080              :                                       _,
    4081              :                                       SysOutletNode,
    4082              :                                       MassFlow,
    4083              :                                       _,
    4084              :                                       _,
    4085            0 :                                       this->HWplantLoc);
    4086              :                 }
    4087              :                 // recalculate damper position
    4088            0 :                 if (this->AirMassFlowRateMax == 0.0) {
    4089            0 :                     this->DamperPosition = 0.0;
    4090              :                 } else {
    4091            0 :                     this->DamperPosition = MassFlow / this->AirMassFlowRateMax;
    4092              :                 }
    4093              :             }
    4094            0 :         } break;
    4095            0 :         case HeatingCoilType::SteamAirHeating: { // ! COIL:STEAM:AIRHEATING
    4096              :             // Determine the load required to pass to the Component controller
    4097            0 :             QZnReq = state.dataSingleDuct->QZoneMax2SCBVAV -
    4098            0 :                      MassFlow * CpAirZn * (this->sd_airterminalInlet.AirTemp - state.dataSingleDuct->ZoneTempSCBVAV);
    4099            0 :             if (QZnReq < SmallLoad) {
    4100            0 :                 QZnReq = 0.0;
    4101              :             }
    4102              : 
    4103              :             // Simulate reheat coil for the VAV system
    4104            0 :             SimulateSteamCoilComponents(state, this->ReheatName, FirstHVACIteration, this->ReheatComp_Index, QZnReq);
    4105            0 :         } break;
    4106            0 :         case HeatingCoilType::Electric: { // COIL:ELECTRIC:HEATING
    4107              :             // Determine the load required to pass to the Component controller
    4108            0 :             QSupplyAir = MassFlow * CpAirZn * (this->sd_airterminalInlet.AirTemp - state.dataSingleDuct->ZoneTempSCBVAV);
    4109            0 :             QZnReq = state.dataSingleDuct->QZoneMax2SCBVAV - QSupplyAir;
    4110            0 :             if (QZnReq < SmallLoad) {
    4111            0 :                 QZnReq = 0.0;
    4112              :             }
    4113              : 
    4114              :             // Simulate reheat coil for the VAV system
    4115            0 :             SimulateHeatingCoilComponents(state, this->ReheatName, FirstHVACIteration, QZnReq, this->ReheatComp_Index);
    4116            0 :         } break;
    4117            2 :         case HeatingCoilType::Gas: { // COIL:GAS:HEATING
    4118              :             // Determine the load required to pass to the Component controller
    4119            2 :             QZnReq = state.dataSingleDuct->QZoneMax2SCBVAV -
    4120            2 :                      MassFlow * CpAirZn * (this->sd_airterminalInlet.AirTemp - state.dataSingleDuct->ZoneTempSCBVAV);
    4121            2 :             if (QZnReq < SmallLoad) {
    4122            0 :                 QZnReq = 0.0;
    4123              :             }
    4124              : 
    4125              :             // Simulate reheat coil for the VAV system
    4126            2 :             SimulateHeatingCoilComponents(state, this->ReheatName, FirstHVACIteration, QZnReq, this->ReheatComp_Index);
    4127            2 :         } break;
    4128            0 :         case HeatingCoilType::None: { // blank
    4129              :                                       // If no reheat is defined then assume that the damper is the only component.
    4130              :             // If something else is there that is not a reheat coil then give the error message below.
    4131            0 :         } break;
    4132            0 :         default: {
    4133            0 :             ShowFatalError(state, format("Invalid Reheat Component={}", this->ReheatComp));
    4134            0 :         } break;
    4135              :         }
    4136              : 
    4137              :         // the COIL is OFF the properties are calculated for this special case.
    4138              :     } else {
    4139            2 :         switch (this->ReheatComp_Num) {
    4140            0 :         case HeatingCoilType::SimpleHeating: { // COIL:WATER:SIMPLEHEATING
    4141              :             // Simulate reheat coil for the Const Volume system
    4142              :             // Node(sd_airterminal(SysNum)%ReheatControlNode)%MassFlowRate = 0.0D0
    4143              :             // Initialize hot water flow rate to zero.
    4144            0 :             DummyMdot = 0.0;
    4145            0 :             SetActuatedBranchFlowRate(state, DummyMdot, this->ReheatControlNode, this->HWplantLoc, true);
    4146              : 
    4147              :             // call the reheat coil with the NO FLOW condition to make sure that the Node values
    4148              :             // are passed through to the coil outlet correctly
    4149            0 :             SimulateWaterCoilComponents(state, this->ReheatName, FirstHVACIteration, this->ReheatComp_Index);
    4150            0 :         } break;
    4151            0 :         case HeatingCoilType::SteamAirHeating: { // COIL:STEAM:AIRHEATING
    4152              :             // Simulate reheat coil for the VAV system
    4153            0 :             SimulateSteamCoilComponents(state, this->ReheatName, FirstHVACIteration, this->ReheatComp_Index, 0.0);
    4154            0 :         } break;
    4155            1 :         case HeatingCoilType::Electric: { // COIL:ELECTRIC:HEATING
    4156              :             // Simulate reheat coil for the VAV system
    4157            1 :             SimulateHeatingCoilComponents(state, this->ReheatName, FirstHVACIteration, 0.0, this->ReheatComp_Index);
    4158            1 :         } break;
    4159            0 :         case HeatingCoilType::Gas: { // COIL:GAS:HEATING
    4160              :             // Simulate reheat coil for the VAV system
    4161            0 :             SimulateHeatingCoilComponents(state, this->ReheatName, FirstHVACIteration, 0.0, this->ReheatComp_Index);
    4162            0 :         } break;
    4163            1 :         case HeatingCoilType::None: { // blank
    4164              :                                       // If no reheat is defined then assume that the damper is the only component.
    4165              :                                       // If something else is there that is not a reheat coil then give the error message
    4166            1 :         } break;
    4167            0 :         default: {
    4168            0 :             ShowFatalError(state, format("Invalid Reheat Component={}", this->ReheatComp));
    4169            0 :         } break;
    4170              :         }
    4171              :     }
    4172              :     // push the flow rate history
    4173            4 :     this->MassFlow3 = this->MassFlow2;
    4174            4 :     this->MassFlow2 = this->MassFlow1;
    4175            4 :     this->MassFlow1 = MassFlow;
    4176            4 : }
    4177              : 
    4178            2 : void SingleDuctAirTerminal::SimVAVVS(EnergyPlusData &state, bool const FirstHVACIteration, int const ZoneNum, int const ZoneNodeNum)
    4179              : {
    4180              : 
    4181              :     // SUBROUTINE INFORMATION:
    4182              :     //       AUTHOR         Fred Buhl
    4183              :     //       DATE WRITTEN   July 2004
    4184              : 
    4185              :     // PURPOSE OF THIS SUBROUTINE:
    4186              :     // This subroutine simulates a single duct VAV terminal unit with a variable-speed fan upstream
    4187              :     // and a reheat coil on the downstream side.
    4188              : 
    4189              :     // METHODOLOGY EMPLOYED:
    4190              :     // Define a compound component in CalcVAVVS. Break the heating/cooling load into 4 regions based
    4191              :     // on equip on/off combinations. Assign the heating load to the appropriate region and iteratively
    4192              :     // solve for the appropriate control variable value using Regula-Falsi solver.
    4193              : 
    4194              :     // Using/Aliasing
    4195              :     using namespace DataZoneEnergyDemands;
    4196              :     using General::SolveRoot;
    4197              :     using SteamCoils::GetCoilCapacity;
    4198              : 
    4199              :     // SUBROUTINE PARAMETER DEFINITIONS:
    4200            2 :     Real64 constexpr BigLoad(1.0e+20);
    4201              : 
    4202              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    4203            2 :     Real64 MassFlow = 0; // [kg/sec]   Total Mass Flow Rate from Hot & Cold Inlets
    4204              :     Real64 QTotLoad;     // [Watts]
    4205              :     // unused  REAL(r64) :: QZnReq      ! [Watts]
    4206              :     Real64 CpAirZn;
    4207              :     // unused  REAL(r64) :: CpAirSysIn
    4208              :     // unused  REAL(r64) :: DeltaTemp
    4209              :     int SysOutletNode;    // The node number of the terminal unit outlet node
    4210              :     int SysInletNode;     // the node number of the terminal unit inlet node
    4211              :     int WaterControlNode; // This is the Actuated Reheat Control Node
    4212              :     int SteamControlNode;
    4213              :     Real64 MaxFlowWater;    // This is the value passed to the Controller depending if FirstHVACIteration or not
    4214              :     Real64 MinFlowWater;    // This is the value passed to the Controller depending if FirstHVACIteration or not
    4215              :     Real64 MaxFlowSteam;    // This is the value passed to the Controller depending if FirstHVACIteration or not
    4216              :     Real64 MinFlowSteam;    // This is the value passed to the Controller depending if FirstHVACIteration or not
    4217              :     Real64 HWFlow;          // the hot water flow rate [kg/s]
    4218              :     Real64 QCoolFanOnMax;   // max cooling - fan at max flow; note that cooling is always < 0. [W]
    4219              :     Real64 QCoolFanOnMin;   // min active cooling with fan on - fan at lowest speed. [W]
    4220              :     Real64 QHeatFanOnMax;   // max heating - fan at heat flow max, hot water flow at max [W]
    4221              :     Real64 QHeatFanOnMin;   // min heating - fan at min flow, hot water at max flow [W]
    4222              :     Real64 QHeatFanOffMax;  // max heating - fan off, hot water flow at max [W]
    4223              :     Real64 QNoHeatFanOff;   // min heating - fan off, hot water at min flow [W]
    4224              :     HeatingCoilType HCType; // heating coil type
    4225              :     HVAC::FanType fanType;  // fan type (as a number)
    4226              :     int FanOp;              // 1 if fan is on; 0 if off.
    4227              :     Real64 MaxCoolMassFlow; // air flow at max cooling [kg/s]
    4228              :     Real64 MaxHeatMassFlow; // air flow at max heating [kg/s]
    4229              :     Real64 MinMassFlow;     // minimum air flow rate [kg/s]
    4230              :     Real64 UnitFlowToler;   // flow rate tolerance
    4231              :     Real64 QDelivered;
    4232              :     Real64 FracDelivered;
    4233              :     int SolFlag;
    4234              :     Real64 ErrTolerance;
    4235              :     Real64 MaxSteamCap; // steam coil capacity at full load
    4236              : 
    4237              :     // The calculated load from the Heat Balance
    4238            2 :     QTotLoad = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ZoneNum).RemainingOutputRequired;
    4239            2 :     SysOutletNode = this->ReheatAirOutletNode;
    4240            2 :     SysInletNode = this->InletNodeNum;
    4241            2 :     CpAirZn = PsyCpAirFnW(state.dataLoopNodes->Node(ZoneNodeNum).HumRat);
    4242            2 :     HCType = this->ReheatComp_Num;
    4243            2 :     fanType = this->fanType;
    4244            2 :     MaxCoolMassFlow = this->sd_airterminalInlet.AirMassFlowRateMaxAvail;
    4245            2 :     MaxHeatMassFlow = min(this->HeatAirMassFlowRateMax, this->sd_airterminalInlet.AirMassFlowRateMaxAvail);
    4246            2 :     MinMassFlow = MaxCoolMassFlow * this->ZoneMinAirFrac;
    4247            2 :     UnitFlowToler = 0.001 * DataConvergParams::HVACFlowRateToler;
    4248            2 :     QDelivered = 0.0;
    4249            2 :     HWFlow = 0.0;
    4250            2 :     if (this->sd_airterminalInlet.AirMassFlowRateMaxAvail <= 0.0 || state.dataZoneEnergyDemand->CurDeadBandOrSetback(ZoneNum)) {
    4251            0 :         MassFlow = 0.0;
    4252            0 :         FanOp = 0;
    4253            0 :         this->CalcVAVVS(state, FirstHVACIteration, ZoneNodeNum, 0.0, 0.0, fanType, MassFlow, FanOp, QDelivered);
    4254            0 :         return;
    4255              :     }
    4256              : 
    4257            2 :     if (HCType == HeatingCoilType::SimpleHeating) {
    4258            0 :         WaterControlNode = this->ReheatControlNode;
    4259            0 :         if (FirstHVACIteration) {
    4260            0 :             MaxFlowWater = this->MaxReheatWaterFlow;
    4261            0 :             MinFlowWater = this->MinReheatWaterFlow;
    4262              :         } else {
    4263            0 :             WaterControlNode = this->ReheatControlNode;
    4264            0 :             MaxFlowWater = state.dataLoopNodes->Node(WaterControlNode).MassFlowRateMaxAvail;
    4265            0 :             MinFlowWater = state.dataLoopNodes->Node(WaterControlNode).MassFlowRateMinAvail;
    4266              :         }
    4267              :     } else {
    4268            2 :         WaterControlNode = 0;
    4269            2 :         MaxFlowWater = 0.0;
    4270            2 :         MinFlowWater = 0.0;
    4271              :     }
    4272              : 
    4273            2 :     if (HCType == HeatingCoilType::SteamAirHeating) {
    4274            0 :         SteamControlNode = this->ReheatControlNode;
    4275            0 :         if (FirstHVACIteration) {
    4276            0 :             MaxFlowSteam = this->MaxReheatSteamFlow;
    4277            0 :             MinFlowSteam = this->MinReheatSteamFlow;
    4278              :         } else {
    4279            0 :             MaxFlowSteam = state.dataLoopNodes->Node(SteamControlNode).MassFlowRateMaxAvail;
    4280            0 :             MinFlowSteam = state.dataLoopNodes->Node(SteamControlNode).MassFlowRateMinAvail;
    4281              :         }
    4282              :     } else {
    4283            2 :         SteamControlNode = 0;
    4284            2 :         MaxFlowSteam = 0.0;
    4285            2 :         MinFlowSteam = 0.0;
    4286              :     }
    4287              : 
    4288              :     // define 3 load regions and assign the current load to the correct region.
    4289              :     // region 1: active cooling with fan on
    4290            2 :     FanOp = 1;
    4291            2 :     if (HCType == HeatingCoilType::SteamAirHeating) {
    4292              :         bool ErrorsFound; // returned from mining function call
    4293            0 :         this->CalcVAVVS(state, FirstHVACIteration, ZoneNodeNum, MinFlowSteam, 0.0, fanType, MaxCoolMassFlow, FanOp, QCoolFanOnMax);
    4294            0 :         this->CalcVAVVS(state, FirstHVACIteration, ZoneNodeNum, MinFlowSteam, 0.0, fanType, MinMassFlow, FanOp, QCoolFanOnMin);
    4295              :         // region 2: active heating with fan on
    4296            0 :         this->CalcVAVVS(state, FirstHVACIteration, ZoneNodeNum, MaxFlowSteam, BigLoad, fanType, MaxHeatMassFlow, FanOp, QHeatFanOnMax);
    4297            0 :         MaxSteamCap = GetCoilCapacity(state, this->ReheatComp, this->ReheatName, ErrorsFound);
    4298            0 :         this->CalcVAVVS(state, FirstHVACIteration, ZoneNodeNum, MaxFlowSteam, 0.0, fanType, MinMassFlow, FanOp, QHeatFanOnMin);
    4299              :         // region 3: active heating with fan off
    4300            0 :         FanOp = 0;
    4301            0 :         this->CalcVAVVS(state, FirstHVACIteration, ZoneNodeNum, MaxFlowSteam, BigLoad, fanType, MinMassFlow, FanOp, QHeatFanOffMax);
    4302            0 :         this->CalcVAVVS(state, FirstHVACIteration, ZoneNodeNum, MinFlowSteam, 0.0, fanType, MinMassFlow, FanOp, QNoHeatFanOff);
    4303              :     } else {
    4304            2 :         this->CalcVAVVS(state, FirstHVACIteration, ZoneNodeNum, MinFlowWater, 0.0, fanType, MaxCoolMassFlow, FanOp, QCoolFanOnMax);
    4305            2 :         this->CalcVAVVS(state, FirstHVACIteration, ZoneNodeNum, MinFlowWater, 0.0, fanType, MinMassFlow, FanOp, QCoolFanOnMin);
    4306              :         // region 2: active heating with fan on
    4307            2 :         this->CalcVAVVS(state, FirstHVACIteration, ZoneNodeNum, MaxFlowWater, BigLoad, fanType, MaxHeatMassFlow, FanOp, QHeatFanOnMax);
    4308            2 :         this->CalcVAVVS(state, FirstHVACIteration, ZoneNodeNum, MaxFlowWater, 0.0, fanType, MinMassFlow, FanOp, QHeatFanOnMin);
    4309              :         // region 3: active heating with fan off
    4310            2 :         FanOp = 0;
    4311            2 :         this->CalcVAVVS(state, FirstHVACIteration, ZoneNodeNum, MaxFlowWater, BigLoad, fanType, MinMassFlow, FanOp, QHeatFanOffMax);
    4312            2 :         this->CalcVAVVS(state, FirstHVACIteration, ZoneNodeNum, MinFlowWater, 0.0, fanType, MinMassFlow, FanOp, QNoHeatFanOff);
    4313              :     }
    4314              : 
    4315              :     // Active cooling with fix for issue #5592
    4316            2 :     if (QTotLoad < (-1.0 * SmallLoad) && QTotLoad < (QCoolFanOnMin - SmallLoad) && this->sd_airterminalInlet.AirMassFlowRateMaxAvail > 0.0 &&
    4317            0 :         !state.dataZoneEnergyDemand->CurDeadBandOrSetback(ZoneNum)) {
    4318              :         // check that it can meet the load
    4319            0 :         FanOp = 1;
    4320            0 :         if (QCoolFanOnMax < QTotLoad - SmallLoad) {
    4321            0 :             Real64 MinHWFlow = (HCType == HeatingCoilType::SteamAirHeating) ? MinFlowSteam : MinFlowWater;
    4322              : 
    4323            0 :             auto f = [&state, this, FirstHVACIteration, ZoneNodeNum, MinHWFlow, fanType, FanOp, QTotLoad](Real64 const SupplyAirMassFlow) {
    4324            0 :                 Real64 UnitOutput = 0.0; // cooling output [W] (cooling is negative)
    4325              : 
    4326            0 :                 state.dataSingleDuct->sd_airterminal(this->SysNum)
    4327            0 :                     .CalcVAVVS(state, FirstHVACIteration, ZoneNodeNum, MinHWFlow, 0.0, fanType, SupplyAirMassFlow, FanOp, UnitOutput);
    4328            0 :                 return (QTotLoad - UnitOutput) / QTotLoad;
    4329            0 :             };
    4330              : 
    4331            0 :             SolveRoot(state, UnitFlowToler, 50, SolFlag, MassFlow, f, MinMassFlow, MaxCoolMassFlow);
    4332            0 :             if (SolFlag == -1) {
    4333            0 :                 if (this->IterationLimit == 0) {
    4334            0 :                     ShowWarningError(state, format("Supply air flow control failed in VS VAV terminal unit {}", this->SysName));
    4335            0 :                     ShowContinueError(state, "  Iteration limit exceeded in calculating air flow rate");
    4336              :                 }
    4337            0 :                 ShowRecurringWarningErrorAtEnd(
    4338            0 :                     state, "Supply air flow Iteration limit exceeded in VS VAV terminal unit " + this->SysName, this->IterationLimit);
    4339            0 :             } else if (SolFlag == -2) {
    4340            0 :                 if (this->IterationFailed == 0) {
    4341            0 :                     ShowWarningError(state, format("Supply air flow control failed in VS VAV terminal unit {}", this->SysName));
    4342            0 :                     ShowContinueError(state, "  Bad air flow limits");
    4343              :                 }
    4344            0 :                 ShowRecurringWarningErrorAtEnd(
    4345            0 :                     state, "Supply air flow control failed in VS VAV terminal unit " + this->SysName, this->IterationFailed);
    4346              :             }
    4347              : 
    4348              :         } else {
    4349              : 
    4350            0 :             MassFlow = MaxCoolMassFlow;
    4351              : 
    4352            0 :             if (HCType == HeatingCoilType::SteamAirHeating) {
    4353            0 :                 this->CalcVAVVS(state, FirstHVACIteration, ZoneNodeNum, MinFlowSteam, 0.0, fanType, MassFlow, FanOp, QDelivered);
    4354              :             } else {
    4355            0 :                 this->CalcVAVVS(state, FirstHVACIteration, ZoneNodeNum, MinFlowWater, 0.0, fanType, MassFlow, FanOp, QDelivered);
    4356              :             }
    4357              :         }
    4358              : 
    4359              :         // no active heating or cooling
    4360            2 :     } else if ((QTotLoad >= QCoolFanOnMin - SmallLoad && QTotLoad <= QNoHeatFanOff + SmallLoad &&
    4361            4 :                 this->sd_airterminalInlet.AirMassFlowRateMaxAvail > 0.0) ||
    4362            0 :                (this->sd_airterminalInlet.AirMassFlowRateMaxAvail > 0.0 && state.dataZoneEnergyDemand->CurDeadBandOrSetback(ZoneNum))) {
    4363            2 :         MassFlow = MinMassFlow;
    4364            2 :         FanOp = 0;
    4365            2 :         if (HCType == HeatingCoilType::SteamAirHeating) {
    4366            0 :             this->CalcVAVVS(state, FirstHVACIteration, ZoneNodeNum, MinFlowSteam, QTotLoad, fanType, MassFlow, FanOp, QNoHeatFanOff);
    4367              :         } else {
    4368            2 :             this->CalcVAVVS(state, FirstHVACIteration, ZoneNodeNum, MinFlowWater, 0.0, fanType, MassFlow, FanOp, QNoHeatFanOff);
    4369              :         }
    4370              : 
    4371              :         // active heating
    4372            0 :     } else if (QTotLoad > QNoHeatFanOff + SmallLoad && this->sd_airterminalInlet.AirMassFlowRateMaxAvail > 0.0 &&
    4373            0 :                !state.dataZoneEnergyDemand->CurDeadBandOrSetback(ZoneNum)) {
    4374              :         // hot water coil
    4375            0 :         if (HCType == HeatingCoilType::SimpleHeating) {
    4376            0 :             if (QTotLoad < QHeatFanOffMax - SmallLoad) {
    4377              :                 // vary HW flow, leave air flow at minimum
    4378            0 :                 ErrTolerance = this->ControllerOffset;
    4379            0 :                 MassFlow = MinMassFlow;
    4380            0 :                 FanOp = 0;
    4381              : 
    4382            0 :                 auto f = [&state, this, FirstHVACIteration, ZoneNodeNum, MassFlow, fanType, FanOp, QTotLoad](Real64 const HWMassFlow) {
    4383            0 :                     Real64 UnitOutput = 0.0; // heating output [W]
    4384            0 :                     Real64 QSteamLoad = 0.0; // proportional load to calculate steam flow [W]
    4385              : 
    4386            0 :                     state.dataSingleDuct->sd_airterminal(this->SysNum)
    4387            0 :                         .CalcVAVVS(state, FirstHVACIteration, ZoneNodeNum, HWMassFlow, QSteamLoad, fanType, MassFlow, FanOp, UnitOutput);
    4388              : 
    4389            0 :                     return (QTotLoad - UnitOutput) / QTotLoad;
    4390            0 :                 };
    4391              : 
    4392            0 :                 SolveRoot(state, ErrTolerance, 500, SolFlag, HWFlow, f, MinFlowWater, MaxFlowWater);
    4393            0 :                 if (SolFlag == -1) {
    4394            0 :                     ShowRecurringWarningErrorAtEnd(state, "Hot Water flow control failed in VS VAV terminal unit " + this->SysName, this->ErrCount1);
    4395            0 :                     ShowRecurringContinueErrorAtEnd(
    4396            0 :                         state, "...Iteration limit (500) exceeded in calculating the hot water flow rate", this->ErrCount1c);
    4397            0 :                     this->CalcVAVVS(state, FirstHVACIteration, ZoneNodeNum, HWFlow, 0.0, fanType, MassFlow, FanOp, QDelivered);
    4398            0 :                 } else if (SolFlag == -2) {
    4399            0 :                     ShowRecurringWarningErrorAtEnd(
    4400            0 :                         state, "Hot Water flow control failed (bad air flow limits) in VS VAV terminal unit " + this->SysName, this->ErrCount2);
    4401              :                 }
    4402            0 :             } else if (QTotLoad >= QHeatFanOffMax - SmallLoad && QTotLoad <= QHeatFanOnMin + SmallLoad) {
    4403            0 :                 MassFlow = MinMassFlow;
    4404            0 :                 FanOp = 0;
    4405            0 :                 this->CalcVAVVS(state, FirstHVACIteration, ZoneNodeNum, MaxFlowWater, 0.0, fanType, MassFlow, FanOp, QDelivered);
    4406            0 :             } else if (QTotLoad > QHeatFanOnMin + SmallLoad && QTotLoad < QHeatFanOnMax - SmallLoad) {
    4407              :                 // set hot water flow to max and vary the supply air flow rate
    4408            0 :                 FanOp = 1;
    4409            0 :                 auto f = [&state, this, FirstHVACIteration, ZoneNodeNum, MaxFlowWater, fanType, FanOp, QTotLoad](Real64 const SupplyAirMassFlow) {
    4410            0 :                     Real64 UnitOutput = 0.0; // heating output [W]
    4411            0 :                     state.dataSingleDuct->sd_airterminal(this->SysNum)
    4412            0 :                         .CalcVAVVS(state, FirstHVACIteration, ZoneNodeNum, MaxFlowWater, QTotLoad, fanType, SupplyAirMassFlow, FanOp, UnitOutput);
    4413              : 
    4414            0 :                     return (QTotLoad - UnitOutput) / QTotLoad;
    4415            0 :                 };
    4416            0 :                 SolveRoot(state, UnitFlowToler, 50, SolFlag, MassFlow, f, MinMassFlow, MaxHeatMassFlow);
    4417            0 :                 if (SolFlag == -1) {
    4418            0 :                     if (this->IterationLimit == 0) {
    4419            0 :                         ShowWarningError(state, format("Supply air flow control failed in VS VAV terminal unit {}", this->SysName));
    4420            0 :                         ShowContinueError(state, "  Iteration limit exceeded in calculating air flow rate");
    4421              :                     }
    4422            0 :                     ShowRecurringWarningErrorAtEnd(
    4423            0 :                         state, "Supply air flow Iteration limit exceeded in VS VAV terminal unit " + this->SysName, this->IterationLimit);
    4424            0 :                 } else if (SolFlag == -2) {
    4425            0 :                     if (this->IterationFailed == 0) {
    4426            0 :                         ShowWarningError(state, format("Supply air flow control failed in VS VAV terminal unit {}", this->SysName));
    4427            0 :                         ShowContinueError(state, "  Bad air flow limits");
    4428              :                     }
    4429            0 :                     ShowRecurringWarningErrorAtEnd(
    4430            0 :                         state, "Supply air flow control failed in VS VAV terminal unit " + this->SysName, this->IterationFailed);
    4431              :                 }
    4432            0 :             } else {
    4433            0 :                 MassFlow = MaxHeatMassFlow;
    4434            0 :                 FanOp = 1;
    4435            0 :                 this->CalcVAVVS(state, FirstHVACIteration, ZoneNodeNum, MaxFlowWater, 0.0, fanType, MassFlow, FanOp, QDelivered);
    4436              :             }
    4437            0 :         } else if (HCType == HeatingCoilType::SteamAirHeating) {
    4438              :             //      IF (QTotLoad > QNoHeatFanOff + SmallLoad .AND. QTotLoad < QHeatFanOffMax - SmallLoad) THEN
    4439            0 :             if (QTotLoad < QHeatFanOffMax - SmallLoad) {
    4440            0 :                 ErrTolerance = this->ControllerOffset;
    4441            0 :                 MassFlow = MinMassFlow;
    4442            0 :                 FanOp = 0;
    4443            0 :                 auto f = [&state, this, FirstHVACIteration, ZoneNodeNum, MassFlow, fanType, FanOp, QTotLoad, MinFlowSteam, MaxFlowSteam, MaxSteamCap](
    4444              :                              Real64 const HWMassFlow) {
    4445            0 :                     Real64 UnitOutput = 0.0; // heating output [W]
    4446            0 :                     Real64 QSteamLoad = 0.0; // proportional load to calculate steam flow [W]
    4447              : 
    4448              :                     // vary the load to be met by the steam coil to converge on a steam flow rate to meet the load
    4449              :                     //   backwards way of varying steam flow rate. Steam coil calculates a flow rate to meet a load.
    4450            0 :                     if ((MaxFlowSteam - MinFlowSteam) == 0.0) {
    4451            0 :                         QSteamLoad = QTotLoad; // Use QTotLoad, bad starting value error for RegulaFalsi will occur
    4452              :                     } else {
    4453            0 :                         QSteamLoad = MaxSteamCap * HWMassFlow / (MaxFlowSteam - MinFlowSteam);
    4454              :                     }
    4455            0 :                     state.dataSingleDuct->sd_airterminal(this->SysNum)
    4456            0 :                         .CalcVAVVS(state, FirstHVACIteration, ZoneNodeNum, HWMassFlow, QSteamLoad, fanType, MassFlow, FanOp, UnitOutput);
    4457              : 
    4458            0 :                     return (QTotLoad - UnitOutput) / QTotLoad;
    4459            0 :                 };
    4460            0 :                 SolveRoot(state, ErrTolerance, 500, SolFlag, HWFlow, f, MinFlowSteam, MaxFlowSteam);
    4461            0 :                 if (SolFlag == -1) {
    4462            0 :                     ShowRecurringWarningErrorAtEnd(state, "Steam flow control failed in VS VAV terminal unit " + this->SysName, this->ErrCount1);
    4463            0 :                     ShowRecurringContinueErrorAtEnd(
    4464            0 :                         state, "...Iteration limit (500) exceeded in calculating the hot water flow rate", this->ErrCount1c);
    4465            0 :                     this->CalcVAVVS(state, FirstHVACIteration, ZoneNodeNum, HWFlow, 0.0, fanType, MassFlow, FanOp, QDelivered);
    4466            0 :                 } else if (SolFlag == -2) {
    4467            0 :                     ShowRecurringWarningErrorAtEnd(
    4468            0 :                         state, "Steam flow control failed (bad air flow limits) in VS VAV terminal unit " + this->SysName, this->ErrCount2);
    4469              :                 }
    4470            0 :             } else if (QTotLoad >= QHeatFanOffMax - SmallLoad && QTotLoad <= QHeatFanOnMin + SmallLoad) {
    4471            0 :                 MassFlow = MinMassFlow;
    4472            0 :                 FanOp = 0;
    4473            0 :                 this->CalcVAVVS(state, FirstHVACIteration, ZoneNodeNum, MaxFlowWater, 0.0, fanType, MassFlow, FanOp, QDelivered);
    4474            0 :             } else if (QTotLoad > QHeatFanOnMin + SmallLoad && QTotLoad < QHeatFanOnMax - SmallLoad) {
    4475            0 :                 FanOp = 1;
    4476              : 
    4477            0 :                 auto f = [&state, this, FirstHVACIteration, ZoneNodeNum, MaxFlowSteam, fanType, FanOp, QTotLoad](Real64 const SupplyAirMassFlow) {
    4478            0 :                     Real64 UnitOutput = 0.0; // heating output [W]
    4479              : 
    4480            0 :                     state.dataSingleDuct->sd_airterminal(this->SysNum)
    4481            0 :                         .CalcVAVVS(state, FirstHVACIteration, ZoneNodeNum, MaxFlowSteam, QTotLoad, fanType, SupplyAirMassFlow, FanOp, UnitOutput);
    4482              : 
    4483            0 :                     return (QTotLoad - UnitOutput) / QTotLoad;
    4484            0 :                 };
    4485              : 
    4486            0 :                 SolveRoot(state, UnitFlowToler, 50, SolFlag, MassFlow, f, MinMassFlow, MaxHeatMassFlow);
    4487            0 :                 if (SolFlag == -1) {
    4488            0 :                     if (this->IterationLimit == 0) {
    4489            0 :                         ShowWarningError(state, format("Steam heating coil control failed in VS VAV terminal unit {}", this->SysName));
    4490            0 :                         ShowContinueError(state, "  Iteration limit exceeded in calculating air flow rate");
    4491              :                     }
    4492            0 :                     ShowRecurringWarningErrorAtEnd(
    4493            0 :                         state, "Steam heating coil iteration limit exceeded in VS VAV terminal unit " + this->SysName, this->IterationLimit);
    4494            0 :                 } else if (SolFlag == -2) {
    4495            0 :                     if (this->IterationFailed == 0) {
    4496            0 :                         ShowWarningError(state, format("Steam heating coil control failed in VS VAV terminal unit {}", this->SysName));
    4497            0 :                         ShowContinueError(state, "  Bad air flow limits");
    4498              :                     }
    4499            0 :                     ShowRecurringWarningErrorAtEnd(
    4500            0 :                         state, "Steam heating coil control failed in VS VAV terminal unit " + this->SysName, this->IterationFailed);
    4501              :                 }
    4502            0 :             } else {
    4503            0 :                 MassFlow = MaxHeatMassFlow;
    4504            0 :                 FanOp = 1;
    4505            0 :                 this->CalcVAVVS(state, FirstHVACIteration, ZoneNodeNum, QTotLoad, QTotLoad, fanType, MassFlow, FanOp, QDelivered);
    4506              :             }
    4507            0 :         } else if (HCType == HeatingCoilType::Gas || HCType == HeatingCoilType::Electric) {
    4508            0 :             if (QTotLoad <= QHeatFanOnMin + SmallLoad) {
    4509              :                 // vary heating coil power, leave mass flow at minimum
    4510            0 :                 MassFlow = MinMassFlow;
    4511            0 :                 FanOp = 0;
    4512            0 :                 this->CalcVAVVS(state, FirstHVACIteration, ZoneNodeNum, 0.0, QTotLoad, fanType, MassFlow, FanOp, QDelivered);
    4513            0 :             } else if (QTotLoad > QHeatFanOnMin + SmallLoad && QTotLoad < QHeatFanOnMax - SmallLoad) {
    4514            0 :                 FanOp = 1;
    4515              : 
    4516            0 :                 auto f = [&state, this, FirstHVACIteration, ZoneNodeNum, fanType, FanOp, QTotLoad](Real64 const HeatingFrac) {
    4517            0 :                     Real64 MaxHeatOut{this->ReheatCoilMaxCapacity}; // maximum heating output [W]
    4518              :                     Real64 UnitOutput;                              // heating output [W]
    4519              :                     Real64 AirMassFlowRate;                         // [kg/s]
    4520              :                     Real64 HeatOut;                                 // heating coil output [W]
    4521              : 
    4522            0 :                     HeatOut = HeatingFrac * MaxHeatOut;
    4523            0 :                     AirMassFlowRate = max(HeatingFrac * state.dataSingleDuct->sd_airterminal(this->SysNum).HeatAirMassFlowRateMax,
    4524            0 :                                           state.dataSingleDuct->sd_airterminal(this->SysNum).sd_airterminalInlet.AirMassFlowRateMaxAvail *
    4525            0 :                                               state.dataSingleDuct->sd_airterminal(this->SysNum).ZoneMinAirFrac);
    4526              : 
    4527            0 :                     state.dataSingleDuct->sd_airterminal(this->SysNum)
    4528            0 :                         .CalcVAVVS(state, FirstHVACIteration, ZoneNodeNum, 0.0, HeatOut, fanType, AirMassFlowRate, FanOp, UnitOutput);
    4529              : 
    4530            0 :                     return (QTotLoad - UnitOutput) / QTotLoad;
    4531            0 :                 };
    4532              : 
    4533            0 :                 SolveRoot(state, UnitFlowToler, 50, SolFlag, FracDelivered, f, 0.0, 1.0);
    4534            0 :                 MassFlow = state.dataLoopNodes->Node(SysInletNode).MassFlowRate;
    4535            0 :                 if (SolFlag == -1) {
    4536            0 :                     if (this->IterationLimit == 0) {
    4537            0 :                         ShowWarningError(state, format("Heating coil control failed in VS VAV terminal unit {}", this->SysName));
    4538            0 :                         ShowContinueError(state, "  Iteration limit exceeded in calculating air flow rate");
    4539              :                     }
    4540            0 :                     ShowRecurringWarningErrorAtEnd(
    4541            0 :                         state, "Heating coil control iteration limit exceeded in VS VAV terminal unit " + this->SysName, this->IterationLimit);
    4542            0 :                 } else if (SolFlag == -2) {
    4543            0 :                     if (this->IterationFailed == 0) {
    4544            0 :                         ShowWarningError(state, format("Heating coil control failed in VS VAV terminal unit {}", this->SysName));
    4545            0 :                         ShowContinueError(state, "  Bad air flow limits");
    4546              :                     }
    4547            0 :                     ShowRecurringWarningErrorAtEnd(
    4548            0 :                         state, "Heating coil control failed in VS VAV terminal unit " + this->SysName, this->IterationFailed);
    4549              :                 }
    4550            0 :             } else {
    4551            0 :                 MassFlow = MaxHeatMassFlow;
    4552            0 :                 FanOp = 1;
    4553            0 :                 this->CalcVAVVS(state, FirstHVACIteration, ZoneNodeNum, 0.0, QTotLoad, fanType, MassFlow, FanOp, QDelivered);
    4554              :             }
    4555            0 :         } else {
    4556            0 :             ShowFatalError(state, format("Invalid Reheat Component={}", this->ReheatComp));
    4557              :         }
    4558              : 
    4559              :     } else {
    4560              : 
    4561            0 :         MassFlow = 0.0;
    4562            0 :         FanOp = 0;
    4563            0 :         this->CalcVAVVS(state, FirstHVACIteration, ZoneNodeNum, 0.0, 0.0, fanType, MassFlow, FanOp, QDelivered);
    4564              :     }
    4565              : 
    4566              :     // Move mass flow rates to the damper outlet node
    4567            2 :     this->sd_airterminalOutlet.AirMassFlowRate = MassFlow;
    4568            2 :     this->sd_airterminalOutlet.AirMassFlowRateMaxAvail = this->sd_airterminalInlet.AirMassFlowRateMaxAvail;
    4569            2 :     this->sd_airterminalOutlet.AirMassFlowRateMinAvail = this->sd_airterminalInlet.AirMassFlowRateMinAvail;
    4570              : 
    4571              :     // calculate VAV damper Position.
    4572            2 :     if (this->AirMassFlowRateMax == 0.0) {
    4573            0 :         this->DamperPosition = 0.0;
    4574              :     } else {
    4575            2 :         this->DamperPosition = MassFlow / this->AirMassFlowRateMax;
    4576              :     }
    4577              :     // update the air terminal outlet node data
    4578            2 :     this->UpdateSys(state);
    4579              : }
    4580              : 
    4581         3473 : void SingleDuctAirTerminal::SimConstVol(EnergyPlusData &state, bool const FirstHVACIteration, int const ZoneNum, int const ZoneNodeNum)
    4582              : {
    4583              : 
    4584              :     // SUBROUTINE INFORMATION:
    4585              :     //       AUTHOR         Richard J. Liesen
    4586              :     //       DATE WRITTEN   February 2000
    4587              :     //       MODIFIED       FB/KHL/TH 2/2011: added maximum supply air temperature leaving reheat coil
    4588              : 
    4589              :     // PURPOSE OF THIS SUBROUTINE:
    4590              :     // This subroutine simulates the simple single duct constant volume systems.
    4591              : 
    4592              :     // Using/Aliasing
    4593              :     using namespace DataZoneEnergyDemands;
    4594              :     // unused   USE DataHeatBalFanSys, ONLY: Mat
    4595              :     using HeatingCoils::SimulateHeatingCoilComponents;
    4596              :     using PlantUtilities::SetActuatedBranchFlowRate;
    4597              :     using SteamCoils::SimulateSteamCoilComponents;
    4598              :     using WaterCoils::SimulateWaterCoilComponents;
    4599              : 
    4600              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    4601              :     Real64 MaxFlowWater; // This is the value passed to the Controller depending if FirstHVACIteration or not
    4602              :     Real64 MinFlowWater; // This is the value passed to the Controller depending if FirstHVACIteration or not
    4603              :     Real64 DummyMdot;    // local fluid mass flow rate
    4604              : 
    4605              :     Real64 QToHeatSetPt =
    4606         3473 :         state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ZoneNum).RemainingOutputReqToHeatSP; // The calculated load from the Heat Balance
    4607         3473 :     Real64 MassFlow = this->sd_airterminalInlet.AirMassFlowRateMaxAvail;                     // System massflow is set to the Available
    4608         3473 :     state.dataSingleDuct->QMax2SCV = QToHeatSetPt;
    4609         3473 :     state.dataSingleDuct->ZoneTempSCV = state.dataLoopNodes->Node(ZoneNodeNum).Temp;
    4610         3473 :     Real64 CpAir = PsyCpAirFnW(state.dataLoopNodes->Node(ZoneNodeNum).HumRat); // zone air specific heat
    4611         3473 :     if (this->MaxReheatTempSetByUser) {
    4612            0 :         state.dataSingleDuct->TAirMaxSCV = this->MaxReheatTemp;
    4613            0 :         state.dataSingleDuct->QMaxSCV = CpAir * MassFlow * (state.dataSingleDuct->TAirMaxSCV - state.dataSingleDuct->ZoneTempSCV);
    4614            0 :         state.dataSingleDuct->QMax2SCV = min(QToHeatSetPt, state.dataSingleDuct->QMaxSCV);
    4615              :     } // if (this->MaxReheatTempSetByUser) {
    4616              : 
    4617         3473 :     if (((this->sd_airterminalInlet.AirMassFlowRateMaxAvail == 0.0) && (this->sd_airterminalInlet.AirMassFlowRateMinAvail == 0.0)) ||
    4618         3469 :         (this->sd_airterminalInlet.AirMassFlowRate == 0.0)) {
    4619              :         // System is Off set massflow to 0.0
    4620            4 :         MassFlow = 0.0;
    4621              :     }
    4622              : 
    4623              :     // Calculate the Damper Position when there is a Max air flow specified.
    4624         3473 :     if (this->AirMassFlowRateMax == 0.0) {
    4625            1 :         this->DamperPosition = 0.0;
    4626              :     } else {
    4627         3472 :         this->DamperPosition = MassFlow / this->AirMassFlowRateMax;
    4628              :     }
    4629              : 
    4630              :     // make sure the inlet node flow rate is updated if the mass flow has been limited
    4631         3473 :     this->sd_airterminalOutlet.AirMassFlowRate = MassFlow;
    4632         3473 :     this->sd_airterminalOutlet.AirMassFlowRateMaxAvail = this->sd_airterminalInlet.AirMassFlowRateMaxAvail;
    4633         3473 :     this->sd_airterminalOutlet.AirMassFlowRateMinAvail = this->sd_airterminalInlet.AirMassFlowRateMinAvail;
    4634         3473 :     this->UpdateSys(state);
    4635              : 
    4636              :     Real64 QActualHeating =
    4637         3473 :         QToHeatSetPt - MassFlow * CpAir * (this->sd_airterminalInlet.AirTemp - state.dataSingleDuct->ZoneTempSCV); // reheat needed
    4638              :     // Now the massflow for reheating has been determined. If it is zero, or in SetBack, or the
    4639              :     // system scheduled OFF then not operational and shut the system down.
    4640         3473 :     if ((MassFlow > SmallMassFlow) && (QActualHeating > 0.0) && (state.dataHeatBalFanSys->TempControlType(ZoneNum) != HVAC::SetptType::SingleCool)) {
    4641              : 
    4642              :         Real64 QZnReq;
    4643              : 
    4644         1365 :         switch (this->ReheatComp_Num) {
    4645         1365 :         case HeatingCoilType::SimpleHeating: { // COIL:WATER:SIMPLEHEATING
    4646              :             // Determine the load required to pass to the Component controller
    4647         1365 :             QZnReq = state.dataSingleDuct->QMax2SCV + MassFlow * CpAir * state.dataSingleDuct->ZoneTempSCV;
    4648              : 
    4649              :             // Before Iterating through the Reheat Coil and Controller set the flags for the
    4650              :             // Do Loop to initialized conditions.
    4651              :             // Node(sd_airterminal(SysNum)%ReheatControlNode)%MassFlowRate = 0.0D0
    4652              :             // Initialize hot water flow rate to zero.
    4653         1365 :             DummyMdot = 0.0;
    4654         1365 :             SetActuatedBranchFlowRate(state, DummyMdot, this->ReheatControlNode, this->HWplantLoc, true);
    4655              : 
    4656              :             // On the first HVAC iteration the system values are given to the controller, but after that
    4657              :             // the demand limits are in place and there needs to be feedback to the Zone Equipment
    4658         1365 :             if (FirstHVACIteration) {
    4659          683 :                 MaxFlowWater = this->MaxReheatWaterFlow;
    4660          683 :                 MinFlowWater = this->MinReheatWaterFlow;
    4661              :             } else {
    4662          682 :                 int WaterControlNode = this->ReheatControlNode;
    4663          682 :                 MaxFlowWater = state.dataLoopNodes->Node(WaterControlNode).MassFlowRateMaxAvail;
    4664          682 :                 MinFlowWater = state.dataLoopNodes->Node(WaterControlNode).MassFlowRateMinAvail;
    4665              :             }
    4666              : 
    4667              :             // Simulate reheat coil for the Const Volume system
    4668              :             // Set Converged to True & when controller is not converged it will set to False.
    4669         5460 :             ControlCompOutput(state,
    4670         1365 :                               this->ReheatName,
    4671         1365 :                               this->ReheatComp,
    4672         1365 :                               this->ReheatComp_Index,
    4673              :                               FirstHVACIteration,
    4674              :                               QZnReq,
    4675              :                               this->ReheatControlNode,
    4676              :                               MaxFlowWater,
    4677              :                               MinFlowWater,
    4678              :                               this->ControllerOffset,
    4679         1365 :                               this->ControlCompTypeNum,
    4680         1365 :                               this->CompErrIndex,
    4681              :                               _,
    4682         1365 :                               this->ReheatAirOutletNode,
    4683              :                               MassFlow,
    4684              :                               _,
    4685              :                               _,
    4686         1365 :                               this->HWplantLoc);
    4687              : 
    4688         1365 :         } break;
    4689            0 :         case HeatingCoilType::SteamAirHeating: { // COIL:STEAM:STEAMAIRHEATING
    4690              :             // Determine the load required to pass to the Component controller
    4691            0 :             QZnReq = state.dataSingleDuct->QMax2SCV - MassFlow * CpAir * (this->sd_airterminalInlet.AirTemp - state.dataSingleDuct->ZoneTempSCV);
    4692              : 
    4693              :             // Simulate reheat coil for the VAV system
    4694            0 :             SimulateSteamCoilComponents(state, this->ReheatName, FirstHVACIteration, this->ReheatComp_Index, QZnReq);
    4695            0 :         } break;
    4696            0 :         case HeatingCoilType::Electric: { // COIL:ELECTRIC:HEATING
    4697              :             // Determine the load required to pass to the Component controller
    4698            0 :             QZnReq = state.dataSingleDuct->QMax2SCV - MassFlow * CpAir * (this->sd_airterminalInlet.AirTemp - state.dataSingleDuct->ZoneTempSCV);
    4699              : 
    4700              :             // Simulate reheat coil for the VAV system
    4701            0 :             SimulateHeatingCoilComponents(state, this->ReheatName, FirstHVACIteration, QZnReq, this->ReheatComp_Index);
    4702              : 
    4703            0 :         } break;
    4704            0 :         case HeatingCoilType::Gas: { // COIL:GAS:HEATING
    4705              :             // Determine the load required to pass to the Component controller
    4706            0 :             QZnReq = state.dataSingleDuct->QMax2SCV - MassFlow * CpAir * (this->sd_airterminalInlet.AirTemp - state.dataSingleDuct->ZoneTempSCV);
    4707              : 
    4708              :             // Simulate reheat coil for the VAV system
    4709            0 :             SimulateHeatingCoilComponents(state, this->ReheatName, FirstHVACIteration, QZnReq, this->ReheatComp_Index);
    4710            0 :         } break;
    4711            0 :         default: {
    4712            0 :             ShowFatalError(state, format("Invalid Reheat Component={}", this->ReheatComp));
    4713            0 :         } break;
    4714              :         }
    4715              : 
    4716              :         // the COIL is OFF the properties are calculated for this special case.
    4717              :     } else {
    4718         2108 :         switch (this->ReheatComp_Num) {
    4719         2107 :         case HeatingCoilType::SimpleHeating: { // COIL:WATER:SIMPLEHEATING
    4720              :             // Simulate reheat coil for the Const Volume system
    4721              :             // Node(sd_airterminal(SysNum)%ReheatControlNode)%MassFlowRate = 0.0D0
    4722              :             // Initialize hot water flow rate to zero.
    4723         2107 :             DummyMdot = 0.0;
    4724         2107 :             SetActuatedBranchFlowRate(state, DummyMdot, this->ReheatControlNode, this->HWplantLoc, true);
    4725              : 
    4726              :             // call the reheat coil with the NO FLOW condition to make sure that the Node values
    4727              :             // are passed through to the coil outlet correctly
    4728         2107 :             SimulateWaterCoilComponents(state, this->ReheatName, FirstHVACIteration, this->ReheatComp_Index);
    4729         2107 :         } break;
    4730            0 :         case HeatingCoilType::SteamAirHeating: { // COIL:STEAM:AIRHEATING
    4731              :             // Simulate reheat coil for the Const Volume system
    4732            0 :             SimulateSteamCoilComponents(state, this->ReheatName, FirstHVACIteration, this->ReheatComp_Index, 0.0);
    4733            0 :         } break;
    4734            1 :         case HeatingCoilType::Electric: { // COIL:ELECTRIC:HEATING
    4735              :             // Simulate reheat coil for the Const Volume system
    4736            1 :             SimulateHeatingCoilComponents(state, this->ReheatName, FirstHVACIteration, 0.0, this->ReheatComp_Index);
    4737            1 :         } break;
    4738            0 :         case HeatingCoilType::Gas: { // COIL:GAS:HEATING
    4739              :             // Simulate reheat coil for the Const Volume system
    4740            0 :             SimulateHeatingCoilComponents(state, this->ReheatName, FirstHVACIteration, 0.0, this->ReheatComp_Index);
    4741            0 :         } break;
    4742            0 :         default: {
    4743            0 :             ShowFatalError(state, format("Invalid Reheat Component={}", this->ReheatComp));
    4744            0 :         } break;
    4745              :         }
    4746              :     }
    4747         3473 : }
    4748              : 
    4749        30643 : void SingleDuctAirTerminal::SimConstVolNoReheat(EnergyPlusData &state)
    4750              : {
    4751              : 
    4752              :     // PURPOSE OF THIS SUBROUTINE:
    4753              :     // Sets outlet flow rate and conditions for singleduct constantvolume with no reheat air terminal.
    4754              : 
    4755        30643 :     this->sd_airterminalOutlet = this->sd_airterminalInlet;
    4756              : 
    4757              :     // update the air terminal outlet node data
    4758        30643 :     this->UpdateSys(state);
    4759        30643 : }
    4760              : 
    4761           14 : void SingleDuctAirTerminal::CalcVAVVS(EnergyPlusData &state,
    4762              :                                       bool const FirstHVACIteration,          // flag for 1st HVAV iteration in the time step
    4763              :                                       int const ZoneNode,                     // zone node number
    4764              :                                       Real64 const HWFlow,                    // hot water flow (kg/s)
    4765              :                                       Real64 const HCoilReq,                  // gas or elec coil demand requested
    4766              :                                       [[maybe_unused]] HVAC::FanType fanType, // type of fan
    4767              :                                       Real64 const AirFlow,                   // air flow rate (kg/s)
    4768              :                                       int const FanOn,                        // 1 means fan is on
    4769              :                                       Real64 &LoadMet                         // load met by unit (watts)
    4770              : )
    4771              : {
    4772              : 
    4773              :     // SUBROUTINE INFORMATION:
    4774              :     //       AUTHOR         Fred Buhl
    4775              :     //       DATE WRITTEN   July 2004
    4776              : 
    4777              :     // PURPOSE OF THIS SUBROUTINE:
    4778              :     // Simulate the components making up the VAV terminal unit with variable speed fan.
    4779              : 
    4780              :     // METHODOLOGY EMPLOYED:
    4781              :     // Simulates the unit components sequentially in the air flow direction.
    4782              : 
    4783              :     // Using/Aliasing
    4784              :     using HeatingCoils::SimulateHeatingCoilComponents;
    4785              :     using PlantUtilities::SetComponentFlowRate;
    4786              :     using SteamCoils::SimulateSteamCoilComponents;
    4787              :     using WaterCoils::SimulateWaterCoilComponents;
    4788              : 
    4789              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    4790              :     int FanInNode;       // unit air inlet node (fan inlet)
    4791              :     int FanOutNode;      // fan outlet node (heating coil inlet node)
    4792              :     int HCOutNode;       // unit air outlet node (heating coil air outlet node)
    4793              :     int HotControlNode;  // the hot water inlet node
    4794              :     Real64 AirMassFlow;  // total air mass flow rate [kg/s]
    4795              :     Real64 CpAirZn;      // zone air specific heat [J/kg-C]
    4796              :     bool TurnFansOffSav; // save the fan off flag
    4797              :     Real64 mdot;
    4798              : 
    4799           14 :     TurnFansOffSav = state.dataHVACGlobal->TurnFansOff;
    4800           14 :     FanInNode = this->InletNodeNum;
    4801           14 :     FanOutNode = this->OutletNodeNum;
    4802           14 :     HCOutNode = this->ReheatAirOutletNode;
    4803           14 :     HotControlNode = this->ReheatControlNode;
    4804           14 :     AirMassFlow = AirFlow;
    4805           14 :     state.dataLoopNodes->Node(FanInNode).MassFlowRate = AirMassFlow;
    4806           14 :     CpAirZn = PsyCpAirFnW(state.dataLoopNodes->Node(ZoneNode).HumRat);
    4807           14 :     if (FanOn == 1) {
    4808            8 :         state.dataFans->fans(this->Fan_Index)->simulate(state, FirstHVACIteration, _, _);
    4809              : 
    4810              :     } else { // pass through conditions
    4811            6 :         state.dataHVACGlobal->TurnFansOff = true;
    4812            6 :         state.dataFans->fans(this->Fan_Index)->simulate(state, FirstHVACIteration, _, _);
    4813            6 :         state.dataHVACGlobal->TurnFansOff = TurnFansOffSav;
    4814            6 :         state.dataLoopNodes->Node(FanOutNode).MassFlowRate = state.dataLoopNodes->Node(FanInNode).MassFlowRate;
    4815            6 :         state.dataLoopNodes->Node(FanOutNode).MassFlowRateMaxAvail = state.dataLoopNodes->Node(FanInNode).MassFlowRateMaxAvail;
    4816            6 :         state.dataLoopNodes->Node(FanOutNode).MassFlowRateMinAvail = state.dataLoopNodes->Node(FanInNode).MassFlowRateMinAvail;
    4817              :     }
    4818           14 :     switch (this->ReheatComp_Num) {
    4819            0 :     case HeatingCoilType::SimpleHeating: { // COIL:WATER:SIMPLEHEATING
    4820            0 :         mdot = HWFlow;
    4821            0 :         if (this->HWplantLoc.loopNum > 0) {
    4822            0 :             SetComponentFlowRate(state, mdot, this->ReheatControlNode, this->ReheatCoilOutletNode, this->HWplantLoc);
    4823              :         }
    4824              : 
    4825            0 :         SimulateWaterCoilComponents(state, this->ReheatName, FirstHVACIteration, this->ReheatComp_Index);
    4826            0 :     } break;
    4827            0 :     case HeatingCoilType::SteamAirHeating: { // HW Flow is steam mass flow here
    4828            0 :         mdot = HWFlow;
    4829            0 :         if (this->HWplantLoc.loopNum > 0) {
    4830            0 :             SetComponentFlowRate(state, mdot, this->ReheatControlNode, this->ReheatCoilOutletNode, this->HWplantLoc);
    4831              :         }
    4832            0 :         SimulateSteamCoilComponents(state, this->ReheatName, FirstHVACIteration, this->ReheatComp_Index, HCoilReq);
    4833            0 :     } break;
    4834           14 :     case HeatingCoilType::Electric: { // COIL:ELECTRIC:HEATING
    4835           14 :         SimulateHeatingCoilComponents(state, this->ReheatName, FirstHVACIteration, HCoilReq, this->ReheatComp_Index);
    4836           14 :     } break;
    4837            0 :     case HeatingCoilType::Gas: { // COIL:GAS:HEATING
    4838            0 :         SimulateHeatingCoilComponents(state, this->ReheatName, FirstHVACIteration, HCoilReq, this->ReheatComp_Index);
    4839            0 :     } break;
    4840            0 :     default: {
    4841            0 :         ShowFatalError(state, format("Invalid Reheat Component={}", this->ReheatComp));
    4842            0 :     } break;
    4843              :     }
    4844              : 
    4845           14 :     LoadMet = AirMassFlow * CpAirZn * (state.dataLoopNodes->Node(HCOutNode).Temp - state.dataLoopNodes->Node(ZoneNode).Temp);
    4846           14 : }
    4847              : 
    4848              : // End Algorithm Section of the Module
    4849              : // *****************************************************************************
    4850              : 
    4851              : // Beginning of Update subroutines for the Sys Module
    4852              : // *****************************************************************************
    4853              : 
    4854       115778 : void SingleDuctAirTerminal::UpdateSys(EnergyPlusData &state) const
    4855              : {
    4856              : 
    4857              :     // SUBROUTINE INFORMATION:
    4858              :     //       AUTHOR         Richard J. Liesen
    4859              :     //       DATE WRITTEN   january 2000
    4860              : 
    4861              :     // PURPOSE OF THIS SUBROUTINE:
    4862              :     // This subroutine updates the Syss.
    4863              : 
    4864       115778 :     int OutletNode = this->OutletNodeNum;
    4865       115778 :     int InletNode = this->InletNodeNum;
    4866              : 
    4867       115778 :     if (this->SysType_Num == SysType::SingleDuctVAVReheat || this->SysType_Num == SysType::SingleDuctCBVAVReheat ||
    4868        94649 :         this->SysType_Num == SysType::SingleDuctCBVAVNoReheat || this->SysType_Num == SysType::SingleDuctVAVNoReheat ||
    4869        34120 :         this->SysType_Num == SysType::SingleDuctConstVolNoReheat) {
    4870              :         // Set the outlet air nodes of the Sys
    4871       112301 :         state.dataLoopNodes->Node(OutletNode).MassFlowRate = this->sd_airterminalOutlet.AirMassFlowRate;
    4872       112301 :         state.dataLoopNodes->Node(OutletNode).Temp = this->sd_airterminalOutlet.AirTemp;
    4873       112301 :         state.dataLoopNodes->Node(OutletNode).HumRat = this->sd_airterminalOutlet.AirHumRat;
    4874       112301 :         state.dataLoopNodes->Node(OutletNode).Enthalpy = this->sd_airterminalOutlet.AirEnthalpy;
    4875              :         // Set the outlet nodes for properties that just pass through & not used
    4876       112301 :         state.dataLoopNodes->Node(OutletNode).Quality = state.dataLoopNodes->Node(InletNode).Quality;
    4877       112301 :         state.dataLoopNodes->Node(OutletNode).Press = state.dataLoopNodes->Node(InletNode).Press;
    4878              :     }
    4879              : 
    4880              :     // After all of the Outlets are updated the mass flow information needs to be
    4881              :     // passed back to the system inlet.
    4882       115778 :     state.dataLoopNodes->Node(InletNode).MassFlowRate = this->sd_airterminalOutlet.AirMassFlowRate;
    4883       115778 :     state.dataLoopNodes->Node(OutletNode).MassFlowRateMaxAvail =
    4884       115778 :         min(this->sd_airterminalOutlet.AirMassFlowRateMaxAvail, state.dataLoopNodes->Node(OutletNode).MassFlowRateMax);
    4885       115778 :     state.dataLoopNodes->Node(OutletNode).MassFlowRateMinAvail = this->sd_airterminalOutlet.AirMassFlowRateMinAvail;
    4886              : 
    4887       115778 :     if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
    4888            0 :         state.dataLoopNodes->Node(OutletNode).CO2 = state.dataLoopNodes->Node(InletNode).CO2;
    4889              :     }
    4890              : 
    4891       115778 :     if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
    4892            0 :         state.dataLoopNodes->Node(OutletNode).GenContam = state.dataLoopNodes->Node(InletNode).GenContam;
    4893              :     }
    4894       115778 : }
    4895              : 
    4896              : //        End of Update subroutines for the Sys Module
    4897              : // *****************************************************************************
    4898              : 
    4899              : // Beginning of Reporting subroutines for the Sys Module
    4900              : // *****************************************************************************
    4901              : 
    4902        97455 : void SingleDuctAirTerminal::ReportSys(EnergyPlusData &state) // unused1208
    4903              : {
    4904              : 
    4905              :     // set zone OA volume flow rate
    4906        97455 :     this->CalcOutdoorAirVolumeFlowRate(state);
    4907        97455 : }
    4908              : 
    4909            0 : void GetHVACSingleDuctSysIndex(EnergyPlusData &state,
    4910              :                                std::string const &SDSName,
    4911              :                                int &SDSIndex,
    4912              :                                bool &ErrorsFound,
    4913              :                                std::string_view const ThisObjectType,
    4914              :                                ObjexxFCL::Optional_int DamperInletNode, // Damper inlet node number
    4915              :                                ObjexxFCL::Optional_int DamperOutletNode // Damper outlet node number
    4916              : )
    4917              : {
    4918              : 
    4919              :     // SUBROUTINE INFORMATION:
    4920              :     //       AUTHOR         Lixing Gu
    4921              :     //       DATE WRITTEN   February 2006
    4922              : 
    4923              :     // PURPOSE OF THIS SUBROUTINE:
    4924              :     // This subroutine sets an index for a given single duct system -- issues error message if that system
    4925              :     // is not a legal system.
    4926              : 
    4927            0 :     if (state.dataSingleDuct->GetInputFlag) { // First time subroutine has been entered
    4928            0 :         GetSysInput(state);
    4929            0 :         state.dataSingleDuct->GetInputFlag = false;
    4930              :     }
    4931              : 
    4932            0 :     SDSIndex = Util::FindItemInList(SDSName, state.dataSingleDuct->sd_airterminal, &SingleDuctAirTerminal::SysName);
    4933            0 :     if (SDSIndex == 0) {
    4934            0 :         if (!ThisObjectType.empty()) {
    4935            0 :             ShowSevereError(state, fmt::format("{}, GetHVACSingleDuctSysIndex: Single duct system not found={}", ThisObjectType, SDSName));
    4936              :         } else {
    4937            0 :             ShowSevereError(state, format("GetHVACSingleDuctSysIndex: Single duct system not found={}", SDSName));
    4938              :         }
    4939            0 :         ErrorsFound = true;
    4940              :     } else {
    4941            0 :         if ((state.dataSingleDuct->sd_airterminal(SDSIndex).SysType_Num != SysType::SingleDuctConstVolReheat) &&
    4942            0 :             (state.dataSingleDuct->sd_airterminal(SDSIndex).SysType_Num != SysType::SingleDuctVAVReheat)) {
    4943            0 :             if (!ThisObjectType.empty()) {
    4944            0 :                 ShowSevereError(state, fmt::format("{}, GetHVACSingleDuctSysIndex: Could not find allowed types={}", ThisObjectType, SDSName));
    4945              :             } else {
    4946            0 :                 ShowSevereError(state, format("GetHVACSingleDuctSysIndex: Could not find allowed types={}", SDSName));
    4947              :             }
    4948            0 :             ShowContinueError(state, "The allowed types are: AirTerminal:SingleDuct:ConstantVolume:Reheat and AirTerminal:SingleDuct:VAV:Reheat");
    4949            0 :             ErrorsFound = true;
    4950              :         }
    4951            0 :         if (state.dataSingleDuct->sd_airterminal(SDSIndex).SysType_Num == SysType::SingleDuctVAVReheat) {
    4952            0 :             if (present(DamperInletNode)) {
    4953            0 :                 DamperInletNode = state.dataSingleDuct->sd_airterminal(SDSIndex).InletNodeNum;
    4954              :             }
    4955            0 :             if (present(DamperOutletNode)) {
    4956            0 :                 DamperOutletNode = state.dataSingleDuct->sd_airterminal(SDSIndex).OutletNodeNum;
    4957              :             }
    4958              :         }
    4959              :     }
    4960            0 : }
    4961              : 
    4962        65969 : void SimATMixer(EnergyPlusData &state, std::string const &SysName, bool const FirstHVACIteration, int &SysIndex)
    4963              : {
    4964              : 
    4965              :     // SUBROUTINE INFORMATION:
    4966              :     //       DATE WRITTEN   March 2012
    4967              : 
    4968              :     // PURPOSE OF THIS SUBROUTINE
    4969              :     // Simulate an Air Terminal Mixer component
    4970              : 
    4971        65969 :     if (state.dataSingleDuct->GetATMixerFlag) {
    4972            0 :         state.dataSingleDuct->GetATMixerFlag = false;
    4973              :     }
    4974              : 
    4975        65969 :     if (SysIndex == 0) {
    4976            0 :         state.dataSingleDuct->SysNumSATM = Util::FindItemInList(SysName, state.dataSingleDuct->SysATMixer);
    4977            0 :         SysIndex = state.dataSingleDuct->SysNumSATM;
    4978            0 :         if (state.dataSingleDuct->SysNumSATM == 0) {
    4979            0 :             ShowFatalError(state, format("Object {} not found", SysName));
    4980              :         }
    4981              :     } else {
    4982        65969 :         state.dataSingleDuct->SysNumSATM = SysIndex;
    4983              :     }
    4984              : 
    4985        65969 :     state.dataSingleDuct->SysATMixer(state.dataSingleDuct->SysNumSATM).InitATMixer(state, FirstHVACIteration);
    4986              : 
    4987        65969 :     CalcATMixer(state, state.dataSingleDuct->SysNumSATM);
    4988              : 
    4989        65969 :     UpdateATMixer(state, state.dataSingleDuct->SysNumSATM);
    4990        65969 : }
    4991              : 
    4992         7082 : void GetATMixers(EnergyPlusData &state)
    4993              : {
    4994              : 
    4995              :     // SUBROUTINE INFORMATION:
    4996              :     //       DATE WRITTEN   March 2012
    4997              : 
    4998              :     // PURPOSE OF THIS SUBROUTINE
    4999              :     // Get input for inlet side air terminal mixers and store it in the inlet side air terminal mixer array
    5000              : 
    5001              :     // METHODOLOGY EMPLOYED:
    5002              :     // Use the Get routines from the InputProcessor module.
    5003              : 
    5004              :     // Using/Aliasing
    5005              :     using DataZoneEquipment::EquipmentData;
    5006              :     using DataZoneEquipment::SubEquipmentData;
    5007              :     using NodeInputManager::GetOnlySingleNode;
    5008              :     using namespace DataLoopNode;
    5009              :     using BranchNodeConnections::TestCompSet;
    5010              : 
    5011              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    5012              :     int NumNums;    // Number of REAL(r64) numbers returned by GetObjectItem
    5013              :     int NumAlphas;  // Number of alphanumerics returned by GetObjectItem
    5014              :     int ATMixerNum; // Index of inlet side mixer air terminal unit
    5015              :     int IOStat;
    5016              :     static constexpr std::string_view RoutineName("GetATMixers: "); // include trailing blank space
    5017         7082 :     bool ErrorsFound(false);                                        // Error flag
    5018              :     int NodeNum;                                                    // Index to node number
    5019              :     int CtrlZone;                                                   // Index to control zone
    5020              :     bool ZoneNodeNotFound;                                          // Flag for error checking
    5021              :     bool errFlag;                                                   // error flag from component validation
    5022              : 
    5023         7082 :     if (!state.dataSingleDuct->GetATMixerFlag) {
    5024         6950 :         return;
    5025              :     }
    5026          132 :     state.dataSingleDuct->GetATMixerFlag = false;
    5027              : 
    5028          132 :     auto &ipsc = state.dataIPShortCut;
    5029              : 
    5030          132 :     auto &cCurrentModuleObject = state.dataIPShortCut->cCurrentModuleObject;
    5031          132 :     cCurrentModuleObject = "AirTerminal:SingleDuct:Mixer";
    5032          132 :     state.dataSingleDuct->NumATMixers = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
    5033          132 :     state.dataSingleDuct->SysATMixer.allocate(state.dataSingleDuct->NumATMixers);
    5034              : 
    5035              :     // make sure the input data is read in only once
    5036          132 :     if (state.dataZoneAirLoopEquipmentManager->GetAirDistUnitsFlag) {
    5037              :         // Need air distribution units first
    5038          116 :         ZoneAirLoopEquipmentManager::GetZoneAirLoopEquipment(state);
    5039          116 :         state.dataZoneAirLoopEquipmentManager->GetAirDistUnitsFlag = false;
    5040              :     }
    5041              : 
    5042          155 :     for (ATMixerNum = 1; ATMixerNum <= state.dataSingleDuct->NumATMixers; ++ATMixerNum) {
    5043           46 :         state.dataInputProcessing->inputProcessor->getObjectItem(state,
    5044              :                                                                  cCurrentModuleObject,
    5045              :                                                                  ATMixerNum,
    5046           23 :                                                                  state.dataIPShortCut->cAlphaArgs,
    5047              :                                                                  NumAlphas,
    5048           23 :                                                                  state.dataIPShortCut->rNumericArgs,
    5049              :                                                                  NumNums,
    5050              :                                                                  IOStat,
    5051           23 :                                                                  state.dataIPShortCut->lNumericFieldBlanks,
    5052           23 :                                                                  state.dataIPShortCut->lAlphaFieldBlanks,
    5053           23 :                                                                  state.dataIPShortCut->cAlphaFieldNames,
    5054           23 :                                                                  state.dataIPShortCut->cNumericFieldNames);
    5055              : 
    5056           23 :         auto &atMixer = state.dataSingleDuct->SysATMixer(ATMixerNum);
    5057           23 :         Util::IsNameEmpty(state, state.dataIPShortCut->cAlphaArgs(1), cCurrentModuleObject, ErrorsFound);
    5058           23 :         state.dataSingleDuct->SysATMixer(ATMixerNum).Name = state.dataIPShortCut->cAlphaArgs(1);
    5059              : 
    5060           23 :         atMixer.type = static_cast<HVAC::MixerType>(getEnumValue(HVAC::mixerTypeLocNamesUC, ipsc->cAlphaArgs(7)));
    5061              : 
    5062           23 :         if (state.dataIPShortCut->cAlphaArgs(2) == "ZONEHVAC:WATERTOAIRHEATPUMP") {
    5063            2 :             state.dataSingleDuct->SysATMixer(ATMixerNum).ZoneHVACUnitType = 1;
    5064           21 :         } else if (state.dataIPShortCut->cAlphaArgs(2) == "ZONEHVAC:FOURPIPEFANCOIL") {
    5065            2 :             state.dataSingleDuct->SysATMixer(ATMixerNum).ZoneHVACUnitType = 2;
    5066           19 :         } else if (state.dataIPShortCut->cAlphaArgs(2) == "ZONEHVAC:PACKAGEDTERMINALAIRCONDITIONER") {
    5067            9 :             state.dataSingleDuct->SysATMixer(ATMixerNum).ZoneHVACUnitType = 3;
    5068           10 :         } else if (state.dataIPShortCut->cAlphaArgs(2) == "ZONEHVAC:PACKAGEDTERMINALHEATPUMP") {
    5069            2 :             state.dataSingleDuct->SysATMixer(ATMixerNum).ZoneHVACUnitType = 4;
    5070            8 :         } else if (state.dataIPShortCut->cAlphaArgs(2) == "ZONEHVAC:VARIABLEREFRIGERANTFLOW") {
    5071            0 :             state.dataSingleDuct->SysATMixer(ATMixerNum).ZoneHVACUnitType = 5;
    5072            8 :         } else if (state.dataIPShortCut->cAlphaArgs(2) == "AIRLOOPHVAC:UNITARYSYSTEM") {
    5073            2 :             state.dataSingleDuct->SysATMixer(ATMixerNum).ZoneHVACUnitType = 6;
    5074            6 :         } else if (state.dataIPShortCut->cAlphaArgs(2) == "ZONEHVAC:UNITVENTILATOR") {
    5075            2 :             state.dataSingleDuct->SysATMixer(ATMixerNum).ZoneHVACUnitType = 7;
    5076              :         }
    5077              : 
    5078           23 :         state.dataSingleDuct->SysATMixer(ATMixerNum).ZoneHVACUnitName = state.dataIPShortCut->cAlphaArgs(3);
    5079              : 
    5080           46 :         ValidateComponent(
    5081           23 :             state, state.dataIPShortCut->cAlphaArgs(2), state.dataSingleDuct->SysATMixer(ATMixerNum).ZoneHVACUnitName, errFlag, cCurrentModuleObject);
    5082              : 
    5083           23 :         state.dataSingleDuct->SysATMixer(ATMixerNum).MixedAirOutNode =
    5084           23 :             GetOnlySingleNode(state,
    5085           23 :                               state.dataIPShortCut->cAlphaArgs(4),
    5086              :                               ErrorsFound,
    5087              :                               DataLoopNode::ConnectionObjectType::AirTerminalSingleDuctMixer,
    5088           23 :                               state.dataIPShortCut->cAlphaArgs(1),
    5089              :                               DataLoopNode::NodeFluidType::Air,
    5090              :                               DataLoopNode::ConnectionType::Outlet,
    5091              :                               NodeInputManager::CompFluidStream::Primary,
    5092              :                               ObjectIsNotParent,
    5093           23 :                               state.dataIPShortCut->cAlphaFieldNames(4));
    5094              : 
    5095           23 :         state.dataSingleDuct->SysATMixer(ATMixerNum).PriInNode = GetOnlySingleNode(state,
    5096           23 :                                                                                    state.dataIPShortCut->cAlphaArgs(5),
    5097              :                                                                                    ErrorsFound,
    5098              :                                                                                    DataLoopNode::ConnectionObjectType::AirTerminalSingleDuctMixer,
    5099           23 :                                                                                    state.dataIPShortCut->cAlphaArgs(1),
    5100              :                                                                                    DataLoopNode::NodeFluidType::Air,
    5101              :                                                                                    DataLoopNode::ConnectionType::Inlet,
    5102              :                                                                                    NodeInputManager::CompFluidStream::Primary,
    5103              :                                                                                    ObjectIsNotParent,
    5104           23 :                                                                                    state.dataIPShortCut->cAlphaFieldNames(5));
    5105           23 :         state.dataSingleDuct->SysATMixer(ATMixerNum).SecInNode = GetOnlySingleNode(state,
    5106           23 :                                                                                    state.dataIPShortCut->cAlphaArgs(6),
    5107              :                                                                                    ErrorsFound,
    5108              :                                                                                    DataLoopNode::ConnectionObjectType::AirTerminalSingleDuctMixer,
    5109           23 :                                                                                    state.dataIPShortCut->cAlphaArgs(1),
    5110              :                                                                                    DataLoopNode::NodeFluidType::Air,
    5111              :                                                                                    DataLoopNode::ConnectionType::Inlet,
    5112              :                                                                                    NodeInputManager::CompFluidStream::Primary,
    5113              :                                                                                    ObjectIsNotParent,
    5114           23 :                                                                                    state.dataIPShortCut->cAlphaFieldNames(6));
    5115              : 
    5116           23 :         if (state.dataIPShortCut->lAlphaFieldBlanks(8)) {
    5117           18 :             state.dataSingleDuct->SysATMixer(ATMixerNum).NoOAFlowInputFromUser = true;
    5118              :         } else {
    5119            5 :             state.dataSingleDuct->SysATMixer(ATMixerNum).OARequirementsPtr =
    5120            5 :                 Util::FindItemInList(state.dataIPShortCut->cAlphaArgs(8), state.dataSize->OARequirements);
    5121            5 :             if (state.dataSingleDuct->SysATMixer(ATMixerNum).OARequirementsPtr == 0) {
    5122            0 :                 ShowSevereError(state, format("{}{}=\"{}\", invalid data.", RoutineName, cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
    5123            0 :                 ShowContinueError(state,
    5124            0 :                                   format("..invalid {}=\"{}\".", state.dataIPShortCut->cAlphaFieldNames(8), state.dataIPShortCut->cAlphaArgs(8)));
    5125            0 :                 ErrorsFound = true;
    5126              :             } else {
    5127            5 :                 state.dataSingleDuct->SysATMixer(ATMixerNum).NoOAFlowInputFromUser = false;
    5128              :             }
    5129              :         }
    5130              : 
    5131           23 :         if (state.dataIPShortCut->lAlphaFieldBlanks(9)) {
    5132           19 :             state.dataSingleDuct->SysATMixer(ATMixerNum).OAPerPersonMode = DataZoneEquipment::PerPersonVentRateMode::DCVByCurrentLevel;
    5133              :         } else {
    5134            4 :             if (state.dataIPShortCut->cAlphaArgs(9) == "CURRENTOCCUPANCY") {
    5135            4 :                 state.dataSingleDuct->SysATMixer(ATMixerNum).OAPerPersonMode = DataZoneEquipment::PerPersonVentRateMode::DCVByCurrentLevel;
    5136            0 :             } else if (state.dataIPShortCut->cAlphaArgs(9) == "DESIGNOCCUPANCY") {
    5137            0 :                 state.dataSingleDuct->SysATMixer(ATMixerNum).OAPerPersonMode = DataZoneEquipment::PerPersonVentRateMode::ByDesignLevel;
    5138              :             } else {
    5139            0 :                 state.dataSingleDuct->SysATMixer(ATMixerNum).OAPerPersonMode = DataZoneEquipment::PerPersonVentRateMode::DCVByCurrentLevel;
    5140            0 :                 ShowWarningError(state, format("{}{}=\"{}\", invalid data.", RoutineName, cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
    5141            0 :                 ShowContinueError(state,
    5142            0 :                                   format("..invalid {}=\"{}\". The default input of CurrentOccupancy is assigned",
    5143            0 :                                          state.dataIPShortCut->cAlphaFieldNames(9),
    5144            0 :                                          state.dataIPShortCut->cAlphaArgs(9)));
    5145              :             }
    5146              :         }
    5147              : 
    5148              :         // Check for dupes in the three nodes.
    5149           23 :         if (state.dataSingleDuct->SysATMixer(ATMixerNum).SecInNode == state.dataSingleDuct->SysATMixer(ATMixerNum).PriInNode) {
    5150            0 :             ShowSevereError(state,
    5151            0 :                             format("{} = {} {} = {} duplicates the {}.",
    5152              :                                    cCurrentModuleObject,
    5153            0 :                                    state.dataSingleDuct->SysATMixer(ATMixerNum).Name,
    5154            0 :                                    state.dataIPShortCut->cAlphaArgs(5),
    5155            0 :                                    state.dataLoopNodes->NodeID(state.dataSingleDuct->SysATMixer(ATMixerNum).PriInNode),
    5156            0 :                                    state.dataIPShortCut->cAlphaArgs(4)));
    5157            0 :             ErrorsFound = true;
    5158           23 :         } else if (state.dataSingleDuct->SysATMixer(ATMixerNum).SecInNode == state.dataSingleDuct->SysATMixer(ATMixerNum).MixedAirOutNode) {
    5159            0 :             ShowSevereError(state,
    5160            0 :                             format("{} = {} {} = {} duplicates the {}.",
    5161              :                                    cCurrentModuleObject,
    5162            0 :                                    state.dataSingleDuct->SysATMixer(ATMixerNum).Name,
    5163            0 :                                    state.dataIPShortCut->cAlphaArgs(6),
    5164            0 :                                    state.dataLoopNodes->NodeID(state.dataSingleDuct->SysATMixer(ATMixerNum).MixedAirOutNode),
    5165            0 :                                    state.dataIPShortCut->cAlphaArgs(4)));
    5166            0 :             ErrorsFound = true;
    5167              :         }
    5168              : 
    5169           23 :         if (state.dataSingleDuct->SysATMixer(ATMixerNum).PriInNode == state.dataSingleDuct->SysATMixer(ATMixerNum).MixedAirOutNode) {
    5170            0 :             ShowSevereError(state,
    5171            0 :                             format("{} = {} {} = {} duplicates the {}.",
    5172              :                                    cCurrentModuleObject,
    5173            0 :                                    state.dataSingleDuct->SysATMixer(ATMixerNum).Name,
    5174            0 :                                    state.dataIPShortCut->cAlphaArgs(6),
    5175            0 :                                    state.dataLoopNodes->NodeID(state.dataSingleDuct->SysATMixer(ATMixerNum).MixedAirOutNode),
    5176            0 :                                    state.dataIPShortCut->cAlphaArgs(5)));
    5177            0 :             ErrorsFound = true;
    5178              :         }
    5179              : 
    5180           34 :         for (int ADUNum = 1; ADUNum <= (int)state.dataDefineEquipment->AirDistUnit.size(); ++ADUNum) {
    5181           34 :             if (state.dataSingleDuct->SysATMixer(ATMixerNum).MixedAirOutNode == state.dataDefineEquipment->AirDistUnit(ADUNum).OutletNodeNum) {
    5182           23 :                 state.dataDefineEquipment->AirDistUnit(ADUNum).InletNodeNum = state.dataSingleDuct->SysATMixer(ATMixerNum).PriInNode;
    5183           23 :                 state.dataSingleDuct->SysATMixer(ATMixerNum).ADUNum = ADUNum;
    5184           23 :                 break;
    5185              :             }
    5186              :         }
    5187              :         // one assumes if there isn't one assigned, it's an error?
    5188           23 :         if (state.dataSingleDuct->SysATMixer(ATMixerNum).ADUNum == 0) {
    5189            0 :             ShowSevereError(state,
    5190            0 :                             format("{}No matching Air Distribution Unit, for System = [{},{}].",
    5191              :                                    RoutineName,
    5192              :                                    cCurrentModuleObject,
    5193            0 :                                    state.dataSingleDuct->SysATMixer(ATMixerNum).Name));
    5194            0 :             ShowContinueError(
    5195              :                 state,
    5196            0 :                 format("...should have outlet node = {}", state.dataLoopNodes->NodeID(state.dataSingleDuct->SysATMixer(ATMixerNum).MixedAirOutNode)));
    5197            0 :             ErrorsFound = true;
    5198              :         } else {
    5199              : 
    5200           23 :             if (state.dataSingleDuct->SysATMixer(ATMixerNum).type == HVAC::MixerType::InletSide) {
    5201              :                 // Air Terminal inlet node must be the same as a zone exhaust node
    5202           14 :                 ZoneNodeNotFound = true;
    5203           22 :                 for (CtrlZone = 1; CtrlZone <= state.dataGlobal->NumOfZones; ++CtrlZone) {
    5204           21 :                     if (!state.dataZoneEquip->ZoneEquipConfig(CtrlZone).IsControlled) {
    5205            2 :                         continue;
    5206              :                     }
    5207           22 :                     for (NodeNum = 1; NodeNum <= state.dataZoneEquip->ZoneEquipConfig(CtrlZone).NumExhaustNodes; ++NodeNum) {
    5208           16 :                         if (state.dataSingleDuct->SysATMixer(ATMixerNum).SecInNode ==
    5209           16 :                             state.dataZoneEquip->ZoneEquipConfig(CtrlZone).ExhaustNode(NodeNum)) {
    5210           13 :                             ZoneNodeNotFound = false;
    5211           13 :                             state.dataDefineEquipment->AirDistUnit(state.dataSingleDuct->SysATMixer(ATMixerNum).ADUNum).ZoneEqNum = CtrlZone;
    5212           13 :                             state.dataSingleDuct->SysATMixer(ATMixerNum).ZoneNum = CtrlZone;
    5213              :                             // Must wait until InitATMixer to fill other zone equip config data because ultimate zone inlet node is not known yet
    5214              :                             // for inlet side mixers
    5215           13 :                             if (!state.dataSingleDuct->SysATMixer(ATMixerNum).NoOAFlowInputFromUser) {
    5216            2 :                                 bool UseOccSchFlag = false;
    5217            2 :                                 bool UseMinOASchFlag = false;
    5218            2 :                                 state.dataSingleDuct->SysATMixer(ATMixerNum).DesignPrimaryAirVolRate =
    5219            2 :                                     DataSizing::calcDesignSpecificationOutdoorAir(state,
    5220            2 :                                                                                   state.dataSingleDuct->SysATMixer(ATMixerNum).OARequirementsPtr,
    5221            2 :                                                                                   state.dataSingleDuct->SysATMixer(ATMixerNum).ZoneNum,
    5222              :                                                                                   UseOccSchFlag,
    5223              :                                                                                   UseMinOASchFlag);
    5224              :                             }
    5225           13 :                             goto ControlledZoneLoop_exit;
    5226              :                         }
    5227              :                     }
    5228              :                 }
    5229            1 :             ControlledZoneLoop_exit:;
    5230           14 :                 if (ZoneNodeNotFound) {
    5231            1 :                     bool ZoneNodeFoundAgain = false;
    5232            4 :                     for (CtrlZone = 1; CtrlZone <= state.dataGlobal->NumOfZones; ++CtrlZone) {
    5233            9 :                         for (int Num = 1; Num <= state.dataZoneEquip->ZoneEquipList(CtrlZone).NumOfEquipTypes; ++Num) {
    5234            7 :                             if (Util::SameString(state.dataIPShortCut->cAlphaArgs(3), state.dataZoneEquip->ZoneEquipList(CtrlZone).EquipName(Num)) &&
    5235            1 :                                 Util::SameString(state.dataIPShortCut->cAlphaArgs(2),
    5236            1 :                                                  state.dataZoneEquip->ZoneEquipList(CtrlZone).EquipTypeName(Num))) {
    5237            1 :                                 state.dataDefineEquipment->AirDistUnit(state.dataSingleDuct->SysATMixer(ATMixerNum).ADUNum).ZoneEqNum = CtrlZone;
    5238            1 :                                 state.dataSingleDuct->SysATMixer(ATMixerNum).ZoneNum = CtrlZone;
    5239              :                                 // Must wait until InitATMixer to fill other zone equip config data because ultimate zone inlet node is not known yet
    5240              :                                 // for inlet side mixers
    5241            1 :                                 if (!state.dataSingleDuct->SysATMixer(ATMixerNum).NoOAFlowInputFromUser) {
    5242            1 :                                     bool UseOccSchFlag = false;
    5243            1 :                                     bool UseMinOASchFlag = false;
    5244            1 :                                     state.dataSingleDuct->SysATMixer(ATMixerNum).DesignPrimaryAirVolRate =
    5245            1 :                                         DataSizing::calcDesignSpecificationOutdoorAir(state,
    5246            1 :                                                                                       state.dataSingleDuct->SysATMixer(ATMixerNum).OARequirementsPtr,
    5247            1 :                                                                                       state.dataSingleDuct->SysATMixer(ATMixerNum).ZoneNum,
    5248              :                                                                                       UseOccSchFlag,
    5249              :                                                                                       UseMinOASchFlag);
    5250              :                                 }
    5251            1 :                                 ZoneNodeFoundAgain = true;
    5252            1 :                                 break;
    5253              :                             }
    5254              :                         }
    5255            4 :                         if (ZoneNodeFoundAgain) {
    5256            1 :                             break;
    5257              :                         }
    5258              :                     }
    5259            1 :                     if (!ZoneNodeFoundAgain) {
    5260            0 :                         ShowSevereError(state,
    5261            0 :                                         format("{} = \"{}\". Inlet Side Air Terminal Mixer air inlet node name must be the same as either a zone "
    5262              :                                                "exhaust node name or an induced air node in ZonePlenum.",
    5263              :                                                cCurrentModuleObject,
    5264            0 :                                                state.dataSingleDuct->SysATMixer(ATMixerNum).Name));
    5265            0 :                         ShowContinueError(state, "..Zone exhaust node name is specified in ZoneHVAC:EquipmentConnections object.");
    5266            0 :                         ShowContinueError(state, "..Induced Air Outlet Node name is specified in AirLoopHVAC:ReturnPlenum object.");
    5267            0 :                         ShowContinueError(state,
    5268            0 :                                           format("..Inlet Side CONNECTED Air Terminal Mixer inlet node name = {}",
    5269            0 :                                                  state.dataLoopNodes->NodeID(state.dataSingleDuct->SysATMixer(ATMixerNum).SecInNode)));
    5270            0 :                         ErrorsFound = true;
    5271              :                     }
    5272              :                 }
    5273              :             }
    5274              : 
    5275           23 :             if (state.dataSingleDuct->SysATMixer(ATMixerNum).type == HVAC::MixerType::SupplySide) {
    5276            9 :                 ZoneNodeNotFound = true;
    5277           19 :                 for (CtrlZone = 1; CtrlZone <= state.dataGlobal->NumOfZones; ++CtrlZone) {
    5278           19 :                     if (!state.dataZoneEquip->ZoneEquipConfig(CtrlZone).IsControlled) {
    5279            2 :                         continue;
    5280              :                     }
    5281           26 :                     for (NodeNum = 1; NodeNum <= state.dataZoneEquip->ZoneEquipConfig(CtrlZone).NumInletNodes; ++NodeNum) {
    5282           18 :                         if (state.dataSingleDuct->SysATMixer(ATMixerNum).MixedAirOutNode ==
    5283           18 :                             state.dataZoneEquip->ZoneEquipConfig(CtrlZone).InletNode(NodeNum)) {
    5284            9 :                             ZoneNodeNotFound = false;
    5285            9 :                             state.dataDefineEquipment->AirDistUnit(state.dataSingleDuct->SysATMixer(ATMixerNum).ADUNum).ZoneEqNum = CtrlZone;
    5286            9 :                             state.dataSingleDuct->SysATMixer(ATMixerNum).ZoneNum = CtrlZone;
    5287              :                             // Wait until InitATMixer to fill other zone equip config data
    5288              : 
    5289            9 :                             if (!state.dataSingleDuct->SysATMixer(ATMixerNum).NoOAFlowInputFromUser) {
    5290            2 :                                 bool UseOccSchFlag = false;
    5291            2 :                                 bool UseMinOASchFlag = false;
    5292            2 :                                 state.dataSingleDuct->SysATMixer(ATMixerNum).DesignPrimaryAirVolRate =
    5293            2 :                                     DataSizing::calcDesignSpecificationOutdoorAir(state,
    5294            2 :                                                                                   state.dataSingleDuct->SysATMixer(ATMixerNum).OARequirementsPtr,
    5295            2 :                                                                                   state.dataSingleDuct->SysATMixer(ATMixerNum).ZoneNum,
    5296              :                                                                                   UseOccSchFlag,
    5297              :                                                                                   UseMinOASchFlag);
    5298              :                             }
    5299            9 :                             goto ControlZoneLoop_exit;
    5300              :                         }
    5301              :                     }
    5302              :                 }
    5303            0 :             ControlZoneLoop_exit:;
    5304            9 :                 if (ZoneNodeNotFound) {
    5305            0 :                     ShowSevereError(
    5306              :                         state,
    5307            0 :                         format("{} = \"{}\". Supply Side Air Terminal Mixer air outlet node name must be the same as a zone inlet node name.",
    5308              :                                cCurrentModuleObject,
    5309            0 :                                state.dataSingleDuct->SysATMixer(ATMixerNum).Name));
    5310            0 :                     ShowContinueError(state, "..Zone inlet node name is specified in ZoneHVAC:EquipmentConnections object.");
    5311            0 :                     ShowContinueError(state,
    5312            0 :                                       format("..Supply Side connected Air Terminal Mixer outlet node name = {}",
    5313            0 :                                              state.dataLoopNodes->NodeID(state.dataSingleDuct->SysATMixer(ATMixerNum).MixedAirOutNode)));
    5314            0 :                     ErrorsFound = true;
    5315              :                 }
    5316              :             }
    5317              :         }
    5318           46 :         TestCompSet(state,
    5319              :                     cCurrentModuleObject,
    5320           23 :                     state.dataSingleDuct->SysATMixer(ATMixerNum).Name,
    5321           23 :                     state.dataIPShortCut->cAlphaArgs(5),
    5322           23 :                     state.dataIPShortCut->cAlphaArgs(4),
    5323              :                     "Air Nodes");
    5324              : 
    5325           23 :         if (state.dataSingleDuct->SysATMixer(ATMixerNum).OARequirementsPtr == 0) {
    5326           18 :             if (state.dataSize->ZoneSizingInput.allocated()) {
    5327            9 :                 for (int SizingInputNum = 1; SizingInputNum <= state.dataSize->NumZoneSizingInput; ++SizingInputNum) {
    5328            6 :                     if (state.dataSize->ZoneSizingInput(SizingInputNum).ZoneNum == state.dataSingleDuct->SysATMixer(ATMixerNum).ZoneNum) {
    5329            3 :                         if (state.dataSize->ZoneSizingInput(SizingInputNum).ZoneDesignSpecOAIndex == 0) {
    5330            0 :                             ShowWarningError(
    5331            0 :                                 state, format("{}{}=\"{}\", invalid data.", RoutineName, cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
    5332            0 :                             ShowContinueError(state,
    5333            0 :                                               format("{} is blank in both the mixer and the Sizing:Zone object for the same zone.",
    5334            0 :                                                      state.dataIPShortCut->cAlphaFieldNames(8)));
    5335            0 :                             ShowContinueError(state, "The mixer outdoor airflow rate is set to zero.");
    5336            0 :                             state.dataSingleDuct->SysATMixer(ATMixerNum).DesignPrimaryAirVolRate = 0.0;
    5337              :                         } else {
    5338            3 :                             state.dataSingleDuct->SysATMixer(ATMixerNum).OARequirementsPtr =
    5339            3 :                                 state.dataSize->ZoneSizingInput(SizingInputNum).ZoneDesignSpecOAIndex;
    5340            3 :                             state.dataSingleDuct->SysATMixer(ATMixerNum).DesignPrimaryAirVolRate =
    5341            3 :                                 DataSizing::calcDesignSpecificationOutdoorAir(state,
    5342            3 :                                                                               state.dataSingleDuct->SysATMixer(ATMixerNum).OARequirementsPtr,
    5343            3 :                                                                               state.dataSingleDuct->SysATMixer(ATMixerNum).ZoneNum,
    5344              :                                                                               false,
    5345              :                                                                               false);
    5346            3 :                             state.dataSingleDuct->SysATMixer(ATMixerNum).NoOAFlowInputFromUser = false;
    5347              :                         }
    5348              :                     }
    5349              :                 }
    5350              :             } else {
    5351           30 :                 ShowWarningError(state,
    5352           30 :                                  format("{}is blank and there is no Sizing:Zone for the same zone. The mixer outdoor airflow rate is set to zero.",
    5353           15 :                                         state.dataIPShortCut->cAlphaFieldNames(8)));
    5354           15 :                 state.dataSingleDuct->SysATMixer(ATMixerNum).DesignPrimaryAirVolRate = 0.0;
    5355              :             }
    5356              :         }
    5357           23 :         state.dataSingleDuct->SysATMixer(ATMixerNum).MassFlowRateMaxAvail =
    5358           23 :             state.dataSingleDuct->SysATMixer(ATMixerNum).DesignPrimaryAirVolRate * state.dataEnvrn->StdRhoAir;
    5359              :     }
    5360              : 
    5361          132 :     if (ErrorsFound) {
    5362            0 :         ShowFatalError(state, format("{}Errors found in input.  Program terminates.", RoutineName));
    5363              :     }
    5364              : }
    5365              : 
    5366        65996 : void AirTerminalMixerData::InitATMixer(EnergyPlusData &state, bool const FirstHVACIteration)
    5367              : {
    5368              :     // Purpose: Initialize the AirTerminalMixers data structure with node data
    5369        65996 :     if (this->OneTimeInitFlag) {
    5370              :         {
    5371           21 :             auto &thisADU(state.dataDefineEquipment->AirDistUnit(this->ADUNum));
    5372              :             {
    5373           21 :                 auto &thisZoneEqConfig(state.dataZoneEquip->ZoneEquipConfig(thisADU.ZoneEqNum));
    5374           42 :                 for (int SupAirIn = 1; SupAirIn <= thisZoneEqConfig.NumInletNodes; ++SupAirIn) {
    5375           21 :                     if (this->ZoneInletNode == thisZoneEqConfig.InletNode(SupAirIn)) {
    5376           21 :                         thisZoneEqConfig.AirDistUnitCool(SupAirIn).InNode = this->PriInNode;
    5377           21 :                         thisZoneEqConfig.AirDistUnitCool(SupAirIn).OutNode = this->MixedAirOutNode;
    5378           21 :                         thisZoneEqConfig.AirDistUnitHeat(SupAirIn).InNode = this->PriInNode;
    5379           21 :                         thisZoneEqConfig.AirDistUnitHeat(SupAirIn).OutNode = this->MixedAirOutNode;
    5380           21 :                         thisADU.TermUnitSizingNum = thisZoneEqConfig.AirDistUnitCool(SupAirIn).TermUnitSizingIndex;
    5381           21 :                         this->CtrlZoneInNodeIndex = SupAirIn;
    5382              :                         {
    5383           21 :                             auto &thisTermUnitSizingData(state.dataSize->TermUnitSizing(thisADU.TermUnitSizingNum));
    5384           21 :                             thisTermUnitSizingData.ADUName = thisADU.Name;
    5385              :                             // Fill TermUnitSizing with specs from DesignSpecification:AirTerminal:Sizing if there is one attached to this
    5386              :                             // terminal unit
    5387           21 :                             if (thisADU.AirTerminalSizingSpecIndex > 0) {
    5388              :                                 {
    5389            0 :                                     auto const &thisAirTermSizingSpec(state.dataSize->AirTerminalSizingSpec(thisADU.AirTerminalSizingSpecIndex));
    5390            0 :                                     thisTermUnitSizingData.SpecDesCoolSATRatio = thisAirTermSizingSpec.DesCoolSATRatio;
    5391            0 :                                     thisTermUnitSizingData.SpecDesHeatSATRatio = thisAirTermSizingSpec.DesHeatSATRatio;
    5392            0 :                                     thisTermUnitSizingData.SpecDesSensCoolingFrac = thisAirTermSizingSpec.DesSensCoolingFrac;
    5393            0 :                                     thisTermUnitSizingData.SpecDesSensHeatingFrac = thisAirTermSizingSpec.DesSensHeatingFrac;
    5394            0 :                                     thisTermUnitSizingData.SpecMinOAFrac = thisAirTermSizingSpec.MinOAFrac;
    5395              :                                 }
    5396              :                             }
    5397              :                         }
    5398              :                     }
    5399              :                 }
    5400              :             }
    5401              :         }
    5402           21 :         this->OneTimeInitFlag = false;
    5403              :     }
    5404              : 
    5405              :     // Keep trying until we find it, the airloopnum, that is
    5406        65996 :     if (this->OneTimeInitFlag2) {
    5407          164 :         this->AirLoopNum = state.dataZoneEquip->ZoneEquipConfig(state.dataDefineEquipment->AirDistUnit(this->ADUNum).ZoneEqNum)
    5408          164 :                                .InletNodeAirLoopNum(this->CtrlZoneInNodeIndex);
    5409          164 :         state.dataDefineEquipment->AirDistUnit(this->ADUNum).AirLoopNum = this->AirLoopNum;
    5410          164 :         if (this->AirLoopNum > 0) {
    5411            6 :             this->OneTimeInitFlag2 = false;
    5412              :         }
    5413              :     }
    5414              : 
    5415              :     // Every iteration
    5416        65996 :     Real64 mDotFromOARequirement(0.0);
    5417        65996 :     Real64 vDotOAReq(0.0);
    5418        65996 :     if (!this->NoOAFlowInputFromUser) {
    5419        65873 :         Real64 airLoopOAFrac(0.0);
    5420        65873 :         bool UseOccSchFlag = false;
    5421        65873 :         if (this->OAPerPersonMode == DataZoneEquipment::PerPersonVentRateMode::DCVByCurrentLevel) {
    5422        65872 :             UseOccSchFlag = true;
    5423              :         }
    5424        65873 :         if (this->AirLoopNum > 0) {
    5425        65838 :             airLoopOAFrac = state.dataAirLoop->AirLoopFlow(this->AirLoopNum).OAFrac;
    5426        65838 :             if (airLoopOAFrac > 0.0) {
    5427        42570 :                 vDotOAReq = DataSizing::calcDesignSpecificationOutdoorAir(state, this->OARequirementsPtr, this->ZoneNum, UseOccSchFlag, true);
    5428        42570 :                 mDotFromOARequirement = vDotOAReq * state.dataEnvrn->StdRhoAir / airLoopOAFrac;
    5429              :             } else {
    5430        23268 :                 mDotFromOARequirement = state.dataLoopNodes->Node(this->PriInNode).MassFlowRate;
    5431              :             }
    5432              :         }
    5433        65873 :         if (FirstHVACIteration) {
    5434        32759 :             state.dataLoopNodes->Node(this->PriInNode).MassFlowRate = mDotFromOARequirement;
    5435        32759 :             state.dataLoopNodes->Node(this->PriInNode).MassFlowRateMaxAvail = this->MassFlowRateMaxAvail;
    5436        32759 :             state.dataLoopNodes->Node(this->PriInNode).MassFlowRateMinAvail = 0.0;
    5437              :         } else {
    5438        33114 :             state.dataLoopNodes->Node(this->PriInNode).MassFlowRate = mDotFromOARequirement;
    5439              : 
    5440        33114 :             state.dataLoopNodes->Node(this->PriInNode).MassFlowRate =
    5441        33114 :                 min(state.dataLoopNodes->Node(this->PriInNode).MassFlowRate, state.dataLoopNodes->Node(this->PriInNode).MassFlowRateMaxAvail);
    5442        33114 :             state.dataLoopNodes->Node(this->PriInNode).MassFlowRate =
    5443        33114 :                 max(state.dataLoopNodes->Node(this->PriInNode).MassFlowRate, state.dataLoopNodes->Node(this->PriInNode).MassFlowRateMinAvail);
    5444        33114 :             state.dataLoopNodes->Node(this->PriInNode).MassFlowRate =
    5445        33114 :                 max(state.dataLoopNodes->Node(this->PriInNode).MassFlowRate, state.dataLoopNodes->Node(this->PriInNode).MassFlowRateMin);
    5446              :         }
    5447              :     }
    5448        65996 :     if (this->type == HVAC::MixerType::InletSide) {
    5449        65902 :         state.dataLoopNodes->Node(this->PriInNode).MassFlowRate =
    5450        65902 :             min(state.dataLoopNodes->Node(this->PriInNode).MassFlowRate, state.dataLoopNodes->Node(this->MixedAirOutNode).MassFlowRate);
    5451              :     }
    5452        65996 : }
    5453              : 
    5454        65969 : void CalcATMixer(EnergyPlusData &state, int const SysNum)
    5455              : {
    5456              : 
    5457              :     // SUBROUTINE INFORMATION:
    5458              :     //       DATE WRITTEN   March 2012
    5459              : 
    5460              :     // PURPOSE OF THIS SUBROUTINE
    5461              :     // Calculate the mixed air flow and conditions in the air terminal mixer
    5462              : 
    5463        65969 :     auto &atMixer = state.dataSingleDuct->SysATMixer(SysNum);
    5464        65969 :     auto &priInNode = state.dataLoopNodes->Node(atMixer.PriInNode);
    5465        65969 :     auto &secInNode = state.dataLoopNodes->Node(atMixer.SecInNode);
    5466        65969 :     auto &mixedAirOutNode = state.dataLoopNodes->Node(atMixer.MixedAirOutNode);
    5467              : 
    5468        65969 :     Real64 MixedAirMassFlowRate =
    5469        65969 :         (atMixer.type == HVAC::MixerType::SupplySide) ? secInNode.MassFlowRate + priInNode.MassFlowRate : mixedAirOutNode.MassFlowRate;
    5470              : 
    5471        65969 :     if (atMixer.type == HVAC::MixerType::InletSide) {
    5472              :         // for inlet side mixer, the mixed air flow has been set, but we don't know the secondary flow
    5473        65887 :         secInNode.MassFlowRate = max(MixedAirMassFlowRate - priInNode.MassFlowRate, 0.0);
    5474        65887 :         if (std::abs(priInNode.MassFlowRate + secInNode.MassFlowRate - MixedAirMassFlowRate) > SmallMassFlow) {
    5475            0 :             ShowSevereError(state, format("CalcATMixer: Invalid mass flow rates in AirTerminal:SingleDuct:Mixer={}", atMixer.Name));
    5476            0 :             ShowContinueErrorTimeStamp(state,
    5477            0 :                                        format("Primary mass flow rate={:.6R}Secondary mass flow rate={:.6R}Mixed mass flow rate={:.6R}",
    5478            0 :                                               priInNode.MassFlowRate,
    5479            0 :                                               secInNode.MassFlowRate,
    5480              :                                               MixedAirMassFlowRate));
    5481            0 :             ShowFatalError(state, "Simulation terminates.");
    5482              :         }
    5483              :     }
    5484              :     // now calculate the mixed (outlet) conditions
    5485        65969 :     if ((atMixer.MixedAirMassFlowRate = MixedAirMassFlowRate) > 0.0) {
    5486        54316 :         Real64 MixedAirEnthalpy = (secInNode.MassFlowRate * secInNode.Enthalpy + priInNode.MassFlowRate * priInNode.Enthalpy) / MixedAirMassFlowRate;
    5487        54316 :         Real64 MixedAirHumRat = (secInNode.MassFlowRate * secInNode.HumRat + priInNode.MassFlowRate * priInNode.HumRat) / MixedAirMassFlowRate;
    5488              :         // Mixed air temperature is calculated from the mixed air enthalpy and humidity ratio.
    5489        54316 :         atMixer.MixedAirTemp = Psychrometrics::PsyTdbFnHW(MixedAirEnthalpy, MixedAirHumRat);
    5490        54316 :         atMixer.MixedAirEnthalpy = MixedAirEnthalpy;
    5491        54316 :         atMixer.MixedAirHumRat = MixedAirHumRat;
    5492              :     } else {
    5493        11653 :         atMixer.MixedAirEnthalpy = priInNode.Enthalpy;
    5494        11653 :         atMixer.MixedAirHumRat = priInNode.HumRat;
    5495        11653 :         atMixer.MixedAirTemp = priInNode.Temp;
    5496              :     }
    5497        65969 : }
    5498              : 
    5499        65969 : void UpdateATMixer(EnergyPlusData &state, int const SysNum)
    5500              : {
    5501              : 
    5502              :     // SUBROUTINE INFORMATION:
    5503              :     //       DATE WRITTEN   March 2012
    5504              : 
    5505              :     // PURPOSE OF THIS SUBROUTINE
    5506              :     // Move the results of CalcATMixer to the affected nodes
    5507              : 
    5508              :     // Using/Aliasing
    5509              :     using namespace DataLoopNode;
    5510              : 
    5511              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    5512        65969 :     int PriInNode = state.dataSingleDuct->SysATMixer(SysNum).PriInNode;
    5513        65969 :     int SecInNode = state.dataSingleDuct->SysATMixer(SysNum).SecInNode;
    5514        65969 :     int MixedAirOutNode = state.dataSingleDuct->SysATMixer(SysNum).MixedAirOutNode;
    5515              : 
    5516              :     // mixed air data
    5517        65969 :     state.dataLoopNodes->Node(MixedAirOutNode).Temp = state.dataSingleDuct->SysATMixer(SysNum).MixedAirTemp;
    5518        65969 :     state.dataLoopNodes->Node(MixedAirOutNode).HumRat = state.dataSingleDuct->SysATMixer(SysNum).MixedAirHumRat;
    5519        65969 :     state.dataLoopNodes->Node(MixedAirOutNode).Enthalpy = state.dataSingleDuct->SysATMixer(SysNum).MixedAirEnthalpy;
    5520        65969 :     state.dataLoopNodes->Node(MixedAirOutNode).Press = state.dataSingleDuct->SysATMixer(SysNum).MixedAirPressure;
    5521        65969 :     state.dataLoopNodes->Node(MixedAirOutNode).MassFlowRate = state.dataSingleDuct->SysATMixer(SysNum).MixedAirMassFlowRate;
    5522              : 
    5523        65969 :     if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
    5524            0 :         if (state.dataSingleDuct->SysATMixer(SysNum).MixedAirMassFlowRate <= HVAC::VerySmallMassFlow) {
    5525            0 :             state.dataLoopNodes->Node(MixedAirOutNode).CO2 = state.dataLoopNodes->Node(PriInNode).CO2;
    5526              :         } else {
    5527            0 :             state.dataLoopNodes->Node(MixedAirOutNode).CO2 =
    5528            0 :                 (state.dataLoopNodes->Node(SecInNode).MassFlowRate * state.dataLoopNodes->Node(SecInNode).CO2 +
    5529            0 :                  state.dataLoopNodes->Node(PriInNode).MassFlowRate * state.dataLoopNodes->Node(PriInNode).CO2) /
    5530            0 :                 state.dataLoopNodes->Node(MixedAirOutNode).MassFlowRate;
    5531              :         }
    5532              :     }
    5533              : 
    5534        65969 :     if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
    5535            0 :         if (state.dataSingleDuct->SysATMixer(SysNum).MixedAirMassFlowRate <= HVAC::VerySmallMassFlow) {
    5536            0 :             state.dataLoopNodes->Node(MixedAirOutNode).GenContam = state.dataLoopNodes->Node(PriInNode).GenContam;
    5537              :         } else {
    5538            0 :             state.dataLoopNodes->Node(MixedAirOutNode).GenContam =
    5539            0 :                 (state.dataLoopNodes->Node(SecInNode).MassFlowRate * state.dataLoopNodes->Node(SecInNode).GenContam +
    5540            0 :                  state.dataLoopNodes->Node(PriInNode).MassFlowRate * state.dataLoopNodes->Node(PriInNode).GenContam) /
    5541            0 :                 state.dataLoopNodes->Node(MixedAirOutNode).MassFlowRate;
    5542              :         }
    5543              :     }
    5544              : 
    5545              :     // update ADU flow data - because SimATMixer is called from the various zone equipment so the updates in SimZoneAirLoopEquipment won't work
    5546        65969 :     int aduNum = state.dataSingleDuct->SysATMixer(SysNum).ADUNum;
    5547        65969 :     state.dataDefineEquipment->AirDistUnit(aduNum).MassFlowRateTU = state.dataLoopNodes->Node(PriInNode).MassFlowRate;
    5548        65969 :     state.dataDefineEquipment->AirDistUnit(aduNum).MassFlowRateZSup = state.dataLoopNodes->Node(PriInNode).MassFlowRate;
    5549        65969 :     state.dataDefineEquipment->AirDistUnit(aduNum).MassFlowRateSup = state.dataLoopNodes->Node(PriInNode).MassFlowRate;
    5550        65969 : }
    5551              : 
    5552          160 : void GetATMixer(EnergyPlusData &state,
    5553              :                 std::string const &ZoneEquipName, // zone unit name name
    5554              :                 std::string &ATMixerName,         // air terminal mixer name
    5555              :                 int &ATMixerNum,                  // air terminal mixer index
    5556              :                 HVAC::MixerType &ATMixerType,     // air teminal mixer type
    5557              :                 int &ATMixerPriNode,              // air terminal mixer primary air node number
    5558              :                 int &ATMixerSecNode,              // air terminal mixer secondary air node number
    5559              :                 int &ATMixerOutNode,              // air terminal mixer outlet air node number
    5560              :                 int const ZoneEquipOutletNode     // zone equipment outlet node (used with inlet side mixers)
    5561              : )
    5562              : {
    5563              : 
    5564              :     // SUBROUTINE INFORMATION:
    5565              :     //       AUTHOR         Fred Buhl
    5566              :     //       DATE WRITTEN   April 2012
    5567              : 
    5568              :     // PURPOSE OF THIS SUBROUTINE:
    5569              :     // This subroutine gets: 1) the index of the named AT Mixer in the SysATMixer data array
    5570              :     //                       2) the node number of the primary air inlet node of the AT Mixer
    5571              :     //                       3) set the AT Mixer ultimate zone inlet node
    5572              : 
    5573              :     int ATMixerIndex; // local air terminal mixer index
    5574              : 
    5575          160 :     if (state.dataSingleDuct->GetATMixerFlag) {
    5576          129 :         GetATMixers(state);
    5577          129 :         state.dataSingleDuct->GetATMixerFlag = false;
    5578              :     }
    5579              : 
    5580          160 :     if (state.dataSingleDuct->NumATMixers <= 0) {
    5581          138 :         ATMixerNum = 0;
    5582          138 :         ATMixerName = "";
    5583          138 :         ATMixerPriNode = 0;
    5584          138 :         ATMixerSecNode = 0;
    5585          138 :         ATMixerOutNode = 0;
    5586          138 :         ATMixerType = HVAC::MixerType::Invalid;
    5587          138 :         return;
    5588              :     }
    5589              : 
    5590           22 :     ATMixerIndex = Util::FindItemInList(ZoneEquipName, state.dataSingleDuct->SysATMixer, &AirTerminalMixerData::ZoneHVACUnitName);
    5591           22 :     if (ATMixerIndex > 0) {
    5592           21 :         ATMixerNum = ATMixerIndex;
    5593           21 :         ATMixerName = state.dataSingleDuct->SysATMixer(ATMixerIndex).Name;
    5594           21 :         ATMixerPriNode = state.dataSingleDuct->SysATMixer(ATMixerIndex).PriInNode;
    5595           21 :         ATMixerSecNode = state.dataSingleDuct->SysATMixer(ATMixerIndex).SecInNode;
    5596           21 :         ATMixerOutNode = state.dataSingleDuct->SysATMixer(ATMixerIndex).MixedAirOutNode;
    5597           21 :         ATMixerType = state.dataSingleDuct->SysATMixer(ATMixerIndex).type;
    5598           21 :         if (ATMixerType == HVAC::MixerType::InletSide) {
    5599           13 :             state.dataSingleDuct->SysATMixer(ATMixerIndex).ZoneInletNode = ZoneEquipOutletNode;
    5600              :         } else {
    5601            8 :             state.dataSingleDuct->SysATMixer(ATMixerIndex).ZoneInletNode = ATMixerOutNode;
    5602              :         }
    5603           21 :         state.dataSingleDuct->SysATMixer(ATMixerNum).InitATMixer(state, false);
    5604              :     } else {
    5605            1 :         ATMixerNum = 0;
    5606            1 :         ATMixerName = "";
    5607            1 :         ATMixerPriNode = 0;
    5608            1 :         ATMixerSecNode = 0;
    5609            1 :         ATMixerOutNode = 0;
    5610            1 :         ATMixerType = HVAC::MixerType::Invalid;
    5611              :     }
    5612              : }
    5613              : 
    5614           18 : void setATMixerSizingProperties(EnergyPlusData &state,
    5615              :                                 int const inletATMixerIndex, // index to ATMixer at inlet of zone equipment
    5616              :                                 int const controlledZoneNum, // controlled zone number
    5617              :                                 int const curZoneEqNum       // current zone equipment being simulated
    5618              : )
    5619              : {
    5620              : 
    5621           18 :     if (inletATMixerIndex == 0) {
    5622            4 :         return; // protect this function from bad inputs
    5623              :     }
    5624           18 :     if (controlledZoneNum == 0) {
    5625            0 :         return;
    5626              :     }
    5627           18 :     if (curZoneEqNum == 0) {
    5628            0 :         return;
    5629              :     }
    5630           18 :     if (state.dataSingleDuct->SysATMixer(inletATMixerIndex).type == HVAC::MixerType::Invalid) {
    5631            0 :         return;
    5632              :     }
    5633              : 
    5634              :     // ATMixer properties only affect coil sizing when the mixer is on the inlet side of zone equipment
    5635           18 :     if (state.dataSingleDuct->SysATMixer(inletATMixerIndex).type == HVAC::MixerType::SupplySide) {
    5636              :         // check if user has selected No to account for DOAS system
    5637            4 :         if (state.dataSize->FinalZoneSizing.allocated() && state.dataSingleDuct->SysATMixer(inletATMixerIndex).printWarning) {
    5638            0 :             auto const &finalZoneSizing = state.dataSize->FinalZoneSizing(curZoneEqNum);
    5639            0 :             if (!finalZoneSizing.AccountForDOAS && finalZoneSizing.DOASControlStrategy != DOASControl::NeutralSup) {
    5640            0 :                 ShowWarningError(state, format("AirTerminal:SingleDuct:Mixer: {}", state.dataSingleDuct->SysATMixer(inletATMixerIndex).Name));
    5641            0 :                 ShowContinueError(
    5642              :                     state,
    5643              :                     " Supply side Air Terminal Mixer does not adjust zone equipment coil sizing and may result in inappropriately sized coils.");
    5644            0 :                 ShowContinueError(
    5645              :                     state,
    5646            0 :                     format(" Set Account for Dedicated Outdoor Air System = Yes in Sizing:Zone object for zone = {}", finalZoneSizing.ZoneName));
    5647              :             }
    5648            0 :             state.dataSingleDuct->SysATMixer(inletATMixerIndex).printWarning = false;
    5649              :         }
    5650            4 :         return; // do nothing else if this is a supply side ATMixer
    5651              :     }
    5652              :     // check if user has selected Yes to account for DOAS system
    5653           14 :     if (state.dataSize->FinalZoneSizing.allocated() && state.dataSingleDuct->SysATMixer(inletATMixerIndex).printWarning) {
    5654            6 :         auto const &finalZoneSizing = state.dataSize->FinalZoneSizing(curZoneEqNum);
    5655            6 :         if (finalZoneSizing.AccountForDOAS && finalZoneSizing.DOASControlStrategy != DOASControl::NeutralSup) {
    5656            0 :             ShowWarningError(state, format("AirTerminal:SingleDuct:Mixer: {}", state.dataSingleDuct->SysATMixer(inletATMixerIndex).Name));
    5657            0 :             ShowContinueError(state, " Inlet side Air Terminal Mixer automatically adjusts zone equipment coil sizing.");
    5658            0 :             ShowContinueError(
    5659            0 :                 state, format(" Set Account for Dedicated Outdoor Air System = No in Sizing:Zone object for zone = {}", finalZoneSizing.ZoneName));
    5660            0 :             state.dataSingleDuct->SysATMixer(inletATMixerIndex).printWarning = false;
    5661              :         }
    5662              :     }
    5663              : 
    5664              :     // proceed to set ATMixer properties used for sizing coils
    5665              : 
    5666              :     int airLoopIndex = // find air loop associated with ATMixer
    5667           14 :         state.dataZoneEquip->ZoneEquipConfig(controlledZoneNum)
    5668           14 :             .InletNodeAirLoopNum(state.dataSingleDuct->SysATMixer(inletATMixerIndex).CtrlZoneInNodeIndex);
    5669              : 
    5670              :     // must be a system sizing run or calculations are not possible
    5671           14 :     bool SizingDesRunThisAirSys = false;                                      // Sizing:System object found flag
    5672           14 :     CheckThisAirSystemForSizing(state, airLoopIndex, SizingDesRunThisAirSys); // check for Sizing:System object
    5673              : 
    5674           14 :     if (SizingDesRunThisAirSys) {
    5675            8 :         auto &finalSysSizing = state.dataSize->FinalSysSizing(airLoopIndex);
    5676            8 :         auto &zoneEqSizing = state.dataSize->ZoneEqSizing(curZoneEqNum);
    5677              : 
    5678              :         // set ATMixer outlet air flow rate in ZoneEqSizing array for ATMixer. If this value > 0, then the Sizer will know an ATMixer exists
    5679            8 :         zoneEqSizing.ATMixerVolFlow = state.dataSingleDuct->SysATMixer(inletATMixerIndex).DesignPrimaryAirVolRate;
    5680              : 
    5681              :         // If air loop has heating coil use SA conditions, else if OA sys has coils then use precool conditions, else use OA conditions
    5682            8 :         if (state.dataAirSystemsData->PrimaryAirSystems(airLoopIndex).CentralHeatCoilExists) {
    5683              :             // if central heating coil exists, ATMixer outlet is assumed to be at supply air conditions described in sizing input
    5684            1 :             zoneEqSizing.ATMixerHeatPriDryBulb = finalSysSizing.HeatSupTemp;
    5685            1 :             zoneEqSizing.ATMixerHeatPriHumRat = finalSysSizing.HeatSupHumRat;
    5686            7 :         } else if (state.dataAirSystemsData->PrimaryAirSystems(airLoopIndex).NumOAHeatCoils > 0) {
    5687              :             // if no central heating coil exists and an outdoor air coil does exist, then ATMixer outlet is mixture of preheat and return
    5688            2 :             if (finalSysSizing.DesMainVolFlow == 0.0) { // protect divide by 0
    5689              :                 // doesn't matter, just pick a condition
    5690            0 :                 zoneEqSizing.ATMixerHeatPriDryBulb = finalSysSizing.PreheatTemp;
    5691            0 :                 zoneEqSizing.ATMixerHeatPriHumRat = finalSysSizing.PreheatHumRat;
    5692              :             } else {
    5693              :                 // mix preheat condition with return air condition based on OA frac. OA frac should nearly always be 1.
    5694              :                 // OA frac is based on air loop fraction, not ATMixer flow fraction since air loop can serve multiple ATMixers
    5695            2 :                 Real64 OutAirFrac = finalSysSizing.DesOutAirVolFlow / finalSysSizing.DesMainVolFlow;
    5696            2 :                 OutAirFrac = min(1.0, max(0.0, OutAirFrac));
    5697              : 
    5698              :                 // calculate humrat based on simple mixing
    5699            2 :                 Real64 CoilInHumRatForSizing = OutAirFrac * finalSysSizing.PreheatHumRat + (1 - OutAirFrac) * finalSysSizing.HeatRetHumRat;
    5700              : 
    5701              :                 // calculate enthalpy based on simple mixing
    5702              :                 Real64 CoilInEnthalpyForSizing =
    5703            2 :                     OutAirFrac * Psychrometrics::PsyHFnTdbW(finalSysSizing.PreheatTemp, finalSysSizing.PreheatHumRat) +
    5704            2 :                     (1 - OutAirFrac) * Psychrometrics::PsyHFnTdbW(finalSysSizing.HeatRetTemp, finalSysSizing.HeatRetHumRat);
    5705              : 
    5706              :                 // back calculate temperature based on humrat and enthalpy state points
    5707            2 :                 Real64 CoilInTempForSizing = Psychrometrics::PsyTdbFnHW(CoilInEnthalpyForSizing, CoilInHumRatForSizing);
    5708              : 
    5709            2 :                 zoneEqSizing.ATMixerHeatPriDryBulb = CoilInTempForSizing;
    5710            2 :                 zoneEqSizing.ATMixerHeatPriHumRat = CoilInHumRatForSizing;
    5711              :             }
    5712              :         } else {
    5713              :             // else no coils exist in air loop so mix OA condition with return air condition
    5714            5 :             if (finalSysSizing.DesMainVolFlow == 0.0) { // protect divide by 0
    5715              :                 // doesn't matter, just pick a condition
    5716            0 :                 zoneEqSizing.ATMixerHeatPriDryBulb = finalSysSizing.HeatOutTemp;
    5717            0 :                 zoneEqSizing.ATMixerHeatPriHumRat = finalSysSizing.HeatOutHumRat;
    5718              :             } else {
    5719              :                 // OA frac is based on air loop fraction, not ATMixer flow fraction since air loop can serve multiple ATMixers
    5720            5 :                 Real64 OutAirFrac = finalSysSizing.DesOutAirVolFlow / finalSysSizing.DesMainVolFlow;
    5721            5 :                 OutAirFrac = min(1.0, max(0.0, OutAirFrac));
    5722              : 
    5723              :                 // calculate humrat based on simple mixing
    5724            5 :                 Real64 CoilInHumRatForSizing = OutAirFrac * finalSysSizing.HeatOutHumRat + (1 - OutAirFrac) * finalSysSizing.HeatRetHumRat;
    5725              : 
    5726              :                 // calculate enthalpy based on simple mixing
    5727              :                 Real64 CoilInEnthalpyForSizing =
    5728            5 :                     OutAirFrac * Psychrometrics::PsyHFnTdbW(finalSysSizing.HeatOutTemp, finalSysSizing.HeatOutHumRat) +
    5729            5 :                     (1 - OutAirFrac) * Psychrometrics::PsyHFnTdbW(finalSysSizing.HeatRetTemp, finalSysSizing.HeatRetHumRat);
    5730              : 
    5731              :                 // back calculate temperature based on humrat and enthalpy state points
    5732            5 :                 Real64 CoilInTempForSizing = Psychrometrics::PsyTdbFnHW(CoilInEnthalpyForSizing, CoilInHumRatForSizing);
    5733              : 
    5734            5 :                 zoneEqSizing.ATMixerHeatPriDryBulb = CoilInTempForSizing;
    5735            5 :                 zoneEqSizing.ATMixerHeatPriHumRat = CoilInHumRatForSizing;
    5736              :             }
    5737              :         }
    5738              : 
    5739              :         // If air loop has cooling coil use SA conditions, else if OA sys has coils then use precool conditions, else use OA conditions
    5740            8 :         if (state.dataAirSystemsData->PrimaryAirSystems(airLoopIndex).CentralCoolCoilExists) {
    5741              :             // if central cooling coil exists, ATMixer outlet is assumed to be at supply air conditions described in sizing input
    5742            1 :             zoneEqSizing.ATMixerCoolPriDryBulb = finalSysSizing.CoolSupTemp;
    5743            1 :             zoneEqSizing.ATMixerCoolPriHumRat = finalSysSizing.CoolSupHumRat;
    5744            7 :         } else if (state.dataAirSystemsData->PrimaryAirSystems(airLoopIndex).NumOACoolCoils > 0) {
    5745              :             // if no central cooling coil exists and an outdoor air coil does exist, then ATMixer outlet is mixture of precool and return
    5746            2 :             if (finalSysSizing.DesMainVolFlow == 0.0) { // protect divide by 0
    5747              :                 // doesn't matter, just pick a condition
    5748            0 :                 zoneEqSizing.ATMixerCoolPriDryBulb = finalSysSizing.PrecoolTemp;
    5749            0 :                 zoneEqSizing.ATMixerCoolPriHumRat = finalSysSizing.PrecoolHumRat;
    5750              :             } else {
    5751              :                 // mix precool condition with return air condition based on OA frac. OA frac should nearly always be 1.
    5752              :                 // OA frac is based on air loop fraction, not ATMixer flow fraction since air loop can serve multiple ATMixers
    5753            2 :                 Real64 OutAirFrac = finalSysSizing.DesOutAirVolFlow / finalSysSizing.DesMainVolFlow;
    5754            2 :                 OutAirFrac = min(1.0, max(0.0, OutAirFrac));
    5755              : 
    5756              :                 // calculate humrat based on simple mixing
    5757            2 :                 Real64 CoilInHumRatForSizing = OutAirFrac * finalSysSizing.PrecoolHumRat + (1 - OutAirFrac) * finalSysSizing.RetHumRatAtCoolPeak;
    5758              : 
    5759              :                 // calculate enthalpy based on simple mixing
    5760              :                 Real64 CoilInEnthalpyForSizing =
    5761            2 :                     OutAirFrac * Psychrometrics::PsyHFnTdbW(finalSysSizing.PrecoolTemp, finalSysSizing.PrecoolHumRat) +
    5762            2 :                     (1 - OutAirFrac) * Psychrometrics::PsyHFnTdbW(finalSysSizing.RetTempAtCoolPeak, finalSysSizing.RetHumRatAtCoolPeak);
    5763              : 
    5764              :                 // back calculate temperature based on humrat and enthalpy state points
    5765            2 :                 Real64 CoilInTempForSizing = Psychrometrics::PsyTdbFnHW(CoilInEnthalpyForSizing, CoilInHumRatForSizing);
    5766              : 
    5767            2 :                 zoneEqSizing.ATMixerCoolPriDryBulb = CoilInTempForSizing;
    5768            2 :                 zoneEqSizing.ATMixerCoolPriHumRat = CoilInHumRatForSizing;
    5769              :             }
    5770              :         } else {
    5771              :             // else no coils exist in air loop so mix OA condition with return air condition
    5772            5 :             if (finalSysSizing.DesMainVolFlow == 0.0) { // protect divide by 0
    5773              :                 // doesn't matter, just pick a condition
    5774            0 :                 zoneEqSizing.ATMixerCoolPriDryBulb = finalSysSizing.OutTempAtCoolPeak;
    5775            0 :                 zoneEqSizing.ATMixerCoolPriHumRat = finalSysSizing.OutHumRatAtCoolPeak;
    5776              :             } else {
    5777              :                 // OA frac is based on air loop fraction, not ATMixer flow fraction since air loop can serve multiple ATMixers
    5778            5 :                 Real64 OutAirFrac = finalSysSizing.DesOutAirVolFlow / finalSysSizing.DesMainVolFlow;
    5779            5 :                 OutAirFrac = min(1.0, max(0.0, OutAirFrac));
    5780              : 
    5781              :                 // calculate humrat based on simple mixing
    5782            5 :                 Real64 CoilInHumRatForSizing =
    5783            5 :                     OutAirFrac * finalSysSizing.OutHumRatAtCoolPeak + (1 - OutAirFrac) * finalSysSizing.RetHumRatAtCoolPeak;
    5784              : 
    5785              :                 // calculate enthalpy based on simple mixing
    5786              :                 Real64 CoilInEnthalpyForSizing =
    5787            5 :                     OutAirFrac * Psychrometrics::PsyHFnTdbW(finalSysSizing.OutTempAtCoolPeak, finalSysSizing.OutHumRatAtCoolPeak) +
    5788            5 :                     (1 - OutAirFrac) * Psychrometrics::PsyHFnTdbW(finalSysSizing.RetTempAtCoolPeak, finalSysSizing.RetHumRatAtCoolPeak);
    5789              : 
    5790              :                 // back calculate temperature based on humrat and enthalpy state points
    5791            5 :                 Real64 CoilInTempForSizing = Psychrometrics::PsyTdbFnHW(CoilInEnthalpyForSizing, CoilInHumRatForSizing);
    5792              : 
    5793            5 :                 zoneEqSizing.ATMixerCoolPriDryBulb = CoilInTempForSizing;
    5794            5 :                 zoneEqSizing.ATMixerCoolPriHumRat = CoilInHumRatForSizing;
    5795              :             }
    5796              :         }
    5797              : 
    5798              :     } else {
    5799              :         // warn user that system sizing is needed to size coils when AT Mixer is used ?
    5800              :         // if there were a message here then this function should only be called when SizingDesRunThisZone is true
    5801              :     }
    5802              : }
    5803              : 
    5804        97455 : void SingleDuctAirTerminal::CalcOutdoorAirVolumeFlowRate(EnergyPlusData &state)
    5805              : {
    5806              :     // calculates zone outdoor air volume flow rate using the supply air flow rate and OA fraction
    5807        97455 :     if (this->AirLoopNum > 0) {
    5808        97384 :         this->OutdoorAirFlowRate =
    5809        97384 :             (this->sd_airterminalOutlet.AirMassFlowRate / state.dataEnvrn->StdRhoAir) * state.dataAirLoop->AirLoopFlow(this->AirLoopNum).OAFrac;
    5810              :     } else {
    5811           71 :         this->OutdoorAirFlowRate = 0.0;
    5812              :     }
    5813        97455 : }
    5814              : 
    5815           29 : void SingleDuctAirTerminal::reportTerminalUnit(EnergyPlusData &state)
    5816              : {
    5817              :     // populate the predefined equipment summary report related to air terminals
    5818           29 :     auto &orp = state.dataOutRptPredefined;
    5819           29 :     auto &adu = state.dataDefineEquipment->AirDistUnit(this->ADUNum);
    5820           29 :     if (!state.dataSize->TermUnitFinalZoneSizing.empty()) {
    5821           26 :         auto &sizing = state.dataSize->TermUnitFinalZoneSizing(adu.TermUnitSizingNum);
    5822           26 :         OutputReportPredefined::PreDefTableEntry(state, orp->pdchAirTermMinFlow, adu.Name, sizing.DesCoolVolFlowMin);
    5823           26 :         OutputReportPredefined::PreDefTableEntry(state, orp->pdchAirTermMinOutdoorFlow, adu.Name, sizing.MinOA);
    5824           26 :         OutputReportPredefined::PreDefTableEntry(state, orp->pdchAirTermSupCoolingSP, adu.Name, sizing.CoolDesTemp);
    5825           26 :         OutputReportPredefined::PreDefTableEntry(state, orp->pdchAirTermSupHeatingSP, adu.Name, sizing.HeatDesTemp);
    5826           26 :         OutputReportPredefined::PreDefTableEntry(state, orp->pdchAirTermHeatingCap, adu.Name, sizing.DesHeatLoad);
    5827           26 :         OutputReportPredefined::PreDefTableEntry(state, orp->pdchAirTermCoolingCap, adu.Name, sizing.DesCoolLoad);
    5828              :     }
    5829           29 :     OutputReportPredefined::PreDefTableEntry(state, orp->pdchAirTermTypeInp, adu.Name, this->sysType);
    5830           29 :     OutputReportPredefined::PreDefTableEntry(state, orp->pdchAirTermPrimFlow, adu.Name, this->MaxAirVolFlowRate);
    5831           29 :     OutputReportPredefined::PreDefTableEntry(state, orp->pdchAirTermSecdFlow, adu.Name, "n/a");
    5832           29 :     if (this->zoneMinAirFracSched != nullptr) {
    5833            1 :         OutputReportPredefined::PreDefTableEntry(state, orp->pdchAirTermMinFlowSch, adu.Name, this->zoneMinAirFracSched->Name);
    5834              :     } else {
    5835           28 :         OutputReportPredefined::PreDefTableEntry(state, orp->pdchAirTermMinFlowSch, adu.Name, "n/a");
    5836              :     }
    5837           29 :     OutputReportPredefined::PreDefTableEntry(state, orp->pdchAirTermMaxFlowReh, adu.Name, this->MaxAirVolFlowRateDuringReheat);
    5838           29 :     std::string schName = "n/a";
    5839           29 :     if (this->OARequirementsPtr > 0) {
    5840            1 :         auto const *minOASched = state.dataSize->OARequirements(this->OARequirementsPtr).oaFlowFracSched;
    5841            1 :         if (minOASched != nullptr) {
    5842            1 :             schName = minOASched->Name;
    5843              :         }
    5844              :     }
    5845           29 :     OutputReportPredefined::PreDefTableEntry(state, orp->pdchAirTermMinOAflowSch, adu.Name, schName);
    5846           29 :     OutputReportPredefined::PreDefTableEntry(state, orp->pdchAirTermHeatCoilType, adu.Name, this->ReheatComp);
    5847           29 :     OutputReportPredefined::PreDefTableEntry(state, orp->pdchAirTermCoolCoilType, adu.Name, "n/a");
    5848           29 :     if (this->fanType != HVAC::FanType::Invalid) {
    5849            2 :         OutputReportPredefined::PreDefTableEntry(state, orp->pdchAirTermFanType, adu.Name, HVAC::fanTypeNames[(int)this->fanType]);
    5850              :     } else {
    5851           27 :         OutputReportPredefined::PreDefTableEntry(state, orp->pdchAirTermFanType, adu.Name, "n/a");
    5852              :     }
    5853           29 :     OutputReportPredefined::PreDefTableEntry(state, orp->pdchAirTermFanName, adu.Name, this->FanName);
    5854           29 : }
    5855              : 
    5856              : //        End of Reporting subroutines for the Sys Module
    5857              : // *****************************************************************************
    5858              : 
    5859              : } // namespace EnergyPlus::SingleDuct
        

Generated by: LCOV version 2.0-1