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

Generated by: LCOV version 2.0-1