LCOV - code coverage report
Current view: top level - EnergyPlus - OutdoorAirUnit.cc (source / functions) Coverage Total Hit
Test: lcov.output.filtered Lines: 56.2 % 1189 668
Test Date: 2025-05-22 16:09:37 Functions: 100.0 % 14 14

            Line data    Source code
       1              : // EnergyPlus, Copyright (c) 1996-2025, The Board of Trustees of the University of Illinois,
       2              : // The Regents of the University of California, through Lawrence Berkeley National Laboratory
       3              : // (subject to receipt of any required approvals from the U.S. Dept. of Energy), Oak Ridge
       4              : // National Laboratory, managed by UT-Battelle, Alliance for Sustainable Energy, LLC, and other
       5              : // contributors. All rights reserved.
       6              : //
       7              : // NOTICE: This Software was developed under funding from the U.S. Department of Energy and the
       8              : // U.S. Government consequently retains certain rights. As such, the U.S. Government has been
       9              : // granted for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable,
      10              : // worldwide license in the Software to reproduce, distribute copies to the public, prepare
      11              : // derivative works, and perform publicly and display publicly, and to permit others to do so.
      12              : //
      13              : // Redistribution and use in source and binary forms, with or without modification, are permitted
      14              : // provided that the following conditions are met:
      15              : //
      16              : // (1) Redistributions of source code must retain the above copyright notice, this list of
      17              : //     conditions and the following disclaimer.
      18              : //
      19              : // (2) Redistributions in binary form must reproduce the above copyright notice, this list of
      20              : //     conditions and the following disclaimer in the documentation and/or other materials
      21              : //     provided with the distribution.
      22              : //
      23              : // (3) Neither the name of the University of California, Lawrence Berkeley National Laboratory,
      24              : //     the University of Illinois, U.S. Dept. of Energy nor the names of its contributors may be
      25              : //     used to endorse or promote products derived from this software without specific prior
      26              : //     written permission.
      27              : //
      28              : // (4) Use of EnergyPlus(TM) Name. If Licensee (i) distributes the software in stand-alone form
      29              : //     without changes from the version obtained under this License, or (ii) Licensee makes a
      30              : //     reference solely to the software portion of its product, Licensee must refer to the
      31              : //     software as "EnergyPlus version X" software, where "X" is the version number Licensee
      32              : //     obtained under this License and may not use a different name for the software. Except as
      33              : //     specifically required in this Section (4), Licensee shall not use in a company name, a
      34              : //     product name, in advertising, publicity, or other promotional activities any name, trade
      35              : //     name, trademark, logo, or other designation of "EnergyPlus", "E+", "e+" or confusingly
      36              : //     similar designation, without the U.S. Department of Energy's prior written consent.
      37              : //
      38              : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
      39              : // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
      40              : // AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
      41              : // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
      42              : // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
      43              : // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      44              : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
      45              : // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
      46              : // POSSIBILITY OF SUCH DAMAGE.
      47              : 
      48              : // C++ Headers
      49              : #include <cmath>
      50              : 
      51              : // ObjexxFCL Headers
      52              : #include <ObjexxFCL/Array.functions.hh>
      53              : #include <ObjexxFCL/Fmath.hh>
      54              : 
      55              : // EnergyPlus Headers
      56              : #include <EnergyPlus/Autosizing/Base.hh>
      57              : #include <EnergyPlus/BranchNodeConnections.hh>
      58              : #include <EnergyPlus/Data/EnergyPlusData.hh>
      59              : #include <EnergyPlus/DataAirSystems.hh>
      60              : #include <EnergyPlus/DataEnvironment.hh>
      61              : #include <EnergyPlus/DataHVACGlobals.hh>
      62              : #include <EnergyPlus/DataIPShortCuts.hh>
      63              : #include <EnergyPlus/DataLoopNode.hh>
      64              : #include <EnergyPlus/DataSizing.hh>
      65              : #include <EnergyPlus/DataZoneEquipment.hh>
      66              : #include <EnergyPlus/DesiccantDehumidifiers.hh>
      67              : #include <EnergyPlus/Fans.hh>
      68              : #include <EnergyPlus/FluidProperties.hh>
      69              : #include <EnergyPlus/General.hh>
      70              : #include <EnergyPlus/GeneralRoutines.hh>
      71              : #include <EnergyPlus/GlobalNames.hh>
      72              : #include <EnergyPlus/HVACDXHeatPumpSystem.hh>
      73              : #include <EnergyPlus/HVACHXAssistedCoolingCoil.hh>
      74              : #include <EnergyPlus/HeatRecovery.hh>
      75              : #include <EnergyPlus/HeatingCoils.hh>
      76              : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
      77              : #include <EnergyPlus/NodeInputManager.hh>
      78              : #include <EnergyPlus/OutAirNodeManager.hh>
      79              : #include <EnergyPlus/OutdoorAirUnit.hh>
      80              : #include <EnergyPlus/OutputProcessor.hh>
      81              : #include <EnergyPlus/PlantUtilities.hh>
      82              : #include <EnergyPlus/Psychrometrics.hh>
      83              : #include <EnergyPlus/ScheduleManager.hh>
      84              : #include <EnergyPlus/SteamCoils.hh>
      85              : #include <EnergyPlus/UnitarySystem.hh>
      86              : #include <EnergyPlus/UtilityRoutines.hh>
      87              : #include <EnergyPlus/WaterCoils.hh>
      88              : #include <EnergyPlus/ZoneTempPredictorCorrector.hh>
      89              : 
      90              : namespace EnergyPlus {
      91              : 
      92              : namespace OutdoorAirUnit {
      93              :     // Module containing the routines dealing with the outdoor air unit
      94              : 
      95              :     // MODULE INFORMATION:
      96              :     //       AUTHOR         Young Tae Chae, Rick Strand
      97              :     //       DATE WRITTEN   AUG. 2009
      98              :     //       MODIFIED
      99              :     //                      Feb 2013 Bereket Nigusse, FSEC
     100              :     //                        Added DX Coil Model For 100% OA systems
     101              :     //       RE-ENGINEERED  na
     102              : 
     103              :     // PURPOSE OF THIS MODULE:
     104              :     // Simulate zone outdoor air unit.
     105              : 
     106              :     // METHODOLOGY EMPLOYED:
     107              :     // Systems are modeled as a collection of components:
     108              :     // fan, heat recovery, dehumidifier, heating coil and/or cooling coil plus an integrated control
     109              :     // algorithm that adjusts the hot or cold water flow to meet the setpoint
     110              :     // condition.
     111              : 
     112              :     // Using/Aliasing
     113              :     using namespace DataLoopNode;
     114              :     using HVAC::SmallAirVolFlow;
     115              :     using HVAC::SmallLoad;
     116              :     using HVAC::SmallMassFlow;
     117              :     using namespace Psychrometrics;
     118              : 
     119              :     // component types addressed by this module
     120              :     constexpr static std::string_view ZoneHVACOAUnit = {"ZoneHVAC:OutdoorAirUnit"};
     121              :     constexpr static std::string_view ZoneHVACEqList = {"ZoneHVAC:OutdoorAirUnit:EquipmentList"};
     122              : 
     123            1 :     void SimOutdoorAirUnit(EnergyPlusData &state,
     124              :                            std::string_view CompName,     // name of the outdoor air unit
     125              :                            int const ZoneNum,             // number of zone being served
     126              :                            bool const FirstHVACIteration, // TRUE if 1st HVAC simulation of system timestep
     127              :                            Real64 &PowerMet,              // Sensible power supplied (W)
     128              :                            Real64 &LatOutputProvided,     // Latent add/removal supplied by window AC (kg/s), dehumid = negative
     129              :                            int &CompIndex)
     130              :     {
     131              : 
     132              :         // SUBROUTINE INFORMATION:
     133              :         //       AUTHOR         Rick Strand
     134              :         //       DATE WRITTEN   May 2000
     135              :         //       MODIFIED       na
     136              :         //       RE-ENGINEERED
     137              :         // This is re-engineered by Rick Strand and Young T. Chae for OutdoorAirUnit (July, 2009)
     138              : 
     139              :         // PURPOSE OF THIS SUBROUTINE:
     140              :         // This is the main driver subroutine for the outdoor air control unit simulation.
     141              : 
     142              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     143            1 :         int OAUnitNum = 0; // index of outdoor air unit being simulated
     144              : 
     145            1 :         if (state.dataOutdoorAirUnit->GetOutdoorAirUnitInputFlag) {
     146            0 :             GetOutdoorAirUnitInputs(state);
     147            0 :             state.dataOutdoorAirUnit->GetOutdoorAirUnitInputFlag = false;
     148              :         }
     149              : 
     150              :         // Find the correct Outdoor Air Unit
     151              : 
     152            1 :         if (CompIndex == 0) {
     153            1 :             OAUnitNum = Util::FindItemInList(CompName, state.dataOutdoorAirUnit->OutAirUnit);
     154            1 :             if (OAUnitNum == 0) {
     155            0 :                 ShowFatalError(state, format("ZoneHVAC:OutdoorAirUnit not found={}", CompName));
     156              :             }
     157            1 :             CompIndex = OAUnitNum;
     158              :         } else {
     159            0 :             OAUnitNum = CompIndex;
     160            0 :             if (OAUnitNum > state.dataOutdoorAirUnit->NumOfOAUnits || OAUnitNum < 1) {
     161            0 :                 ShowFatalError(state,
     162            0 :                                format("SimOutdoorAirUnit:  Invalid CompIndex passed={}, Number of Units={}, Entered Unit name={}",
     163              :                                       OAUnitNum,
     164            0 :                                       state.dataOutdoorAirUnit->NumOfOAUnits,
     165              :                                       CompName));
     166              :             }
     167            0 :             if (state.dataOutdoorAirUnit->CheckEquipName(OAUnitNum)) {
     168            0 :                 if (CompName != state.dataOutdoorAirUnit->OutAirUnit(OAUnitNum).Name) {
     169            0 :                     ShowFatalError(state,
     170            0 :                                    format("SimOutdoorAirUnit: Invalid CompIndex passed={}, Unit name={}, stored Unit Name for that index={}",
     171              :                                           OAUnitNum,
     172              :                                           CompName,
     173            0 :                                           state.dataOutdoorAirUnit->OutAirUnit(OAUnitNum).Name));
     174              :                 }
     175            0 :                 state.dataOutdoorAirUnit->CheckEquipName(OAUnitNum) = false;
     176              :             }
     177              :         }
     178              : 
     179            1 :         state.dataSize->ZoneEqOutdoorAirUnit = true;
     180              : 
     181            1 :         if (state.dataGlobal->ZoneSizingCalc || state.dataGlobal->SysSizingCalc) {
     182            0 :             return;
     183              :         }
     184              : 
     185            1 :         InitOutdoorAirUnit(state, OAUnitNum, ZoneNum, FirstHVACIteration);
     186              : 
     187            1 :         CalcOutdoorAirUnit(state, OAUnitNum, ZoneNum, FirstHVACIteration, PowerMet, LatOutputProvided);
     188              : 
     189            1 :         ReportOutdoorAirUnit(state, OAUnitNum);
     190              : 
     191            1 :         state.dataSize->ZoneEqOutdoorAirUnit = false;
     192              :     }
     193              : 
     194            3 :     void GetOutdoorAirUnitInputs(EnergyPlusData &state)
     195              :     {
     196              : 
     197              :         // SUBROUTINE INFORMATION:
     198              :         //       AUTHOR         Young Tae Chae, Rick Strand
     199              :         //       DATE WRITTEN   July 2009
     200              :         //       MODIFIED       July 2012, Chandan Sharma - FSEC: Added zone sys avail managers
     201              :         //       RE-ENGINEERED  na
     202              : 
     203              :         // PURPOSE OF THIS SUBROUTINE:
     204              :         // This subroutine obtains the input for the outdoor air control unit and sets
     205              :         // up the appropriate derived type.
     206              : 
     207              :         // METHODOLOGY EMPLOYED:
     208              :         // Standard EnergyPlus methodology.
     209              : 
     210              :         // REFERENCES:
     211              :         // Fred Buhl's fan coil module (FanCoilUnits.cc)
     212              :         // Kwang Ho Lee's Unit Ventilator Module (UnitVentilator.cc)
     213              :         // Young Tae Chae's Ventilated Slab System (VentilatedSlab.cc)
     214              :         // Mixed Air.cc
     215              : 
     216              :         // Using/Aliasing
     217              :         using BranchNodeConnections::SetUpCompSets;
     218              :         using BranchNodeConnections::TestCompSet;
     219              :         using NodeInputManager::GetOnlySingleNode;
     220              :         using SteamCoils::GetCoilAirInletNode;
     221              :         using SteamCoils::GetCoilAirOutletNode;
     222              :         using SteamCoils::GetCoilMaxSteamFlowRate;
     223              :         using SteamCoils::GetCoilSteamInletNode;
     224              :         using SteamCoils::GetCoilSteamOutletNode;
     225              :         using SteamCoils::GetSteamCoilIndex;
     226              :         using namespace DataLoopNode;
     227              :         using HeatingCoils::GetCoilInletNode;
     228              :         using HeatingCoils::GetCoilOutletNode;
     229              :         using OutAirNodeManager::CheckAndAddAirNodeNumber;
     230              :         using WaterCoils::GetCoilWaterInletNode;
     231              :         using WaterCoils::GetCoilWaterOutletNode;
     232              :         using WaterCoils::GetWaterCoilIndex;
     233              : 
     234              :         // SUBROUTINE PARAMETER DEFINITIONS:
     235              :         static constexpr std::string_view RoutineName("GetOutdoorAirUnitInputs: "); // include trailing blank space
     236              :         static constexpr std::string_view routineName = "GetOutdoorAirUnitInputs";  // include trailing blank space
     237              : 
     238              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     239              : 
     240            3 :         if (!state.dataOutdoorAirUnit->GetOutdoorAirUnitInputFlag) {
     241            0 :             return;
     242              :         }
     243              : 
     244            3 :         int NumAlphas = 0;        // Number of elements in the alpha array
     245            3 :         int NumNums = 0;          // Number of elements in the numeric array
     246            3 :         Array1D_string AlphArray; // character string data
     247            3 :         Array1D<Real64> NumArray; // numeric data
     248            3 :         int IOStat = -1;          // IO Status when calling get input subroutine
     249            3 :         bool ErrorsFound = false;
     250              : 
     251            3 :         int MaxNums = 0;                 // Maximum number of numeric input fields
     252            3 :         int MaxAlphas = 0;               // Maximum number of alpha input fields
     253            3 :         int TotalArgs = 0;               // Total number of alpha and numeric arguments (max) for a
     254              :         bool IsValid;                    // Set for outside air node check
     255            3 :         Array1D_string cAlphaArgs;       // Alpha input items for object
     256            3 :         std::string CurrentModuleObject; // Object type for getting and messages
     257            3 :         Array1D_string cAlphaFields;     // Alpha field names
     258            3 :         Array1D_string cNumericFields;   // Numeric field names
     259            3 :         Array1D_bool lAlphaBlanks;       // Logical array, alpha field input BLANK = .TRUE.
     260            3 :         Array1D_bool lNumericBlanks;     // Logical array, numeric field input BLANK = .TRUE.
     261              : 
     262              :         // Figure out how many outdoor air units there are in the input file
     263              : 
     264            3 :         state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, ZoneHVACOAUnit, TotalArgs, NumAlphas, NumNums);
     265            3 :         MaxNums = max(MaxNums, NumNums);
     266            3 :         MaxAlphas = max(MaxAlphas, NumAlphas);
     267            3 :         state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, ZoneHVACEqList, TotalArgs, NumAlphas, NumNums);
     268            3 :         MaxNums = max(MaxNums, NumNums);
     269            3 :         MaxAlphas = max(MaxAlphas, NumAlphas);
     270              : 
     271            3 :         AlphArray.allocate(MaxAlphas);
     272            3 :         cAlphaFields.allocate(MaxAlphas);
     273            3 :         NumArray.dimension(MaxNums, 0.0);
     274            3 :         cNumericFields.allocate(MaxNums);
     275            3 :         lAlphaBlanks.dimension(MaxAlphas, true);
     276            3 :         lNumericBlanks.dimension(MaxNums, true);
     277            3 :         cAlphaArgs.allocate(NumAlphas);
     278              : 
     279            3 :         CurrentModuleObject = ZoneHVACOAUnit;
     280            3 :         state.dataOutdoorAirUnit->NumOfOAUnits = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject);
     281              : 
     282            3 :         state.dataOutdoorAirUnit->OutAirUnit.allocate(state.dataOutdoorAirUnit->NumOfOAUnits);
     283            3 :         state.dataOutdoorAirUnit->SupplyFanUniqueNames.reserve(static_cast<unsigned>(state.dataOutdoorAirUnit->NumOfOAUnits));
     284            3 :         state.dataOutdoorAirUnit->ExhaustFanUniqueNames.reserve(static_cast<unsigned>(state.dataOutdoorAirUnit->NumOfOAUnits));
     285            3 :         state.dataOutdoorAirUnit->ComponentListUniqueNames.reserve(static_cast<unsigned>(state.dataOutdoorAirUnit->NumOfOAUnits));
     286            3 :         state.dataOutdoorAirUnit->MyOneTimeErrorFlag.dimension(state.dataOutdoorAirUnit->NumOfOAUnits, true);
     287            3 :         state.dataOutdoorAirUnit->CheckEquipName.dimension(state.dataOutdoorAirUnit->NumOfOAUnits, true);
     288              : 
     289            6 :         for (int OAUnitNum = 1; OAUnitNum <= state.dataOutdoorAirUnit->NumOfOAUnits; ++OAUnitNum) {
     290              : 
     291            3 :             auto &thisOutAirUnit = state.dataOutdoorAirUnit->OutAirUnit(OAUnitNum);
     292              : 
     293            6 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
     294              :                                                                      CurrentModuleObject,
     295              :                                                                      OAUnitNum,
     296            3 :                                                                      state.dataIPShortCut->cAlphaArgs,
     297              :                                                                      NumAlphas,
     298              :                                                                      NumArray,
     299              :                                                                      NumNums,
     300              :                                                                      IOStat,
     301              :                                                                      lNumericBlanks,
     302              :                                                                      lAlphaBlanks,
     303              :                                                                      cAlphaFields,
     304              :                                                                      cNumericFields);
     305              : 
     306            3 :             ErrorObjectHeader eoh{routineName, CurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)};
     307            3 :             Util::IsNameEmpty(state, state.dataIPShortCut->cAlphaArgs(1), CurrentModuleObject, ErrorsFound);
     308              : 
     309              :             // A1
     310            3 :             thisOutAirUnit.Name = state.dataIPShortCut->cAlphaArgs(1);
     311              : 
     312              :             // A2
     313            3 :             if (lAlphaBlanks(2)) {
     314            0 :                 thisOutAirUnit.availSched = Sched::GetScheduleAlwaysOn(state);
     315            3 :             } else if ((thisOutAirUnit.availSched = Sched::GetSchedule(state, state.dataIPShortCut->cAlphaArgs(2))) == nullptr) {
     316            0 :                 ShowSevereItemNotFound(state, eoh, state.dataIPShortCut->cAlphaArgs(2), state.dataIPShortCut->cAlphaArgs(2));
     317            0 :                 ErrorsFound = true;
     318              :             }
     319              : 
     320              :             // A3
     321            3 :             thisOutAirUnit.ZoneName = state.dataIPShortCut->cAlphaArgs(3);
     322            3 :             thisOutAirUnit.ZonePtr = Util::FindItemInList(state.dataIPShortCut->cAlphaArgs(3), state.dataHeatBal->Zone);
     323              : 
     324            3 :             if (thisOutAirUnit.ZonePtr == 0) {
     325            0 :                 if (lAlphaBlanks(3)) {
     326            0 :                     ShowSevereError(state,
     327            0 :                                     format("{}=\"{}\" invalid {} is required but input is blank.",
     328              :                                            CurrentModuleObject,
     329            0 :                                            state.dataIPShortCut->cAlphaArgs(1),
     330            0 :                                            state.dataIPShortCut->cAlphaArgs(3)));
     331              :                 } else {
     332            0 :                     ShowSevereError(state,
     333            0 :                                     format("{}=\"{}\" invalid {}=\"{}\" not found.",
     334              :                                            CurrentModuleObject,
     335            0 :                                            state.dataIPShortCut->cAlphaArgs(1),
     336            0 :                                            state.dataIPShortCut->cAlphaArgs(3),
     337            0 :                                            state.dataIPShortCut->cAlphaArgs(3)));
     338              :                 }
     339            0 :                 ErrorsFound = true;
     340              :             }
     341            3 :             thisOutAirUnit.ZoneNodeNum = state.dataHeatBal->Zone(thisOutAirUnit.ZonePtr).SystemZoneNodeNumber;
     342              :             // Outside air information:
     343              :             // N1
     344            3 :             thisOutAirUnit.OutAirVolFlow = NumArray(1);
     345              :             // A4
     346            3 :             if (lAlphaBlanks(4)) {
     347            0 :                 ShowSevereEmptyField(state, eoh, cAlphaFields(4));
     348            0 :                 ErrorsFound = true;
     349            3 :             } else if ((thisOutAirUnit.outAirSched = Sched::GetSchedule(state, state.dataIPShortCut->cAlphaArgs(4))) == nullptr) {
     350            0 :                 ShowSevereItemNotFound(state, eoh, cAlphaFields(4), state.dataIPShortCut->cAlphaArgs(4));
     351            0 :                 ErrorsFound = true;
     352              :             }
     353              : 
     354              :             // A5
     355            3 :             thisOutAirUnit.SFanName = state.dataIPShortCut->cAlphaArgs(5);
     356            3 :             GlobalNames::IntraObjUniquenessCheck(state,
     357            3 :                                                  state.dataIPShortCut->cAlphaArgs(5),
     358              :                                                  CurrentModuleObject,
     359            3 :                                                  cAlphaFields(5),
     360            3 :                                                  state.dataOutdoorAirUnit->SupplyFanUniqueNames,
     361              :                                                  ErrorsFound);
     362              : 
     363            3 :             if ((thisOutAirUnit.SFan_Index = Fans::GetFanIndex(state, thisOutAirUnit.SFanName)) == 0) {
     364            0 :                 ShowSevereItemNotFound(state, eoh, state.dataIPShortCut->cAlphaFieldNames(5), thisOutAirUnit.SFanName);
     365            0 :                 ErrorsFound = true;
     366              :             } else {
     367            3 :                 auto *fan = state.dataFans->fans(thisOutAirUnit.SFan_Index);
     368            3 :                 thisOutAirUnit.supFanType = fan->type;
     369            3 :                 thisOutAirUnit.SFanMaxAirVolFlow = fan->maxAirFlowRate;
     370            3 :                 thisOutAirUnit.supFanAvailSched = fan->availSched;
     371              :             }
     372              :             // A6 :Fan Place
     373            3 :             thisOutAirUnit.supFanPlace = static_cast<HVAC::FanPlace>(getEnumValue(HVAC::fanPlaceNamesUC, state.dataIPShortCut->cAlphaArgs(6)));
     374              : 
     375              :             // A7
     376              : 
     377            3 :             if (lAlphaBlanks(7)) {
     378            0 :                 thisOutAirUnit.ExtFan = false;
     379            0 :                 if (!state.dataHeatBal->ZoneAirMassFlow.EnforceZoneMassBalance) {
     380            0 :                     ShowWarningError(state,
     381            0 :                                      format("{}=\"{}\", {} is blank.", CurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1), cAlphaFields(7)));
     382            0 :                     ShowContinueError(state,
     383              :                                       "Unbalanced mass flow rates between supply from outdoor air and exhaust from zone air will be introduced.");
     384              :                 }
     385            3 :             } else if (!lAlphaBlanks(7)) {
     386            3 :                 thisOutAirUnit.ExtFanName = state.dataIPShortCut->cAlphaArgs(7);
     387            3 :                 GlobalNames::IntraObjUniquenessCheck(state,
     388            3 :                                                      state.dataIPShortCut->cAlphaArgs(7),
     389              :                                                      CurrentModuleObject,
     390            3 :                                                      cAlphaFields(7),
     391            3 :                                                      state.dataOutdoorAirUnit->ExhaustFanUniqueNames,
     392              :                                                      ErrorsFound);
     393              : 
     394            3 :                 if ((thisOutAirUnit.ExtFan_Index = Fans::GetFanIndex(state, thisOutAirUnit.ExtFanName)) == 0) {
     395            0 :                     ShowSevereItemNotFound(state, eoh, state.dataIPShortCut->cAlphaFieldNames(7), thisOutAirUnit.ExtFanName);
     396            0 :                     ErrorsFound = true;
     397              :                 } else {
     398            3 :                     auto *fan = state.dataFans->fans(thisOutAirUnit.ExtFan_Index);
     399            3 :                     thisOutAirUnit.extFanType = fan->type;
     400            3 :                     thisOutAirUnit.EFanMaxAirVolFlow = fan->maxAirFlowRate;
     401            3 :                     thisOutAirUnit.extFanAvailSched = fan->availSched;
     402              :                 }
     403            3 :                 thisOutAirUnit.ExtFan = true;
     404              :             }
     405              : 
     406              :             // N2
     407            3 :             thisOutAirUnit.ExtAirVolFlow = NumArray(2);
     408            3 :             if ((thisOutAirUnit.ExtFan) && (!state.dataHeatBal->ZoneAirMassFlow.EnforceZoneMassBalance)) {
     409            3 :                 if (NumArray(2) != NumArray(1)) {
     410            0 :                     ShowWarningError(state,
     411            0 :                                      format("{}=\"{}\", {} and {} are not equal. This may cause unbalanced flow.",
     412              :                                             CurrentModuleObject,
     413            0 :                                             state.dataIPShortCut->cAlphaArgs(1),
     414              :                                             cNumericFields(1),
     415              :                                             cNumericFields(2)));
     416            0 :                     ShowContinueError(state, format("{}={:.3R}= and {}{:.3R}", cNumericFields(1), NumArray(1), cNumericFields(2), NumArray(2)));
     417              :                 }
     418              :             }
     419              :             // A8
     420              : 
     421              :             // convert schedule name to pointer
     422            3 :             if (thisOutAirUnit.ExtFan) {
     423            3 :                 if (lAlphaBlanks(8)) {
     424            0 :                     ShowSevereEmptyField(state, eoh, cAlphaFields(8));
     425            0 :                     ErrorsFound = true;
     426            3 :                 } else if ((thisOutAirUnit.extAirSched = Sched::GetSchedule(state, state.dataIPShortCut->cAlphaArgs(8))) == nullptr) {
     427            0 :                     ShowSevereItemNotFound(state, eoh, cAlphaFields(8), state.dataIPShortCut->cAlphaArgs(8));
     428            0 :                     ErrorsFound = true;
     429            3 :                 } else if ((thisOutAirUnit.extAirSched != thisOutAirUnit.outAirSched) &&
     430            0 :                            (!state.dataHeatBal->ZoneAirMassFlow.EnforceZoneMassBalance)) {
     431            0 :                     ShowWarningError(
     432              :                         state,
     433            0 :                         format("{}=\"{}\", different schedule inputs for outdoor air and exhaust air schedules may cause unbalanced mass flow.",
     434              :                                CurrentModuleObject,
     435            0 :                                state.dataIPShortCut->cAlphaArgs(1)));
     436            0 :                     ShowContinueError(state,
     437            0 :                                       format("{}={} and {}={}",
     438              :                                              cAlphaFields(4),
     439            0 :                                              state.dataIPShortCut->cAlphaArgs(4),
     440              :                                              cAlphaFields(8),
     441            0 :                                              state.dataIPShortCut->cAlphaArgs(8)));
     442              :                 }
     443              : 
     444            6 :                 SetUpCompSets(
     445            3 :                     state, CurrentModuleObject, thisOutAirUnit.Name, "UNDEFINED", state.dataIPShortCut->cAlphaArgs(7), "UNDEFINED", "UNDEFINED");
     446              :             }
     447              : 
     448              :             // Process the unit control type
     449            3 :             if (lAlphaBlanks(9)) {
     450            0 :                 ShowWarningEmptyField(state, eoh, cAlphaFields(9), "Control reset to Unconditioned Control.");
     451            0 :                 thisOutAirUnit.controlType = OAUnitCtrlType::Neutral;
     452              :             } else {
     453            3 :                 constexpr std::array<std::string_view, (int)OAUnitCtrlType::Num> ctrlTypeNamesUC = {
     454              :                     "NEUTRALCONTROL", "INVALID-UNCONDITIONED", "TEMPERATURECONTROL"};
     455            3 :                 OAUnitCtrlType tmpCtrlType = static_cast<OAUnitCtrlType>(getEnumValue(ctrlTypeNamesUC, state.dataIPShortCut->cAlphaArgs(9)));
     456            3 :                 if (tmpCtrlType == OAUnitCtrlType::Invalid) {
     457            0 :                     ShowWarningEmptyField(state, eoh, cAlphaFields(9), "Control reset to Unconditioned Control.");
     458            3 :                 } else if (tmpCtrlType == OAUnitCtrlType::Neutral || tmpCtrlType == OAUnitCtrlType::Temperature) {
     459            3 :                     thisOutAirUnit.controlType = tmpCtrlType;
     460              :                 }
     461              :             }
     462              : 
     463              :             // A10:High Control Temp :
     464            3 :             if (lAlphaBlanks(10)) {
     465            3 :             } else if ((thisOutAirUnit.hiCtrlTempSched = Sched::GetSchedule(state, state.dataIPShortCut->cAlphaArgs(10))) == nullptr) {
     466            0 :                 ShowSevereItemNotFound(state, eoh, cAlphaFields(10), state.dataIPShortCut->cAlphaArgs(10));
     467            0 :                 ErrorsFound = true;
     468              :             }
     469              : 
     470              :             // A11:Low Control Temp :
     471            3 :             if (lAlphaBlanks(11)) {
     472            3 :             } else if ((thisOutAirUnit.loCtrlTempSched = Sched::GetSchedule(state, state.dataIPShortCut->cAlphaArgs(11))) == nullptr) {
     473            0 :                 ShowSevereItemNotFound(state, eoh, cAlphaFields(11), state.dataIPShortCut->cAlphaArgs(11));
     474            0 :                 ErrorsFound = true;
     475              :             }
     476              : 
     477            3 :             thisOutAirUnit.CompOutSetTemp = 0.0;
     478              : 
     479              :             // A12~A15 : Node Condition
     480              : 
     481              :             // Main air nodes (except outside air node):
     482              : 
     483            3 :             thisOutAirUnit.AirOutletNode = GetOnlySingleNode(state,
     484            3 :                                                              state.dataIPShortCut->cAlphaArgs(13),
     485              :                                                              ErrorsFound,
     486              :                                                              DataLoopNode::ConnectionObjectType::ZoneHVACOutdoorAirUnit,
     487            3 :                                                              state.dataIPShortCut->cAlphaArgs(1),
     488              :                                                              DataLoopNode::NodeFluidType::Air,
     489              :                                                              DataLoopNode::ConnectionType::Outlet,
     490              :                                                              NodeInputManager::CompFluidStream::Primary,
     491              :                                                              ObjectIsParent);
     492            3 :             if (!lAlphaBlanks(14)) {
     493            6 :                 thisOutAirUnit.AirInletNode = GetOnlySingleNode(state,
     494            3 :                                                                 state.dataIPShortCut->cAlphaArgs(14),
     495              :                                                                 ErrorsFound,
     496              :                                                                 DataLoopNode::ConnectionObjectType::ZoneHVACOutdoorAirUnit,
     497            3 :                                                                 state.dataIPShortCut->cAlphaArgs(1),
     498              :                                                                 DataLoopNode::NodeFluidType::Air,
     499              :                                                                 DataLoopNode::ConnectionType::Inlet,
     500              :                                                                 NodeInputManager::CompFluidStream::Primary,
     501              :                                                                 ObjectIsParent);
     502              :             } else {
     503            0 :                 if (thisOutAirUnit.ExtFan) {
     504            0 :                     ShowSevereError(state,
     505            0 :                                     format("{}=\"{}\" invalid {} cannot be blank when there is an exhaust fan.",
     506              :                                            CurrentModuleObject,
     507            0 :                                            state.dataIPShortCut->cAlphaArgs(1),
     508              :                                            cAlphaFields(14)));
     509            0 :                     ErrorsFound = true;
     510              :                 }
     511              :             }
     512              : 
     513            3 :             thisOutAirUnit.SFanOutletNode = GetOnlySingleNode(state,
     514            3 :                                                               state.dataIPShortCut->cAlphaArgs(15),
     515              :                                                               ErrorsFound,
     516              :                                                               DataLoopNode::ConnectionObjectType::ZoneHVACOutdoorAirUnit,
     517            3 :                                                               state.dataIPShortCut->cAlphaArgs(1),
     518              :                                                               DataLoopNode::NodeFluidType::Air,
     519              :                                                               DataLoopNode::ConnectionType::Internal,
     520              :                                                               NodeInputManager::CompFluidStream::Primary,
     521              :                                                               ObjectIsNotParent);
     522              : 
     523              :             //  Set connection type to 'OutdoorAir', because this is hardwired to OA conditions
     524            3 :             thisOutAirUnit.OutsideAirNode = GetOnlySingleNode(state,
     525            3 :                                                               state.dataIPShortCut->cAlphaArgs(12),
     526              :                                                               ErrorsFound,
     527              :                                                               DataLoopNode::ConnectionObjectType::ZoneHVACOutdoorAirUnit,
     528            3 :                                                               state.dataIPShortCut->cAlphaArgs(1),
     529              :                                                               DataLoopNode::NodeFluidType::Air,
     530              :                                                               DataLoopNode::ConnectionType::OutsideAirReference,
     531              :                                                               NodeInputManager::CompFluidStream::Primary,
     532              :                                                               ObjectIsNotParent);
     533              : 
     534            3 :             if (!lAlphaBlanks(12)) {
     535            3 :                 CheckAndAddAirNodeNumber(state, thisOutAirUnit.OutsideAirNode, IsValid);
     536            3 :                 if (!IsValid) {
     537            0 :                     ShowWarningError(state,
     538            0 :                                      format("{}=\"{}\", Adding OutdoorAir:Node={}",
     539              :                                             CurrentModuleObject,
     540            0 :                                             state.dataIPShortCut->cAlphaArgs(1),
     541            0 :                                             state.dataIPShortCut->cAlphaArgs(12)));
     542              :                 }
     543              :             }
     544              : 
     545              :             // When the fan position is "BlowThru", Each node is set up
     546              : 
     547            3 :             if (thisOutAirUnit.supFanPlace == HVAC::FanPlace::BlowThru) {
     548            4 :                 SetUpCompSets(state,
     549              :                               CurrentModuleObject,
     550              :                               thisOutAirUnit.Name,
     551              :                               "UNDEFINED",
     552            2 :                               state.dataIPShortCut->cAlphaArgs(5),
     553            2 :                               state.dataIPShortCut->cAlphaArgs(12),
     554            2 :                               state.dataIPShortCut->cAlphaArgs(15));
     555              :             }
     556              : 
     557              :             // A16 : component list
     558              : 
     559            3 :             GlobalNames::IntraObjUniquenessCheck(state,
     560            3 :                                                  state.dataIPShortCut->cAlphaArgs(16),
     561              :                                                  CurrentModuleObject,
     562            3 :                                                  cAlphaFields(16),
     563            3 :                                                  state.dataOutdoorAirUnit->ComponentListUniqueNames,
     564              :                                                  ErrorsFound);
     565            3 :             std::string const ComponentListName = state.dataIPShortCut->cAlphaArgs(16);
     566            3 :             thisOutAirUnit.ComponentListName = ComponentListName;
     567            3 :             if (!lAlphaBlanks(16)) {
     568            3 :                 int const ListNum = state.dataInputProcessing->inputProcessor->getObjectItemNum(state, ZoneHVACEqList, ComponentListName);
     569            3 :                 if (ListNum > 0) {
     570            3 :                     state.dataInputProcessing->inputProcessor->getObjectItem(
     571              :                         state, ZoneHVACEqList, ListNum, AlphArray, NumAlphas, NumArray, NumNums, IOStat);
     572            3 :                     int NumInList = (NumAlphas - 1) / 2; // potential problem if puts in type but not name
     573            3 :                     if (mod(NumAlphas - 1, 2) != 0) {
     574            0 :                         ++NumInList;
     575              :                     }
     576            3 :                     thisOutAirUnit.NumComponents = NumInList;
     577            3 :                     thisOutAirUnit.OAEquip.allocate(NumInList);
     578              : 
     579              :                     // Get information of component
     580            7 :                     for (int InListNum = 1; InListNum <= NumInList; ++InListNum) {
     581            4 :                         thisOutAirUnit.OAEquip(InListNum).ComponentName = AlphArray(InListNum * 2 + 1);
     582              : 
     583            8 :                         thisOutAirUnit.OAEquip(InListNum).Type =
     584            4 :                             static_cast<CompType>(getEnumValue(CompTypeNamesUC, Util::makeUPPER(AlphArray(InListNum * 2))));
     585              : 
     586            4 :                         int const CompNum = InListNum;
     587              : 
     588              :                         // Coil Types
     589            4 :                         switch (thisOutAirUnit.OAEquip(InListNum).Type) {
     590            1 :                         case CompType::WaterCoil_Cooling: {
     591            1 :                             thisOutAirUnit.OAEquip(CompNum).CoilType = DataPlant::PlantEquipmentType::CoilWaterCooling;
     592            2 :                             thisOutAirUnit.OAEquip(CompNum).ComponentIndex =
     593            1 :                                 GetWaterCoilIndex(state,
     594            1 :                                                   CompTypeNamesUC[static_cast<int>(thisOutAirUnit.OAEquip(CompNum).Type)],
     595            1 :                                                   thisOutAirUnit.OAEquip(CompNum).ComponentName,
     596              :                                                   ErrorsFound);
     597            2 :                             thisOutAirUnit.OAEquip(CompNum).CoilAirInletNode =
     598            1 :                                 WaterCoils::GetCoilInletNode(state,
     599            1 :                                                              CompTypeNames[static_cast<int>(thisOutAirUnit.OAEquip(CompNum).Type)],
     600            1 :                                                              thisOutAirUnit.OAEquip(CompNum).ComponentName,
     601              :                                                              ErrorsFound);
     602            2 :                             thisOutAirUnit.OAEquip(CompNum).CoilAirOutletNode =
     603            1 :                                 WaterCoils::GetCoilOutletNode(state,
     604            1 :                                                               CompTypeNames[static_cast<int>(thisOutAirUnit.OAEquip(CompNum).Type)],
     605            1 :                                                               thisOutAirUnit.OAEquip(CompNum).ComponentName,
     606              :                                                               ErrorsFound);
     607            2 :                             thisOutAirUnit.OAEquip(CompNum).CoilWaterInletNode =
     608            1 :                                 GetCoilWaterInletNode(state,
     609            1 :                                                       CompTypeNames[static_cast<int>(thisOutAirUnit.OAEquip(CompNum).Type)],
     610            1 :                                                       thisOutAirUnit.OAEquip(CompNum).ComponentName,
     611              :                                                       ErrorsFound);
     612            2 :                             thisOutAirUnit.OAEquip(CompNum).CoilWaterOutletNode =
     613            1 :                                 GetCoilWaterOutletNode(state,
     614            1 :                                                        CompTypeNames[static_cast<int>(thisOutAirUnit.OAEquip(CompNum).Type)],
     615            1 :                                                        thisOutAirUnit.OAEquip(CompNum).ComponentName,
     616              :                                                        ErrorsFound);
     617            2 :                             thisOutAirUnit.OAEquip(CompNum).MaxVolWaterFlow =
     618            1 :                                 WaterCoils::GetCoilMaxWaterFlowRate(state,
     619            1 :                                                                     CompTypeNames[static_cast<int>(thisOutAirUnit.OAEquip(CompNum).Type)],
     620            1 :                                                                     thisOutAirUnit.OAEquip(CompNum).ComponentName,
     621              :                                                                     ErrorsFound);
     622            1 :                             thisOutAirUnit.OAEquip(CompNum).MinVolWaterFlow = 0.0;
     623            1 :                             break;
     624              :                         }
     625            0 :                         case CompType::WaterCoil_SimpleHeat: {
     626            0 :                             thisOutAirUnit.OAEquip(CompNum).CoilType = DataPlant::PlantEquipmentType::CoilWaterSimpleHeating;
     627            0 :                             thisOutAirUnit.OAEquip(CompNum).ComponentIndex =
     628            0 :                                 GetWaterCoilIndex(state,
     629            0 :                                                   CompTypeNamesUC[static_cast<int>(thisOutAirUnit.OAEquip(CompNum).Type)],
     630            0 :                                                   thisOutAirUnit.OAEquip(CompNum).ComponentName,
     631              :                                                   ErrorsFound);
     632            0 :                             thisOutAirUnit.OAEquip(CompNum).CoilAirInletNode =
     633            0 :                                 WaterCoils::GetCoilInletNode(state,
     634            0 :                                                              CompTypeNames[static_cast<int>(thisOutAirUnit.OAEquip(CompNum).Type)],
     635            0 :                                                              thisOutAirUnit.OAEquip(CompNum).ComponentName,
     636              :                                                              ErrorsFound);
     637            0 :                             thisOutAirUnit.OAEquip(CompNum).CoilAirOutletNode = WaterCoils::GetCoilOutletNode(
     638            0 :                                 state, "Coil:Heating:Water", thisOutAirUnit.OAEquip(CompNum).ComponentName, ErrorsFound);
     639            0 :                             thisOutAirUnit.OAEquip(CompNum).CoilWaterInletNode =
     640            0 :                                 GetCoilWaterInletNode(state,
     641            0 :                                                       CompTypeNames[static_cast<int>(thisOutAirUnit.OAEquip(CompNum).Type)],
     642            0 :                                                       thisOutAirUnit.OAEquip(CompNum).ComponentName,
     643              :                                                       ErrorsFound);
     644            0 :                             thisOutAirUnit.OAEquip(CompNum).CoilWaterOutletNode =
     645            0 :                                 GetCoilWaterOutletNode(state,
     646            0 :                                                        CompTypeNames[static_cast<int>(thisOutAirUnit.OAEquip(CompNum).Type)],
     647            0 :                                                        thisOutAirUnit.OAEquip(CompNum).ComponentName,
     648              :                                                        ErrorsFound);
     649            0 :                             thisOutAirUnit.OAEquip(CompNum).MaxVolWaterFlow = WaterCoils::GetCoilMaxWaterFlowRate(
     650            0 :                                 state, "Coil:Heating:Water", thisOutAirUnit.OAEquip(CompNum).ComponentName, ErrorsFound);
     651            0 :                             thisOutAirUnit.OAEquip(CompNum).MinVolWaterFlow = 0.0;
     652            0 :                             break;
     653              :                         }
     654            1 :                         case CompType::SteamCoil_AirHeat: {
     655            1 :                             thisOutAirUnit.OAEquip(CompNum).CoilType = DataPlant::PlantEquipmentType::CoilSteamAirHeating;
     656            2 :                             thisOutAirUnit.OAEquip(CompNum).ComponentIndex =
     657            1 :                                 GetSteamCoilIndex(state,
     658            1 :                                                   CompTypeNamesUC[static_cast<int>(thisOutAirUnit.OAEquip(CompNum).Type)],
     659            1 :                                                   thisOutAirUnit.OAEquip(CompNum).ComponentName,
     660              :                                                   ErrorsFound);
     661            1 :                             thisOutAirUnit.OAEquip(CompNum).CoilAirInletNode = GetCoilAirInletNode(
     662            1 :                                 state, thisOutAirUnit.OAEquip(CompNum).ComponentIndex, thisOutAirUnit.OAEquip(CompNum).ComponentName, ErrorsFound);
     663            1 :                             thisOutAirUnit.OAEquip(CompNum).CoilAirOutletNode = GetCoilAirOutletNode(
     664            1 :                                 state, thisOutAirUnit.OAEquip(CompNum).ComponentIndex, thisOutAirUnit.OAEquip(CompNum).ComponentName, ErrorsFound);
     665            1 :                             thisOutAirUnit.OAEquip(CompNum).CoilWaterInletNode = GetCoilSteamInletNode(
     666            1 :                                 state, thisOutAirUnit.OAEquip(CompNum).ComponentIndex, thisOutAirUnit.OAEquip(CompNum).ComponentName, ErrorsFound);
     667            2 :                             thisOutAirUnit.OAEquip(CompNum).CoilWaterOutletNode =
     668            1 :                                 GetCoilSteamOutletNode(state,
     669            1 :                                                        CompTypeNames[static_cast<int>(thisOutAirUnit.OAEquip(CompNum).Type)],
     670            1 :                                                        thisOutAirUnit.OAEquip(CompNum).ComponentName,
     671              :                                                        ErrorsFound);
     672              : 
     673            2 :                             thisOutAirUnit.OAEquip(CompNum).MaxVolWaterFlow =
     674            1 :                                 GetCoilMaxSteamFlowRate(state, thisOutAirUnit.OAEquip(CompNum).ComponentIndex, ErrorsFound);
     675            1 :                             thisOutAirUnit.OAEquip(CompNum).MinVolWaterFlow = 0.0;
     676              :                             // below: no extra error needed if steam properties not in input
     677              :                             // file because getting the steam coil will have done that.
     678            1 :                             thisOutAirUnit.OAEquip(CompNum).FluidIndex = Fluid::GetRefrigNum(state, "STEAM");
     679            1 :                             break;
     680              :                         }
     681            0 :                         case CompType::WaterCoil_DetailedCool: {
     682            0 :                             thisOutAirUnit.OAEquip(CompNum).ComponentIndex =
     683            0 :                                 GetWaterCoilIndex(state,
     684            0 :                                                   CompTypeNamesUC[static_cast<int>(thisOutAirUnit.OAEquip(CompNum).Type)],
     685            0 :                                                   thisOutAirUnit.OAEquip(CompNum).ComponentName,
     686              :                                                   ErrorsFound);
     687            0 :                             thisOutAirUnit.OAEquip(CompNum).CoilType = DataPlant::PlantEquipmentType::CoilWaterDetailedFlatCooling;
     688            0 :                             thisOutAirUnit.OAEquip(CompNum).CoilAirInletNode =
     689            0 :                                 WaterCoils::GetCoilInletNode(state,
     690            0 :                                                              CompTypeNames[static_cast<int>(thisOutAirUnit.OAEquip(CompNum).Type)],
     691            0 :                                                              thisOutAirUnit.OAEquip(CompNum).ComponentName,
     692              :                                                              ErrorsFound);
     693            0 :                             thisOutAirUnit.OAEquip(CompNum).CoilAirOutletNode =
     694            0 :                                 WaterCoils::GetCoilOutletNode(state,
     695            0 :                                                               CompTypeNames[static_cast<int>(thisOutAirUnit.OAEquip(CompNum).Type)],
     696            0 :                                                               thisOutAirUnit.OAEquip(CompNum).ComponentName,
     697              :                                                               ErrorsFound);
     698            0 :                             thisOutAirUnit.OAEquip(CompNum).CoilWaterInletNode =
     699            0 :                                 GetCoilWaterInletNode(state,
     700            0 :                                                       CompTypeNames[static_cast<int>(thisOutAirUnit.OAEquip(CompNum).Type)],
     701            0 :                                                       thisOutAirUnit.OAEquip(CompNum).ComponentName,
     702              :                                                       ErrorsFound);
     703            0 :                             thisOutAirUnit.OAEquip(CompNum).CoilWaterOutletNode =
     704            0 :                                 GetCoilWaterOutletNode(state,
     705            0 :                                                        CompTypeNames[static_cast<int>(thisOutAirUnit.OAEquip(CompNum).Type)],
     706            0 :                                                        thisOutAirUnit.OAEquip(CompNum).ComponentName,
     707              :                                                        ErrorsFound);
     708            0 :                             thisOutAirUnit.OAEquip(CompNum).MaxVolWaterFlow =
     709            0 :                                 WaterCoils::GetCoilMaxWaterFlowRate(state,
     710            0 :                                                                     CompTypeNames[static_cast<int>(thisOutAirUnit.OAEquip(CompNum).Type)],
     711            0 :                                                                     thisOutAirUnit.OAEquip(CompNum).ComponentName,
     712              :                                                                     ErrorsFound);
     713            0 :                             thisOutAirUnit.OAEquip(CompNum).MinVolWaterFlow = 0.0;
     714            0 :                             break;
     715              :                         }
     716            0 :                         case CompType::WaterCoil_CoolingHXAsst: {
     717            0 :                             thisOutAirUnit.OAEquip(CompNum).CoilAirInletNode =
     718            0 :                                 HVACHXAssistedCoolingCoil::GetCoilInletNode(state,
     719            0 :                                                                             CompTypeNames[static_cast<int>(thisOutAirUnit.OAEquip(CompNum).Type)],
     720            0 :                                                                             thisOutAirUnit.OAEquip(CompNum).ComponentName,
     721              :                                                                             ErrorsFound);
     722            0 :                             thisOutAirUnit.OAEquip(CompNum).CoilAirOutletNode =
     723            0 :                                 HVACHXAssistedCoolingCoil::GetCoilOutletNode(state,
     724            0 :                                                                              CompTypeNames[static_cast<int>(thisOutAirUnit.OAEquip(CompNum).Type)],
     725            0 :                                                                              thisOutAirUnit.OAEquip(CompNum).ComponentName,
     726              :                                                                              ErrorsFound);
     727            0 :                             thisOutAirUnit.OAEquip(CompNum).CoilWaterInletNode =
     728            0 :                                 GetCoilWaterInletNode(state,
     729            0 :                                                       CompTypeNames[static_cast<int>(thisOutAirUnit.OAEquip(CompNum).Type)],
     730            0 :                                                       thisOutAirUnit.OAEquip(CompNum).ComponentName,
     731              :                                                       ErrorsFound);
     732            0 :                             thisOutAirUnit.OAEquip(CompNum).CoilWaterOutletNode =
     733            0 :                                 GetCoilWaterOutletNode(state,
     734            0 :                                                        CompTypeNames[static_cast<int>(thisOutAirUnit.OAEquip(CompNum).Type)],
     735            0 :                                                        thisOutAirUnit.OAEquip(CompNum).ComponentName,
     736              :                                                        ErrorsFound);
     737            0 :                             thisOutAirUnit.OAEquip(CompNum).MaxVolWaterFlow = HVACHXAssistedCoolingCoil::GetCoilMaxWaterFlowRate(
     738              :                                 state,
     739            0 :                                 CompTypeNames[static_cast<int>(thisOutAirUnit.OAEquip(CompNum).Type)],
     740            0 :                                 thisOutAirUnit.OAEquip(CompNum).ComponentName,
     741              :                                 ErrorsFound);
     742            0 :                             thisOutAirUnit.OAEquip(CompNum).MinVolWaterFlow = 0.0;
     743            0 :                             break;
     744              :                         }
     745            1 :                         case CompType::Coil_ElectricHeat: {
     746              :                             // Get OutAirUnit( OAUnitNum ).OAEquip( CompNum ).ComponentIndex, 2 types of mining functions to choose from
     747            1 :                             HeatingCoils::GetCoilIndex(
     748            1 :                                 state, thisOutAirUnit.OAEquip(CompNum).ComponentName, thisOutAirUnit.OAEquip(CompNum).ComponentIndex, ErrorsFound);
     749            2 :                             thisOutAirUnit.OAEquip(CompNum).CoilAirInletNode =
     750            1 :                                 HeatingCoils::GetCoilInletNode(state,
     751            1 :                                                                CompTypeNames[static_cast<int>(thisOutAirUnit.OAEquip(CompNum).Type)],
     752            1 :                                                                thisOutAirUnit.OAEquip(CompNum).ComponentName,
     753              :                                                                ErrorsFound);
     754            2 :                             thisOutAirUnit.OAEquip(CompNum).CoilAirOutletNode =
     755            1 :                                 HeatingCoils::GetCoilOutletNode(state,
     756            1 :                                                                 CompTypeNames[static_cast<int>(thisOutAirUnit.OAEquip(CompNum).Type)],
     757            1 :                                                                 thisOutAirUnit.OAEquip(CompNum).ComponentName,
     758              :                                                                 ErrorsFound);
     759            1 :                             break;
     760              :                         }
     761            0 :                         case CompType::Coil_GasHeat: {
     762              :                             // Get OutAirUnit( OAUnitNum ).OAEquip( CompNum ).ComponentIndex, 2 types of mining functions to choose from
     763            0 :                             HeatingCoils::GetCoilIndex(
     764            0 :                                 state, thisOutAirUnit.OAEquip(CompNum).ComponentName, thisOutAirUnit.OAEquip(CompNum).ComponentIndex, ErrorsFound);
     765            0 :                             thisOutAirUnit.OAEquip(CompNum).CoilAirInletNode =
     766            0 :                                 GetCoilInletNode(state,
     767            0 :                                                  CompTypeNames[static_cast<int>(thisOutAirUnit.OAEquip(CompNum).Type)],
     768            0 :                                                  thisOutAirUnit.OAEquip(CompNum).ComponentName,
     769              :                                                  ErrorsFound);
     770            0 :                             thisOutAirUnit.OAEquip(CompNum).CoilAirOutletNode =
     771            0 :                                 GetCoilOutletNode(state,
     772            0 :                                                   CompTypeNames[static_cast<int>(thisOutAirUnit.OAEquip(CompNum).Type)],
     773            0 :                                                   thisOutAirUnit.OAEquip(CompNum).ComponentName,
     774              :                                                   ErrorsFound);
     775            0 :                             break;
     776              :                         }
     777            1 :                         case CompType::DXSystem: {
     778              :                             // set the data for 100% DOAS DX cooling coil
     779              :                             // is a different function call needed here? similar to one in HVACDXSystem
     780              :                             // CheckDXCoolingCoilInOASysExists(state, thisOutAirUnit.OAEquip(CompNum).ComponentName);
     781            1 :                             break;
     782              :                         }
     783            0 :                         case CompType::DXHeatPumpSystem: {
     784            0 :                             break;
     785              :                         }
     786            0 :                         case CompType::UnitarySystemModel: {
     787            0 :                             UnitarySystems::UnitarySys thisSys;
     788            0 :                             thisOutAirUnit.OAEquip(CompNum).compPointer = thisSys.factory(
     789            0 :                                 state, HVAC::UnitarySysType::Unitary_AnyCoilType, thisOutAirUnit.OAEquip(CompNum).ComponentName, false, OAUnitNum);
     790            0 :                             UnitarySystems::UnitarySys::checkUnitarySysCoilInOASysExists(
     791            0 :                                 state, thisOutAirUnit.OAEquip(CompNum).ComponentName, OAUnitNum);
     792              : 
     793              :                             // Heat recovery
     794            0 :                             break;
     795            0 :                         }
     796            0 :                         case CompType::HeatXchngrFP:
     797              :                         case CompType::HeatXchngrSL: {
     798              :                             //        CASE('HEATEXCHANGER:DESICCANT:BALANCEDFLOW')
     799              :                             //          thisOutAirUnit%OAEquip(CompNum)%Type= CompType::HeatXchngr
     800              : 
     801              :                             // Desiccant Dehumidifier
     802            0 :                             break;
     803              :                         }
     804            0 :                         case CompType::Desiccant: {
     805              :                             // Future Enhancement
     806              :                             //        CASE('DEHUMIDIFIER:DESICCANT:SYSTEM')
     807              :                             //          thisOutAirUnit%OAEquip(CompNum)%Type= CompType::Desiccant
     808            0 :                             break;
     809              :                         }
     810            0 :                         default: {
     811            0 :                             ShowSevereError(state,
     812            0 :                                             format("{}= \"{}\" invalid Outside Air Component=\"{}\".",
     813              :                                                    CurrentModuleObject,
     814              :                                                    AlphArray(1),
     815            0 :                                                    CompTypeNames[static_cast<int>(thisOutAirUnit.OAEquip(CompNum).Type)]));
     816            0 :                             ErrorsFound = true;
     817              :                         }
     818              :                         }
     819              : 
     820              :                         // Add equipment to component sets array
     821              :                         // Node set up
     822            4 :                         if (thisOutAirUnit.supFanPlace == HVAC::FanPlace::BlowThru) {
     823            2 :                             if (InListNum == 1) { // the component is the first one
     824            4 :                                 SetUpCompSets(state,
     825              :                                               "ZoneHVAC:OutdoorAirUnit",
     826              :                                               thisOutAirUnit.Name,
     827            2 :                                               CompTypeNames[static_cast<int>(thisOutAirUnit.OAEquip(InListNum).Type)],
     828            2 :                                               thisOutAirUnit.OAEquip(InListNum).ComponentName,
     829            2 :                                               state.dataIPShortCut->cAlphaArgs(15),
     830              :                                               "UNDEFINED");
     831            0 :                             } else if (InListNum != NumInList) { // the component is placed in b/w components
     832            0 :                                 SetUpCompSets(state,
     833              :                                               "ZoneHVAC:OutdoorAirUnit",
     834              :                                               thisOutAirUnit.Name,
     835            0 :                                               CompTypeNames[static_cast<int>(thisOutAirUnit.OAEquip(InListNum).Type)],
     836            0 :                                               thisOutAirUnit.OAEquip(InListNum).ComponentName,
     837              :                                               "UNDEFINED",
     838              :                                               "UNDEFINED");
     839              :                             } else { // (InListNum == NumInList) => the component is the last one
     840            0 :                                 SetUpCompSets(state,
     841              :                                               "ZoneHVAC:OutdoorAirUnit",
     842              :                                               thisOutAirUnit.Name,
     843            0 :                                               CompTypeNames[static_cast<int>(thisOutAirUnit.OAEquip(InListNum).Type)],
     844            0 :                                               thisOutAirUnit.OAEquip(InListNum).ComponentName,
     845              :                                               "UNDEFINED",
     846            0 :                                               state.dataIPShortCut->cAlphaArgs(13));
     847              :                             }
     848              :                             // If fan is on the end of equipment.
     849            2 :                         } else if (thisOutAirUnit.supFanPlace == HVAC::FanPlace::DrawThru) {
     850            2 :                             if (InListNum == 1) {
     851            2 :                                 SetUpCompSets(state,
     852              :                                               "ZoneHVAC:OutdoorAirUnit",
     853              :                                               thisOutAirUnit.Name,
     854            1 :                                               CompTypeNames[static_cast<int>(thisOutAirUnit.OAEquip(InListNum).Type)],
     855            1 :                                               thisOutAirUnit.OAEquip(InListNum).ComponentName,
     856            1 :                                               state.dataIPShortCut->cAlphaArgs(12),
     857              :                                               "UNDEFINED");
     858            1 :                             } else if (InListNum != NumInList) {
     859            0 :                                 SetUpCompSets(state,
     860              :                                               "ZoneHVAC:OutdoorAirUnit",
     861              :                                               thisOutAirUnit.Name,
     862            0 :                                               CompTypeNames[static_cast<int>(thisOutAirUnit.OAEquip(InListNum).Type)],
     863            0 :                                               thisOutAirUnit.OAEquip(InListNum).ComponentName,
     864              :                                               "UNDEFINED",
     865              :                                               "UNDEFINED");
     866              :                             } else { // (InListNum == NumInList) => the component is the last one
     867            2 :                                 SetUpCompSets(state,
     868              :                                               "ZoneHVAC:OutdoorAirUnit",
     869              :                                               thisOutAirUnit.Name,
     870            1 :                                               CompTypeNames[static_cast<int>(thisOutAirUnit.OAEquip(InListNum).Type)],
     871            1 :                                               thisOutAirUnit.OAEquip(InListNum).ComponentName,
     872              :                                               "UNDEFINED",
     873              :                                               "UNDEFINED");
     874              :                             }
     875              :                         }
     876              :                         // Must call after SetUpCompSets since this will add another CoilSystem:Cooling:DX object in CompSets
     877            4 :                         if (CompTypeNamesUC[static_cast<int>(thisOutAirUnit.OAEquip(InListNum).Type)] == "COILSYSTEM:COOLING:DX") {
     878            1 :                             UnitarySystems::UnitarySys::checkUnitarySysCoilInOASysExists(
     879            1 :                                 state, thisOutAirUnit.OAEquip(CompNum).ComponentName, OAUnitNum);
     880              :                         }
     881              :                     } // End Inlist
     882              : 
     883              :                     // In case of draw through, the last component is linked with the zone air supply node
     884            3 :                     if (thisOutAirUnit.supFanPlace == HVAC::FanPlace::DrawThru) {
     885            3 :                         SetUpCompSets(state,
     886              :                                       CurrentModuleObject,
     887              :                                       thisOutAirUnit.Name,
     888              :                                       "UNDEFINED",
     889            1 :                                       state.dataIPShortCut->cAlphaArgs(5),
     890              :                                       "UNDEFINED",
     891            1 :                                       state.dataIPShortCut->cAlphaArgs(13));
     892              :                     }
     893              : 
     894              :                 } else { // when ListNum<0
     895            0 :                     ShowSevereError(state,
     896            0 :                                     format("{} = \"{}\" invalid {}=\"{}\" not found.",
     897              :                                            CurrentModuleObject,
     898            0 :                                            state.dataIPShortCut->cAlphaArgs(1),
     899              :                                            cAlphaFields(16),
     900            0 :                                            state.dataIPShortCut->cAlphaArgs(16)));
     901            0 :                     ErrorsFound = true;
     902              :                 }
     903              :             } else { // when Equipment list is left blanked
     904            0 :                 ShowSevereError(state,
     905            0 :                                 format("{} = \"{}\" invalid {} is blank and must be entered.",
     906              :                                        CurrentModuleObject,
     907            0 :                                        state.dataIPShortCut->cAlphaArgs(1),
     908              :                                        cAlphaFields(16)));
     909            0 :                 ErrorsFound = true;
     910              :             }
     911            3 :             if (!lAlphaBlanks(17)) {
     912            0 :                 thisOutAirUnit.AvailManagerListName = state.dataIPShortCut->cAlphaArgs(17);
     913              :             }
     914            3 :         }
     915              : 
     916            3 :         if (ErrorsFound) {
     917            0 :             ShowFatalError(state, format("{}Errors found in getting {}.", RoutineName, CurrentModuleObject));
     918              :         }
     919              : 
     920            3 :         AlphArray.deallocate();
     921            3 :         cAlphaFields.deallocate();
     922            3 :         NumArray.deallocate();
     923            3 :         cNumericFields.deallocate();
     924            3 :         lAlphaBlanks.deallocate();
     925            3 :         lNumericBlanks.deallocate();
     926              : 
     927            3 :         state.dataOutdoorAirUnit->GetOutdoorAirUnitInputFlag = false;
     928              : 
     929              :         // Setup Report variables for the zone outdoor air unit CurrentModuleObject='ZoneHVAC:OutdoorAirUnit'
     930            6 :         for (int OAUnitNum = 1; OAUnitNum <= state.dataOutdoorAirUnit->NumOfOAUnits; ++OAUnitNum) {
     931              : 
     932            3 :             auto &thisOutAirUnit = state.dataOutdoorAirUnit->OutAirUnit(OAUnitNum);
     933              : 
     934            6 :             SetupOutputVariable(state,
     935              :                                 "Zone Outdoor Air Unit Total Heating Rate",
     936              :                                 Constant::Units::W,
     937            3 :                                 thisOutAirUnit.TotHeatingRate,
     938              :                                 OutputProcessor::TimeStepType::System,
     939              :                                 OutputProcessor::StoreType::Average,
     940            3 :                                 thisOutAirUnit.Name);
     941            6 :             SetupOutputVariable(state,
     942              :                                 "Zone Outdoor Air Unit Total Heating Energy",
     943              :                                 Constant::Units::J,
     944            3 :                                 thisOutAirUnit.TotHeatingEnergy,
     945              :                                 OutputProcessor::TimeStepType::System,
     946              :                                 OutputProcessor::StoreType::Sum,
     947            3 :                                 thisOutAirUnit.Name);
     948            6 :             SetupOutputVariable(state,
     949              :                                 "Zone Outdoor Air Unit Sensible Heating Rate",
     950              :                                 Constant::Units::W,
     951            3 :                                 thisOutAirUnit.SensHeatingRate,
     952              :                                 OutputProcessor::TimeStepType::System,
     953              :                                 OutputProcessor::StoreType::Average,
     954            3 :                                 thisOutAirUnit.Name);
     955            6 :             SetupOutputVariable(state,
     956              :                                 "Zone Outdoor Air Unit Sensible Heating Energy",
     957              :                                 Constant::Units::J,
     958            3 :                                 thisOutAirUnit.SensHeatingEnergy,
     959              :                                 OutputProcessor::TimeStepType::System,
     960              :                                 OutputProcessor::StoreType::Sum,
     961            3 :                                 thisOutAirUnit.Name);
     962            6 :             SetupOutputVariable(state,
     963              :                                 "Zone Outdoor Air Unit Latent Heating Rate",
     964              :                                 Constant::Units::W,
     965            3 :                                 thisOutAirUnit.LatHeatingRate,
     966              :                                 OutputProcessor::TimeStepType::System,
     967              :                                 OutputProcessor::StoreType::Average,
     968            3 :                                 thisOutAirUnit.Name);
     969            6 :             SetupOutputVariable(state,
     970              :                                 "Zone Outdoor Air Unit Latent Heating Energy",
     971              :                                 Constant::Units::J,
     972            3 :                                 thisOutAirUnit.LatHeatingEnergy,
     973              :                                 OutputProcessor::TimeStepType::System,
     974              :                                 OutputProcessor::StoreType::Sum,
     975            3 :                                 thisOutAirUnit.Name);
     976            6 :             SetupOutputVariable(state,
     977              :                                 "Zone Outdoor Air Unit Total Cooling Rate",
     978              :                                 Constant::Units::W,
     979            3 :                                 thisOutAirUnit.TotCoolingRate,
     980              :                                 OutputProcessor::TimeStepType::System,
     981              :                                 OutputProcessor::StoreType::Average,
     982            3 :                                 thisOutAirUnit.Name);
     983            6 :             SetupOutputVariable(state,
     984              :                                 "Zone Outdoor Air Unit Total Cooling Energy",
     985              :                                 Constant::Units::J,
     986            3 :                                 thisOutAirUnit.TotCoolingEnergy,
     987              :                                 OutputProcessor::TimeStepType::System,
     988              :                                 OutputProcessor::StoreType::Sum,
     989            3 :                                 thisOutAirUnit.Name);
     990            6 :             SetupOutputVariable(state,
     991              :                                 "Zone Outdoor Air Unit Sensible Cooling Rate",
     992              :                                 Constant::Units::W,
     993            3 :                                 thisOutAirUnit.SensCoolingRate,
     994              :                                 OutputProcessor::TimeStepType::System,
     995              :                                 OutputProcessor::StoreType::Average,
     996            3 :                                 thisOutAirUnit.Name);
     997            6 :             SetupOutputVariable(state,
     998              :                                 "Zone Outdoor Air Unit Sensible Cooling Energy",
     999              :                                 Constant::Units::J,
    1000            3 :                                 thisOutAirUnit.SensCoolingEnergy,
    1001              :                                 OutputProcessor::TimeStepType::System,
    1002              :                                 OutputProcessor::StoreType::Sum,
    1003            3 :                                 thisOutAirUnit.Name);
    1004            6 :             SetupOutputVariable(state,
    1005              :                                 "Zone Outdoor Air Unit Latent Cooling Rate",
    1006              :                                 Constant::Units::W,
    1007            3 :                                 thisOutAirUnit.LatCoolingRate,
    1008              :                                 OutputProcessor::TimeStepType::System,
    1009              :                                 OutputProcessor::StoreType::Average,
    1010            3 :                                 thisOutAirUnit.Name);
    1011            6 :             SetupOutputVariable(state,
    1012              :                                 "Zone Outdoor Air Unit Latent Cooling Energy",
    1013              :                                 Constant::Units::J,
    1014            3 :                                 thisOutAirUnit.LatCoolingEnergy,
    1015              :                                 OutputProcessor::TimeStepType::System,
    1016              :                                 OutputProcessor::StoreType::Sum,
    1017            3 :                                 thisOutAirUnit.Name);
    1018            6 :             SetupOutputVariable(state,
    1019              :                                 "Zone Outdoor Air Unit Air Mass Flow Rate",
    1020              :                                 Constant::Units::kg_s,
    1021            3 :                                 thisOutAirUnit.AirMassFlow,
    1022              :                                 OutputProcessor::TimeStepType::System,
    1023              :                                 OutputProcessor::StoreType::Average,
    1024            3 :                                 thisOutAirUnit.Name);
    1025            6 :             SetupOutputVariable(state,
    1026              :                                 "Zone Outdoor Air Unit Fan Electricity Rate",
    1027              :                                 Constant::Units::W,
    1028            3 :                                 thisOutAirUnit.ElecFanRate,
    1029              :                                 OutputProcessor::TimeStepType::System,
    1030              :                                 OutputProcessor::StoreType::Average,
    1031            3 :                                 thisOutAirUnit.Name);
    1032            6 :             SetupOutputVariable(state,
    1033              :                                 "Zone Outdoor Air Unit Fan Electricity Energy",
    1034              :                                 Constant::Units::J,
    1035            3 :                                 thisOutAirUnit.ElecFanEnergy,
    1036              :                                 OutputProcessor::TimeStepType::System,
    1037              :                                 OutputProcessor::StoreType::Sum,
    1038            3 :                                 thisOutAirUnit.Name);
    1039            3 :             SetupOutputVariable(state,
    1040              :                                 "Zone Outdoor Air Unit Fan Availability Status",
    1041              :                                 Constant::Units::None,
    1042            3 :                                 (int &)thisOutAirUnit.availStatus,
    1043              :                                 OutputProcessor::TimeStepType::System,
    1044              :                                 OutputProcessor::StoreType::Average,
    1045            3 :                                 thisOutAirUnit.Name);
    1046              :             //! Note that the outdoor air unit fan electric is NOT metered because this value is already metered through the fan component
    1047              :         }
    1048            3 :     }
    1049              : 
    1050            3 :     void InitOutdoorAirUnit(EnergyPlusData &state,
    1051              :                             int const OAUnitNum,          // index for the current outdoor air unit
    1052              :                             int const ZoneNum,            // number of zone being served
    1053              :                             bool const FirstHVACIteration // TRUE if 1st HVAC simulation of system timestep
    1054              :     )
    1055              :     {
    1056              : 
    1057              :         // SUBROUTINE INFORMATION:
    1058              :         //       AUTHOR         Young Tae Chae, Rick Strand
    1059              :         //       DATE WRITTEN   July 2009
    1060              :         //       MODIFIED       July 2012, Chandan Sharma - FSEC: Added zone sys avail managers
    1061              :         //       RE-ENGINEERED  na
    1062              : 
    1063              :         // PURPOSE OF THIS SUBROUTINE:
    1064              :         // This subroutine initializes all of the data elements which are necessary
    1065              :         // to simulate a zone outdoor air control unit.
    1066              : 
    1067              :         // METHODOLOGY EMPLOYED:
    1068              :         // Uses the status flags to trigger initializations.
    1069              : 
    1070              :         // REFERENCES:
    1071              :         // na
    1072              : 
    1073              :         // Using/Aliasing
    1074              :         using DataZoneEquipment::CheckZoneEquipmentList;
    1075              :         using HVACHXAssistedCoolingCoil::SimHXAssistedCoolingCoil;
    1076              :         using PlantUtilities::InitComponentNodes;
    1077              :         using PlantUtilities::ScanPlantLoopsForObject;
    1078              :         using SteamCoils::GetCoilMaxSteamFlowRate;
    1079              :         using WaterCoils::SimulateWaterCoilComponents;
    1080              : 
    1081              :         // SUBROUTINE PARAMETER DEFINITIONS:
    1082              :         static constexpr std::string_view CurrentModuleObject("ZoneHVAC:OutdoorAirUnit");
    1083              :         static constexpr std::string_view RoutineName("SizeOutdoorAirUnit");
    1084              : 
    1085              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    1086              :         // Do the one time initializations
    1087              : 
    1088            3 :         auto &thisOutAirUnit = state.dataOutdoorAirUnit->OutAirUnit(OAUnitNum);
    1089              : 
    1090            3 :         Real64 const RhoAir = state.dataEnvrn->StdRhoAir;
    1091            3 :         int const InNode = thisOutAirUnit.AirInletNode;
    1092            3 :         int const OutNode = thisOutAirUnit.AirOutletNode;
    1093            3 :         int const OutsideAirNode = thisOutAirUnit.OutsideAirNode;
    1094            3 :         Real64 const OAFrac = thisOutAirUnit.outAirSched->getCurrentVal();
    1095              : 
    1096            3 :         if (state.dataOutdoorAirUnit->MyOneTimeFlag) {
    1097              : 
    1098            3 :             state.dataOutdoorAirUnit->MyEnvrnFlag.dimension(state.dataOutdoorAirUnit->NumOfOAUnits, true);
    1099            3 :             state.dataOutdoorAirUnit->MySizeFlag.dimension(state.dataOutdoorAirUnit->NumOfOAUnits, true);
    1100            3 :             state.dataOutdoorAirUnit->MyPlantScanFlag.dimension(state.dataOutdoorAirUnit->NumOfOAUnits, true);
    1101            3 :             state.dataOutdoorAirUnit->MyZoneEqFlag.dimension(state.dataOutdoorAirUnit->NumOfOAUnits, true);
    1102            3 :             state.dataOutdoorAirUnit->MyOneTimeFlag = false;
    1103              :         }
    1104              : 
    1105            3 :         if (allocated(state.dataAvail->ZoneComp)) {
    1106            0 :             auto &availMgr = state.dataAvail->ZoneComp(DataZoneEquipment::ZoneEquipType::OutdoorAirUnit).ZoneCompAvailMgrs(OAUnitNum);
    1107            0 :             if (state.dataOutdoorAirUnit->MyZoneEqFlag(OAUnitNum)) { // initialize the name of each availability manager list and zone number
    1108            0 :                 availMgr.AvailManagerListName = thisOutAirUnit.AvailManagerListName;
    1109            0 :                 availMgr.ZoneNum = ZoneNum;
    1110            0 :                 state.dataOutdoorAirUnit->MyZoneEqFlag(OAUnitNum) = false;
    1111              :             }
    1112            0 :             thisOutAirUnit.availStatus = availMgr.availStatus;
    1113              :         }
    1114              : 
    1115            3 :         if (state.dataOutdoorAirUnit->MyPlantScanFlag(OAUnitNum) && allocated(state.dataPlnt->PlantLoop)) {
    1116            4 :             for (int compLoop = 1; compLoop <= thisOutAirUnit.NumComponents; ++compLoop) {
    1117              : 
    1118            2 :                 CompType const Type = thisOutAirUnit.OAEquip(compLoop).Type;
    1119              : 
    1120            2 :                 switch (Type) {
    1121            2 :                 case CompType::WaterCoil_Cooling:
    1122              :                 case CompType::WaterCoil_DetailedCool:
    1123              :                 case CompType::WaterCoil_SimpleHeat:
    1124              :                 case CompType::SteamCoil_AirHeat:
    1125              : 
    1126              :                 {
    1127            2 :                     bool errFlag = false;
    1128            4 :                     ScanPlantLoopsForObject(state,
    1129            2 :                                             thisOutAirUnit.OAEquip(compLoop).ComponentName,
    1130            2 :                                             thisOutAirUnit.OAEquip(compLoop).CoilType,
    1131            2 :                                             thisOutAirUnit.OAEquip(compLoop).plantLoc,
    1132              :                                             errFlag,
    1133              :                                             _,
    1134              :                                             _,
    1135              :                                             _,
    1136              :                                             _,
    1137              :                                             _);
    1138            2 :                     if (errFlag) {
    1139            0 :                         ShowFatalError(state, "InitOutdoorAirUnit: Program terminated for previous conditions.");
    1140              :                     }
    1141            2 :                     break;
    1142              :                 }
    1143            0 :                 default:
    1144            0 :                     break;
    1145              :                 }
    1146              :             }
    1147              : 
    1148            2 :             state.dataOutdoorAirUnit->MyPlantScanFlag(OAUnitNum) = false;
    1149            1 :         } else if (state.dataOutdoorAirUnit->MyPlantScanFlag(OAUnitNum) && !state.dataGlobal->AnyPlantInModel) {
    1150            1 :             state.dataOutdoorAirUnit->MyPlantScanFlag(OAUnitNum) = false;
    1151              :         }
    1152              : 
    1153              :         // need to check all zone outdoor air control units to see if they are on Zone Equipment List or issue warning
    1154            3 :         if (!state.dataOutdoorAirUnit->ZoneEquipmentListChecked && state.dataZoneEquip->ZoneEquipInputsFilled) {
    1155            1 :             state.dataOutdoorAirUnit->ZoneEquipmentListChecked = true;
    1156            2 :             for (int Loop = 1; Loop <= state.dataOutdoorAirUnit->NumOfOAUnits; ++Loop) {
    1157            1 :                 if (CheckZoneEquipmentList(state, CurrentModuleObject, state.dataOutdoorAirUnit->OutAirUnit(Loop).Name)) {
    1158            1 :                     continue;
    1159              :                 }
    1160            0 :                 ShowSevereError(
    1161              :                     state,
    1162            0 :                     format("InitOutdoorAirUnit: Zone Outdoor Air Unit=[{},{}] is not on any ZoneHVAC:EquipmentList.  It will not be simulated.",
    1163              :                            CurrentModuleObject,
    1164            0 :                            state.dataOutdoorAirUnit->OutAirUnit(Loop).Name));
    1165              :             }
    1166              :         }
    1167              : 
    1168            6 :         if (!state.dataGlobal->SysSizingCalc && state.dataOutdoorAirUnit->MySizeFlag(OAUnitNum) &&
    1169            3 :             !state.dataOutdoorAirUnit->MyPlantScanFlag(OAUnitNum)) {
    1170              : 
    1171            3 :             SizeOutdoorAirUnit(state, OAUnitNum);
    1172              : 
    1173            3 :             state.dataOutdoorAirUnit->MySizeFlag(OAUnitNum) = false;
    1174              :         }
    1175              : 
    1176              :         // Do the one time initializations
    1177            3 :         if (state.dataGlobal->BeginEnvrnFlag && state.dataOutdoorAirUnit->MyEnvrnFlag(OAUnitNum)) {
    1178              :             // Node Conditions
    1179            3 :             thisOutAirUnit.OutAirMassFlow = RhoAir * OAFrac * thisOutAirUnit.OutAirVolFlow;
    1180            3 :             thisOutAirUnit.SMaxAirMassFlow = RhoAir * OAFrac * thisOutAirUnit.SFanMaxAirVolFlow;
    1181              : 
    1182            3 :             if (thisOutAirUnit.ExtFan) {
    1183              :                 // set the exhaust air mass flow rate from input
    1184            3 :                 Real64 const EAFrac = thisOutAirUnit.extAirSched->getCurrentVal();
    1185            3 :                 thisOutAirUnit.ExtAirMassFlow = RhoAir * EAFrac * thisOutAirUnit.ExtAirVolFlow;
    1186            3 :                 thisOutAirUnit.EMaxAirMassFlow = RhoAir * EAFrac * thisOutAirUnit.EFanMaxAirVolFlow;
    1187              : 
    1188            3 :                 state.dataLoopNodes->Node(InNode).MassFlowRateMax = thisOutAirUnit.EMaxAirMassFlow;
    1189            3 :                 state.dataLoopNodes->Node(InNode).MassFlowRateMin = 0.0;
    1190              :             }
    1191              :             // set the node max and min mass flow rates
    1192            3 :             state.dataLoopNodes->Node(OutsideAirNode).MassFlowRateMax = thisOutAirUnit.SMaxAirMassFlow;
    1193            3 :             state.dataLoopNodes->Node(OutsideAirNode).MassFlowRateMin = 0.0;
    1194            3 :             state.dataLoopNodes->Node(OutNode).MassFlowRate = thisOutAirUnit.EMaxAirMassFlow;
    1195              : 
    1196            3 :             if (!state.dataOutdoorAirUnit->MyPlantScanFlag(OAUnitNum)) {
    1197            3 :                 bool errFlag = false;
    1198            7 :                 for (int compLoop = 1; compLoop <= thisOutAirUnit.NumComponents; ++compLoop) {
    1199            7 :                     if ((thisOutAirUnit.OAEquip(compLoop).Type == CompType::WaterCoil_Cooling) ||
    1200            3 :                         (thisOutAirUnit.OAEquip(compLoop).Type == CompType::WaterCoil_DetailedCool)) {
    1201            2 :                         thisOutAirUnit.OAEquip(compLoop).MaxVolWaterFlow =
    1202            1 :                             WaterCoils::GetCoilMaxWaterFlowRate(state,
    1203            1 :                                                                 CompTypeNames[static_cast<int>(thisOutAirUnit.OAEquip(compLoop).Type)],
    1204            1 :                                                                 thisOutAirUnit.OAEquip(compLoop).ComponentName,
    1205              :                                                                 errFlag);
    1206            1 :                         Real64 const rho = state.dataPlnt->PlantLoop(thisOutAirUnit.OAEquip(compLoop).plantLoc.loopNum)
    1207            1 :                                                .glycol->getDensity(state, Constant::CWInitConvTemp, RoutineName);
    1208            1 :                         thisOutAirUnit.OAEquip(compLoop).MaxWaterMassFlow = rho * thisOutAirUnit.OAEquip(compLoop).MaxVolWaterFlow;
    1209            1 :                         thisOutAirUnit.OAEquip(compLoop).MinWaterMassFlow = rho * thisOutAirUnit.OAEquip(compLoop).MinVolWaterFlow;
    1210            4 :                         InitComponentNodes(state,
    1211            1 :                                            thisOutAirUnit.OAEquip(compLoop).MinWaterMassFlow,
    1212            1 :                                            thisOutAirUnit.OAEquip(compLoop).MaxWaterMassFlow,
    1213            1 :                                            thisOutAirUnit.OAEquip(compLoop).CoilWaterInletNode,
    1214            1 :                                            thisOutAirUnit.OAEquip(compLoop).CoilWaterOutletNode);
    1215              :                     }
    1216              : 
    1217            4 :                     if (thisOutAirUnit.OAEquip(compLoop).Type == CompType::WaterCoil_SimpleHeat) {
    1218            0 :                         thisOutAirUnit.OAEquip(compLoop).MaxVolWaterFlow =
    1219            0 :                             WaterCoils::GetCoilMaxWaterFlowRate(state,
    1220            0 :                                                                 CompTypeNames[static_cast<int>(thisOutAirUnit.OAEquip(compLoop).Type)],
    1221            0 :                                                                 thisOutAirUnit.OAEquip(compLoop).ComponentName,
    1222              :                                                                 errFlag);
    1223            0 :                         Real64 const rho = state.dataPlnt->PlantLoop(thisOutAirUnit.OAEquip(compLoop).plantLoc.loopNum)
    1224            0 :                                                .glycol->getDensity(state, Constant::HWInitConvTemp, RoutineName);
    1225            0 :                         thisOutAirUnit.OAEquip(compLoop).MaxWaterMassFlow = rho * thisOutAirUnit.OAEquip(compLoop).MaxVolWaterFlow;
    1226            0 :                         thisOutAirUnit.OAEquip(compLoop).MinWaterMassFlow = rho * thisOutAirUnit.OAEquip(compLoop).MinVolWaterFlow;
    1227            0 :                         InitComponentNodes(state,
    1228            0 :                                            thisOutAirUnit.OAEquip(compLoop).MinWaterMassFlow,
    1229            0 :                                            thisOutAirUnit.OAEquip(compLoop).MaxWaterMassFlow,
    1230            0 :                                            thisOutAirUnit.OAEquip(compLoop).CoilWaterInletNode,
    1231            0 :                                            thisOutAirUnit.OAEquip(compLoop).CoilWaterOutletNode);
    1232              :                     }
    1233            4 :                     if (thisOutAirUnit.OAEquip(compLoop).Type == CompType::SteamCoil_AirHeat) {
    1234            2 :                         thisOutAirUnit.OAEquip(compLoop).MaxVolWaterFlow =
    1235            1 :                             GetCoilMaxSteamFlowRate(state, thisOutAirUnit.OAEquip(compLoop).ComponentIndex, errFlag);
    1236            1 :                         Real64 const rho = state.dataPlnt->PlantLoop(thisOutAirUnit.OAEquip(compLoop).plantLoc.loopNum)
    1237            1 :                                                .steam->getSatDensity(state, Constant::SteamInitConvTemp, 1.0, RoutineName);
    1238            1 :                         thisOutAirUnit.OAEquip(compLoop).MaxWaterMassFlow = rho * thisOutAirUnit.OAEquip(compLoop).MaxVolWaterFlow;
    1239            1 :                         thisOutAirUnit.OAEquip(compLoop).MinWaterMassFlow = rho * thisOutAirUnit.OAEquip(compLoop).MinVolWaterFlow;
    1240            4 :                         InitComponentNodes(state,
    1241            1 :                                            thisOutAirUnit.OAEquip(compLoop).MinWaterMassFlow,
    1242            1 :                                            thisOutAirUnit.OAEquip(compLoop).MaxWaterMassFlow,
    1243            1 :                                            thisOutAirUnit.OAEquip(compLoop).CoilWaterInletNode,
    1244            1 :                                            thisOutAirUnit.OAEquip(compLoop).CoilWaterOutletNode);
    1245              :                     }
    1246            4 :                     if (thisOutAirUnit.OAEquip(compLoop).Type == CompType::WaterCoil_CoolingHXAsst) {
    1247            0 :                         thisOutAirUnit.OAEquip(compLoop).MaxVolWaterFlow =
    1248            0 :                             WaterCoils::GetCoilMaxWaterFlowRate(state,
    1249            0 :                                                                 CompTypeNames[static_cast<int>(thisOutAirUnit.OAEquip(compLoop).Type)],
    1250            0 :                                                                 thisOutAirUnit.OAEquip(compLoop).ComponentName,
    1251              :                                                                 errFlag);
    1252            0 :                         Real64 const rho = state.dataPlnt->PlantLoop(thisOutAirUnit.OAEquip(compLoop).plantLoc.loopNum)
    1253            0 :                                                .glycol->getDensity(state, Constant::CWInitConvTemp, RoutineName);
    1254            0 :                         thisOutAirUnit.OAEquip(compLoop).MaxWaterMassFlow = rho * thisOutAirUnit.OAEquip(compLoop).MaxVolWaterFlow;
    1255            0 :                         thisOutAirUnit.OAEquip(compLoop).MinWaterMassFlow = rho * thisOutAirUnit.OAEquip(compLoop).MinVolWaterFlow;
    1256            0 :                         InitComponentNodes(state,
    1257            0 :                                            thisOutAirUnit.OAEquip(compLoop).MinWaterMassFlow,
    1258            0 :                                            thisOutAirUnit.OAEquip(compLoop).MaxWaterMassFlow,
    1259            0 :                                            thisOutAirUnit.OAEquip(compLoop).CoilWaterInletNode,
    1260            0 :                                            thisOutAirUnit.OAEquip(compLoop).CoilWaterOutletNode);
    1261              :                     }
    1262              :                 }
    1263              :             }
    1264            3 :             state.dataOutdoorAirUnit->MyEnvrnFlag(OAUnitNum) = false;
    1265              : 
    1266              :         } // ...end start of environment inits
    1267              : 
    1268            3 :         if (!state.dataGlobal->BeginEnvrnFlag) {
    1269            0 :             state.dataOutdoorAirUnit->MyEnvrnFlag(OAUnitNum) = true;
    1270              :         }
    1271              : 
    1272              :         // These initializations are done every iteration...
    1273              :         // Set all the output variable
    1274            3 :         thisOutAirUnit.TotHeatingRate = 0.0;
    1275            3 :         thisOutAirUnit.SensHeatingRate = 0.0;
    1276            3 :         thisOutAirUnit.LatHeatingRate = 0.0;
    1277            3 :         thisOutAirUnit.TotCoolingRate = 0.0;
    1278            3 :         thisOutAirUnit.SensCoolingRate = 0.0;
    1279            3 :         thisOutAirUnit.LatCoolingRate = 0.0;
    1280            3 :         thisOutAirUnit.AirMassFlow = 0.0;
    1281            3 :         thisOutAirUnit.ElecFanRate = 0.0;
    1282              :         // Node Set
    1283              : 
    1284              :         // set the mass flow rates from the input volume flow rates
    1285            3 :         if (OAFrac > 0.0 || (state.dataHVACGlobal->TurnFansOn && !state.dataHVACGlobal->TurnFansOff)) { // fan is available
    1286            3 :             thisOutAirUnit.OutAirMassFlow = RhoAir * OAFrac * thisOutAirUnit.OutAirVolFlow;
    1287              :         } else {
    1288            0 :             thisOutAirUnit.OutAirMassFlow = 0.0;
    1289              :         }
    1290              : 
    1291              :         // set the exhaust air mass flow rate from input
    1292            3 :         if (thisOutAirUnit.ExtFan) {
    1293            3 :             if (thisOutAirUnit.extFanAvailSched != nullptr) {
    1294            3 :                 thisOutAirUnit.ExtAirMassFlow = RhoAir * thisOutAirUnit.ExtAirVolFlow * thisOutAirUnit.extAirSched->getCurrentVal();
    1295              :             } else {
    1296            0 :                 thisOutAirUnit.ExtAirMassFlow = 0.0;
    1297              :             }
    1298            3 :             state.dataLoopNodes->Node(InNode).MassFlowRate = thisOutAirUnit.ExtAirMassFlow;
    1299            3 :             state.dataLoopNodes->Node(InNode).MassFlowRateMaxAvail = thisOutAirUnit.ExtAirMassFlow;
    1300            3 :             state.dataLoopNodes->Node(InNode).MassFlowRateMinAvail = 0.0;
    1301            0 :         } else if (!thisOutAirUnit.ExtFan) {
    1302            0 :             thisOutAirUnit.ExtAirMassFlow = 0.0;
    1303              :         }
    1304              : 
    1305              :         // First, set the flow conditions up so that there is flow through the unit
    1306              : 
    1307            3 :         state.dataLoopNodes->Node(OutNode).MassFlowRate = thisOutAirUnit.OutAirMassFlow;
    1308            3 :         state.dataLoopNodes->Node(OutNode).MassFlowRateMaxAvail = thisOutAirUnit.OutAirMassFlow;
    1309            3 :         state.dataLoopNodes->Node(OutNode).MassFlowRateMinAvail = 0.0;
    1310            3 :         state.dataLoopNodes->Node(OutsideAirNode).MassFlowRate = thisOutAirUnit.OutAirMassFlow;
    1311            3 :         state.dataLoopNodes->Node(OutsideAirNode).MassFlowRateMaxAvail = thisOutAirUnit.OutAirMassFlow;
    1312            3 :         state.dataLoopNodes->Node(OutsideAirNode).MassFlowRateMinAvail = 0.0;
    1313              : 
    1314              :         // Just in case the system is off and conditions do not get sent through
    1315              :         // the system for some reason, set the outlet conditions equal to the inlet
    1316              :         // conditions of the zone outdoor air control unit
    1317            3 :         if (thisOutAirUnit.ExtFan) {
    1318            3 :             state.dataLoopNodes->Node(OutNode).Temp = state.dataLoopNodes->Node(InNode).Temp;
    1319            3 :             state.dataLoopNodes->Node(OutNode).Press = state.dataLoopNodes->Node(InNode).Press;
    1320            3 :             state.dataLoopNodes->Node(OutNode).HumRat = state.dataLoopNodes->Node(InNode).HumRat;
    1321            3 :             state.dataLoopNodes->Node(OutNode).Enthalpy = state.dataLoopNodes->Node(InNode).Enthalpy;
    1322              :         } else {
    1323            0 :             state.dataLoopNodes->Node(OutNode).Temp = state.dataLoopNodes->Node(OutsideAirNode).Temp;
    1324            0 :             state.dataLoopNodes->Node(OutNode).Press = state.dataLoopNodes->Node(OutsideAirNode).Press;
    1325            0 :             state.dataLoopNodes->Node(OutNode).HumRat = state.dataLoopNodes->Node(OutsideAirNode).HumRat;
    1326            0 :             state.dataLoopNodes->Node(OutNode).Enthalpy = state.dataLoopNodes->Node(OutsideAirNode).Enthalpy;
    1327              :         }
    1328              :         // These initializations only need to be done once at the start of the iterations...
    1329            3 :         if (FirstHVACIteration || state.dataHVACGlobal->ShortenTimeStepSys) {
    1330              :             // Initialize the outside air conditions...
    1331            3 :             state.dataLoopNodes->Node(OutsideAirNode).Temp = state.dataLoopNodes->Node(OutsideAirNode).OutAirDryBulb;
    1332            3 :             state.dataLoopNodes->Node(OutsideAirNode).HumRat = state.dataEnvrn->OutHumRat;
    1333            3 :             state.dataLoopNodes->Node(OutsideAirNode).Press = state.dataEnvrn->OutBaroPress;
    1334              :         }
    1335            3 :     }
    1336              : 
    1337            3 :     void SizeOutdoorAirUnit(EnergyPlusData &state, int const OAUnitNum)
    1338              :     {
    1339              : 
    1340              :         // SUBROUTINE INFORMATION:
    1341              :         //       AUTHOR         Young Tae Chae, Rick Strand
    1342              :         //       DATE WRITTEN   July 2009
    1343              :         //       MODIFIED       Brent Griffith, March 2010, autosize OA flow rate
    1344              :         //                      August 2013 Daeho Kang, add component sizing table entries
    1345              :         //       RE-ENGINEERED  na
    1346              : 
    1347              :         // PURPOSE OF THIS SUBROUTINE:
    1348              :         // This subroutine is for sizing zone outdoor air control unit components for which flow rates have not been
    1349              :         // specified in the input.
    1350              : 
    1351              :         // METHODOLOGY EMPLOYED:
    1352              :         // Obtains flow rates from the zone sizing arrays and plant sizing data.
    1353              : 
    1354              :         // Using/Aliasing
    1355              :         using namespace DataSizing;
    1356              : 
    1357              :         using HVACHXAssistedCoolingCoil::SimHXAssistedCoolingCoil;
    1358              :         using PlantUtilities::MyPlantSizingIndex;
    1359              :         using SteamCoils::SimulateSteamCoilComponents;
    1360              :         using WaterCoils::SimulateWaterCoilComponents;
    1361              : 
    1362              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    1363            3 :         bool IsAutoSize = false;        // Indicator to autosize
    1364            3 :         Real64 OutAirVolFlowDes = 0.0;  // Autosized outdoor air flow for reporting
    1365            3 :         Real64 OutAirVolFlowUser = 0.0; // Hardsized outdoor air flow for reporting
    1366            3 :         Real64 ExtAirVolFlowDes = 0.0;  // Autosized exhaust air flow for reporting
    1367            3 :         Real64 ExtAirVolFlowUser = 0.0; // Hardsized exhaust air flow for reporting
    1368              : 
    1369            3 :         bool ErrorsFound = false;
    1370              : 
    1371            3 :         auto &thisOutAirUnit = state.dataOutdoorAirUnit->OutAirUnit(OAUnitNum);
    1372              : 
    1373            3 :         state.dataSize->DataFanType = thisOutAirUnit.supFanType;
    1374            3 :         state.dataSize->DataFanIndex = thisOutAirUnit.SFan_Index;
    1375            3 :         state.dataSize->DataFanPlacement = thisOutAirUnit.supFanPlace;
    1376              : 
    1377            3 :         if (thisOutAirUnit.OutAirVolFlow == AutoSize) {
    1378            3 :             IsAutoSize = true;
    1379              :         }
    1380              : 
    1381            3 :         if (state.dataSize->CurZoneEqNum > 0) {
    1382            3 :             if (!IsAutoSize && !state.dataSize->ZoneSizingRunDone) { // Simulation continue
    1383            0 :                 if (thisOutAirUnit.OutAirVolFlow > 0.0) {
    1384            0 :                     BaseSizer::reportSizerOutput(
    1385              :                         state, ZoneHVACOAUnit, thisOutAirUnit.Name, "User-Specified Outdoor Air Flow Rate [m3/s]", thisOutAirUnit.OutAirVolFlow);
    1386              :                 }
    1387              :             } else {
    1388            6 :                 CheckZoneSizing(state, std::string(ZoneHVACOAUnit), thisOutAirUnit.Name);
    1389            3 :                 OutAirVolFlowDes = state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).MinOA;
    1390            3 :                 if (OutAirVolFlowDes < SmallAirVolFlow) {
    1391            0 :                     OutAirVolFlowDes = 0.0;
    1392              :                 }
    1393            3 :                 if (IsAutoSize) {
    1394            3 :                     thisOutAirUnit.OutAirVolFlow = OutAirVolFlowDes;
    1395            3 :                     BaseSizer::reportSizerOutput(
    1396              :                         state, ZoneHVACOAUnit, thisOutAirUnit.Name, "Design Size Outdoor Air Flow Rate [m3/s]", OutAirVolFlowDes);
    1397              :                 } else {
    1398            0 :                     if (thisOutAirUnit.OutAirVolFlow > 0.0 && OutAirVolFlowDes > 0.0) {
    1399            0 :                         OutAirVolFlowUser = thisOutAirUnit.OutAirVolFlow;
    1400            0 :                         BaseSizer::reportSizerOutput(
    1401              :                             state, ZoneHVACOAUnit, thisOutAirUnit.Name, "User-Specified Outdoor Air Flow Rate [m3/s]", OutAirVolFlowUser);
    1402            0 :                         if (state.dataGlobal->DisplayExtraWarnings) {
    1403            0 :                             if ((std::abs(OutAirVolFlowDes - OutAirVolFlowUser) / OutAirVolFlowUser) > state.dataSize->AutoVsHardSizingThreshold) {
    1404            0 :                                 BaseSizer::reportSizerOutput(
    1405              :                                     state, ZoneHVACOAUnit, thisOutAirUnit.Name, "Design Size Outdoor Air Flow Rate [m3/s]", OutAirVolFlowDes);
    1406            0 :                                 ShowMessage(state,
    1407            0 :                                             format("SizeOutdoorAirUnit: Potential issue with equipment sizing for ZoneHVAC:OutdoorAirUnit {}",
    1408            0 :                                                    thisOutAirUnit.Name));
    1409            0 :                                 ShowContinueError(state, format("User-Specified Outdoor Air Flow Rate of {:.5R} [m3/s]", OutAirVolFlowUser));
    1410            0 :                                 ShowContinueError(state, format("differs from Design Size Outdoor Air Flow Rate of {:.5R} [m3/s]", OutAirVolFlowDes));
    1411            0 :                                 ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
    1412            0 :                                 ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
    1413              :                             }
    1414              :                         }
    1415              :                     }
    1416              :                 }
    1417              :             }
    1418              :         }
    1419              : 
    1420            3 :         IsAutoSize = false;
    1421            3 :         if (thisOutAirUnit.ExtAirVolFlow == AutoSize) {
    1422            3 :             IsAutoSize = true;
    1423              :         }
    1424            3 :         if (state.dataSize->CurZoneEqNum > 0) {
    1425            3 :             if (!IsAutoSize && !state.dataSize->ZoneSizingRunDone) { // Simulation continue
    1426            0 :                 if (thisOutAirUnit.ExtAirVolFlow > 0.0) {
    1427            0 :                     BaseSizer::reportSizerOutput(
    1428              :                         state, ZoneHVACOAUnit, thisOutAirUnit.Name, "User-Specified Exhaust Air Flow Rate [m3/s]", thisOutAirUnit.ExtAirVolFlow);
    1429              :                 }
    1430              :             } else {
    1431              :                 // set exhaust flow equal to the oa inlet flow
    1432            3 :                 ExtAirVolFlowDes = thisOutAirUnit.OutAirVolFlow;
    1433            3 :                 if (IsAutoSize) {
    1434            3 :                     thisOutAirUnit.ExtAirVolFlow = ExtAirVolFlowDes;
    1435            3 :                     BaseSizer::reportSizerOutput(
    1436              :                         state, ZoneHVACOAUnit, thisOutAirUnit.Name, "Design Size Exhaust Air Flow Rate [m3/s]", ExtAirVolFlowDes);
    1437              :                 } else {
    1438            0 :                     if (thisOutAirUnit.ExtAirVolFlow > 0.0 && ExtAirVolFlowDes > 0.0) {
    1439            0 :                         ExtAirVolFlowUser = thisOutAirUnit.ExtAirVolFlow;
    1440            0 :                         BaseSizer::reportSizerOutput(
    1441              :                             state, ZoneHVACOAUnit, thisOutAirUnit.Name, "User-Specified Exhaust Air Flow Rate [m3/s]", ExtAirVolFlowUser);
    1442            0 :                         if (state.dataGlobal->DisplayExtraWarnings) {
    1443            0 :                             if ((std::abs(ExtAirVolFlowDes - ExtAirVolFlowUser) / ExtAirVolFlowUser) > state.dataSize->AutoVsHardSizingThreshold) {
    1444            0 :                                 BaseSizer::reportSizerOutput(
    1445              :                                     state, ZoneHVACOAUnit, thisOutAirUnit.Name, "Design Size Exhaust Air Flow Rate [m3/s]", ExtAirVolFlowDes);
    1446            0 :                                 ShowMessage(state,
    1447            0 :                                             format("SizeOutdoorAirUnit: Potential issue with equipment sizing for ZoneHVAC:OutdoorAirUnit {}",
    1448            0 :                                                    thisOutAirUnit.Name));
    1449            0 :                                 ShowContinueError(state, format("User-Specified Exhaust Air Flow Rate of {:.5R} [m3/s]", ExtAirVolFlowUser));
    1450            0 :                                 ShowContinueError(state, format("differs from Design Size Exhaust Air Flow Rate of {:.5R} [m3/s]", ExtAirVolFlowDes));
    1451            0 :                                 ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
    1452            0 :                                 ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
    1453              :                             }
    1454              :                         }
    1455              :                     }
    1456              :                 }
    1457              :             }
    1458              :         }
    1459              : 
    1460            3 :         state.dataSize->ZoneEqSizing(state.dataSize->CurZoneEqNum).CoolingAirFlow = true;
    1461            3 :         state.dataSize->ZoneEqSizing(state.dataSize->CurZoneEqNum).HeatingAirFlow = true;
    1462            3 :         state.dataSize->ZoneEqSizing(state.dataSize->CurZoneEqNum).CoolingAirVolFlow = thisOutAirUnit.OutAirVolFlow;
    1463            3 :         state.dataSize->ZoneEqSizing(state.dataSize->CurZoneEqNum).HeatingAirVolFlow = thisOutAirUnit.OutAirVolFlow;
    1464            3 :         state.dataSize->ZoneEqSizing(state.dataSize->CurZoneEqNum).OAVolFlow = thisOutAirUnit.OutAirVolFlow;
    1465              : 
    1466            3 :         if (thisOutAirUnit.SFanMaxAirVolFlow == AutoSize) {
    1467            3 :             state.dataFans->fans(thisOutAirUnit.SFan_Index)->simulate(state, true, _, _);
    1468            3 :             thisOutAirUnit.SFanMaxAirVolFlow = state.dataFans->fans(thisOutAirUnit.SFan_Index)->maxAirFlowRate;
    1469              :         }
    1470            3 :         if (thisOutAirUnit.ExtFan) {
    1471            3 :             if (thisOutAirUnit.EFanMaxAirVolFlow == AutoSize) {
    1472            3 :                 state.dataFans->fans(thisOutAirUnit.ExtFan_Index)->simulate(state, true, _, _);
    1473            3 :                 thisOutAirUnit.EFanMaxAirVolFlow = state.dataFans->fans(thisOutAirUnit.ExtFan_Index)->maxAirFlowRate;
    1474              :             }
    1475              :         }
    1476              : 
    1477            7 :         for (int CompNum = 1; CompNum <= thisOutAirUnit.NumComponents; ++CompNum) {
    1478            4 :             auto &thisOAEquip = thisOutAirUnit.OAEquip(CompNum);
    1479            4 :             if ((thisOAEquip.Type == CompType::WaterCoil_Cooling) || (thisOAEquip.Type == CompType::WaterCoil_DetailedCool)) {
    1480            1 :                 if (thisOAEquip.MaxVolWaterFlow == AutoSize) {
    1481            1 :                     SimulateWaterCoilComponents(state, thisOAEquip.ComponentName, true, thisOAEquip.ComponentIndex, _, HVAC::FanOp::Cycling, 0.0);
    1482              :                 }
    1483              :             }
    1484            4 :             if (thisOAEquip.Type == CompType::WaterCoil_SimpleHeat) {
    1485            0 :                 if (thisOAEquip.MaxVolWaterFlow == AutoSize) {
    1486            0 :                     SimulateWaterCoilComponents(state, thisOAEquip.ComponentName, true, thisOAEquip.ComponentIndex, _, HVAC::FanOp::Cycling, 0.0);
    1487              :                 }
    1488              :             }
    1489            4 :             if (thisOAEquip.Type == CompType::SteamCoil_AirHeat) {
    1490            1 :                 if (thisOAEquip.MaxVolWaterFlow == AutoSize) {
    1491            1 :                     SimulateSteamCoilComponents(state, thisOAEquip.ComponentName, true, thisOAEquip.ComponentIndex);
    1492              :                 }
    1493              :             }
    1494            4 :             if (thisOAEquip.Type == CompType::WaterCoil_CoolingHXAsst) {
    1495            0 :                 if (thisOAEquip.MaxVolWaterFlow == AutoSize) {
    1496            0 :                     SimHXAssistedCoolingCoil(
    1497            0 :                         state, thisOAEquip.ComponentName, true, HVAC::CompressorOp::On, 0.0, thisOAEquip.ComponentIndex, HVAC::FanOp::Continuous);
    1498              :                 }
    1499              :             }
    1500              :         }
    1501              : 
    1502            3 :         if (ErrorsFound) {
    1503            0 :             ShowFatalError(state, "Preceding sizing errors cause program termination");
    1504              :         }
    1505            3 :     }
    1506              : 
    1507            2 :     void CalcOutdoorAirUnit(EnergyPlusData &state,
    1508              :                             int &OAUnitNum,                // number of the current unit being simulated
    1509              :                             int const ZoneNum,             // number of zone being served
    1510              :                             bool const FirstHVACIteration, // TRUE if 1st HVAC simulation of system timestep
    1511              :                             Real64 &PowerMet,              // power supplied
    1512              :                             Real64 &LatOutputProvided      // Latent power supplied (kg/s), negative = dehumidification
    1513              :     )
    1514              :     {
    1515              : 
    1516              :         // SUBROUTINE INFORMATION:
    1517              :         //       AUTHOR         Young Tae Chae, Rick Strand
    1518              :         //       DATE WRITTEN   June 2008
    1519              :         //       MODIFIED       July 2012, Chandan Sharma - FSEC: Added zone sys avail managers
    1520              :         //       RE-ENGINEERED  na
    1521              : 
    1522              :         // PURPOSE OF THIS SUBROUTINE:
    1523              :         // This subroutine mainly controls the action of the outdoor air unit
    1524              :         // (or more exactly, it controls the coil outlet temperature of the unit)
    1525              :         // based on the user input for controls and the defined controls
    1526              :         // algorithms.
    1527              : 
    1528              :         // METHODOLOGY EMPLOYED:
    1529              :         // Outdoor air unit is controlled based on user input and what is happening in the
    1530              :         // simulation.
    1531              :         // Note: controls are strictly temperature based and do not factor
    1532              :         // humidity into the equation (not an enthalpy economy cycle but rather
    1533              :         // a simple return air cycle).
    1534              : 
    1535              :         // REFERENCES:
    1536              :         // ASHRAE Systems and Equipment Handbook (SI), 1996. page 31.3
    1537              : 
    1538              :         // USE STATEMENTS:
    1539              : 
    1540              :         // Using/Aliasing
    1541            2 :         auto &thisOutAirUnit = state.dataOutdoorAirUnit->OutAirUnit(OAUnitNum);
    1542              : 
    1543            2 :         auto &TurnFansOff = state.dataHVACGlobal->TurnFansOff;
    1544            2 :         auto &TurnFansOn = state.dataHVACGlobal->TurnFansOn;
    1545              :         using HeatingCoils::CheckHeatingCoilSchedule;
    1546              :         using HVACHXAssistedCoolingCoil::CheckHXAssistedCoolingCoilSchedule;
    1547              : 
    1548              :         // Locals
    1549              : 
    1550              :         // SUBROUTINE ARGUMENT DEFINITIONS:
    1551              : 
    1552              :         // SUBROUTINE PARAMETER DEFINITIONS:
    1553              :         // INTERFACE BLOCK SPECIFICATIONS
    1554              : 
    1555              :         // DERIVED TYPE DEFINITIONS
    1556              :         // na
    1557              : 
    1558              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    1559              :         Real64 DesOATemp;      // Design OA Temp degree C
    1560              :         Real64 AirMassFlow;    // air mass flow rate [kg/s]
    1561              :         Real64 QTotUnitOut;    // total unit output [watts]
    1562            2 :         Real64 QUnitOut = 0.0; // heating or sens. cooling provided by fan coil unit [watts]
    1563              :         Real64 LatLoadMet;     // heating or sens. cooling provided by fan coil unit [watts]
    1564              :         Real64 MinHumRat;      // desired temperature after mixing inlet and outdoor air [degrees C]
    1565              :         Real64 SetPointTemp;   // temperature that will be used to control the radiant system [Celsius]
    1566              :         Real64 HiCtrlTemp;     // Current high point in setpoint temperature range
    1567              :         Real64 LoCtrlTemp;     // Current low point in setpoint temperature range
    1568              :         Real64 AirInEnt;       // RE-calculate the Enthalpy of supply air
    1569            2 :         Real64 AirOutletTemp = 0.0;
    1570              :         Real64 ZoneSupAirEnt; // Specific humidity ratio of inlet air (kg moisture / kg moist air)
    1571              :         // Latent output
    1572              :         Real64 LatentOutput; // Latent (moisture) add/removal rate, negative is dehumidification [kg/s]
    1573              :         Real64 SpecHumOut;   // Specific humidity ratio of outlet air (kg moisture / kg moist air)
    1574              :         Real64 SpecHumIn;    // Specific humidity ratio of inlet air (kg moisture / kg moist air)
    1575              :         Real64 ZoneAirEnt;   // zone air enthalpy J/kg
    1576              : 
    1577              :         // initialize local variables
    1578            2 :         int const InletNode = thisOutAirUnit.AirInletNode;        // Unit air inlet node, only used if ExtFan
    1579            2 :         int const SFanOutletNode = thisOutAirUnit.SFanOutletNode; // Unit supply fan outlet node
    1580            2 :         int const OutletNode = thisOutAirUnit.AirOutletNode;      // air outlet node
    1581            2 :         int const OutsideAirNode = thisOutAirUnit.OutsideAirNode; // outside air node
    1582            2 :         OAUnitCtrlType const UnitControlType = thisOutAirUnit.controlType;
    1583              : 
    1584            2 :         thisOutAirUnit.CompOutSetTemp = 0.0;
    1585            2 :         thisOutAirUnit.FanEffect = false;
    1586              : 
    1587            6 :         if ((thisOutAirUnit.availSched->getCurrentVal() <= 0) || (thisOutAirUnit.outAirSched->getCurrentVal() <= 0) ||
    1588            6 :             ((thisOutAirUnit.supFanAvailSched->getCurrentVal() <= 0) && !TurnFansOn) || TurnFansOff) {
    1589              :             // System is off or has no load upon the unit; set the flow rates to zero and then
    1590              :             // simulate the components with the no flow conditions
    1591            0 :             if (thisOutAirUnit.ExtFan) {
    1592            0 :                 state.dataLoopNodes->Node(InletNode).MassFlowRate = 0.0;
    1593            0 :                 state.dataLoopNodes->Node(InletNode).MassFlowRateMaxAvail = 0.0;
    1594            0 :                 state.dataLoopNodes->Node(InletNode).MassFlowRateMinAvail = 0.0;
    1595              :             }
    1596            0 :             state.dataLoopNodes->Node(SFanOutletNode).MassFlowRate = 0.0;
    1597            0 :             state.dataLoopNodes->Node(SFanOutletNode).MassFlowRateMaxAvail = 0.0;
    1598            0 :             state.dataLoopNodes->Node(SFanOutletNode).MassFlowRateMinAvail = 0.0;
    1599            0 :             state.dataLoopNodes->Node(OutletNode).MassFlowRate = 0.0;
    1600            0 :             state.dataLoopNodes->Node(OutletNode).MassFlowRateMaxAvail = 0.0;
    1601            0 :             state.dataLoopNodes->Node(OutletNode).MassFlowRateMinAvail = 0.0;
    1602            0 :             state.dataLoopNodes->Node(OutsideAirNode).MassFlowRate = 0.0;
    1603            0 :             state.dataLoopNodes->Node(OutsideAirNode).MassFlowRateMaxAvail = 0.0;
    1604            0 :             state.dataLoopNodes->Node(OutsideAirNode).MassFlowRateMinAvail = 0.0;
    1605              : 
    1606              :             // Node condition
    1607            0 :             if (thisOutAirUnit.ExtFan) {
    1608            0 :                 state.dataLoopNodes->Node(InletNode).Temp = state.dataZoneTempPredictorCorrector->zoneHeatBalance(ZoneNum).MAT;
    1609            0 :                 state.dataLoopNodes->Node(SFanOutletNode).Temp = state.dataLoopNodes->Node(InletNode).Temp;
    1610              :             } else {
    1611            0 :                 state.dataLoopNodes->Node(SFanOutletNode).Temp = state.dataZoneTempPredictorCorrector->zoneHeatBalance(ZoneNum).MAT;
    1612              :             }
    1613            0 :             state.dataLoopNodes->Node(OutletNode).Temp = state.dataLoopNodes->Node(SFanOutletNode).Temp;
    1614              : 
    1615            0 :             if (thisOutAirUnit.supFanPlace == HVAC::FanPlace::BlowThru) {
    1616            0 :                 state.dataFans->fans(thisOutAirUnit.SFan_Index)->simulate(state, FirstHVACIteration, _);
    1617              : 
    1618            0 :                 SimZoneOutAirUnitComps(state, OAUnitNum, FirstHVACIteration);
    1619            0 :                 if (thisOutAirUnit.ExtFan) {
    1620            0 :                     state.dataFans->fans(thisOutAirUnit.ExtFan_Index)->simulate(state, FirstHVACIteration, _, _);
    1621              :                 }
    1622              : 
    1623            0 :             } else if (thisOutAirUnit.supFanPlace == HVAC::FanPlace::DrawThru) {
    1624            0 :                 SimZoneOutAirUnitComps(state, OAUnitNum, FirstHVACIteration);
    1625            0 :                 state.dataFans->fans(thisOutAirUnit.SFan_Index)->simulate(state, FirstHVACIteration, _, _);
    1626              : 
    1627            0 :                 if (thisOutAirUnit.ExtFan) {
    1628            0 :                     state.dataFans->fans(thisOutAirUnit.ExtFan_Index)->simulate(state, FirstHVACIteration, _, _);
    1629              :                 }
    1630              :             }
    1631              : 
    1632              :         } else { // System On
    1633              : 
    1634              :             // Flowrate Check
    1635            2 :             if (state.dataLoopNodes->Node(OutsideAirNode).MassFlowRate > 0.0) {
    1636            2 :                 state.dataLoopNodes->Node(OutsideAirNode).MassFlowRate = thisOutAirUnit.OutAirMassFlow;
    1637              :             }
    1638              : 
    1639              :             // Fan Positioning Check
    1640              : 
    1641            2 :             if (thisOutAirUnit.ExtFan) {
    1642            2 :                 state.dataLoopNodes->Node(InletNode).MassFlowRate = thisOutAirUnit.ExtAirMassFlow;
    1643              :             }
    1644              : 
    1645              :             // Air mass balance check
    1646            3 :             if ((std::abs(thisOutAirUnit.ExtAirMassFlow - thisOutAirUnit.OutAirMassFlow) > 0.001) &&
    1647            1 :                 (!state.dataHeatBal->ZoneAirMassFlow.EnforceZoneMassBalance)) {
    1648            1 :                 if (!thisOutAirUnit.FlowError) {
    1649            2 :                     ShowWarningError(state, "Air mass flow between zone supply and exhaust is not balanced. Only the first occurrence is reported.");
    1650            1 :                     ShowContinueError(state, format("Occurs in ZoneHVAC:OutdoorAirUnit Object= {}", thisOutAirUnit.Name));
    1651            2 :                     ShowContinueError(state,
    1652              :                                       "Air mass balance is required by other outdoor air units: Fan:ZoneExhaust, ZoneMixing, ZoneCrossMixing, or "
    1653              :                                       "other air flow control inputs.");
    1654            2 :                     ShowContinueErrorTimeStamp(state,
    1655            2 :                                                format("The outdoor mass flow rate = {:.3R} and the exhaust mass flow rate = {:.3R}.",
    1656            1 :                                                       thisOutAirUnit.OutAirMassFlow,
    1657            1 :                                                       thisOutAirUnit.ExtAirMassFlow));
    1658            1 :                     thisOutAirUnit.FlowError = true;
    1659              :                 }
    1660              :             }
    1661              : 
    1662            2 :             if (thisOutAirUnit.supFanPlace == HVAC::FanPlace::BlowThru) {
    1663            0 :                 state.dataFans->fans(thisOutAirUnit.SFan_Index)->simulate(state, FirstHVACIteration, _, _);
    1664            0 :                 DesOATemp = state.dataLoopNodes->Node(SFanOutletNode).Temp;
    1665            2 :             } else if (thisOutAirUnit.supFanPlace == HVAC::FanPlace::DrawThru) {
    1666            2 :                 DesOATemp = state.dataLoopNodes->Node(OutsideAirNode).Temp;
    1667              :             }
    1668              : 
    1669              :             // Control type check
    1670            2 :             switch (UnitControlType) {
    1671            0 :             case OAUnitCtrlType::Neutral: {
    1672            0 :                 SetPointTemp = state.dataZoneTempPredictorCorrector->zoneHeatBalance(ZoneNum).MAT;
    1673              :                 // Neutral Control Condition
    1674            0 :                 if (DesOATemp == SetPointTemp) {
    1675            0 :                     thisOutAirUnit.OperatingMode = Operation::NeutralMode;
    1676            0 :                     AirOutletTemp = DesOATemp;
    1677            0 :                     thisOutAirUnit.CompOutSetTemp = DesOATemp;
    1678            0 :                     SimZoneOutAirUnitComps(state, OAUnitNum, FirstHVACIteration);
    1679              :                 } else {
    1680            0 :                     if (DesOATemp < SetPointTemp) { // Heating MODE
    1681            0 :                         thisOutAirUnit.OperatingMode = Operation::HeatingMode;
    1682            0 :                         AirOutletTemp = SetPointTemp;
    1683            0 :                         thisOutAirUnit.CompOutSetTemp = AirOutletTemp;
    1684            0 :                         SimZoneOutAirUnitComps(state, OAUnitNum, FirstHVACIteration);
    1685              :                     } else { // Cooling Mode
    1686            0 :                         thisOutAirUnit.OperatingMode = Operation::CoolingMode;
    1687            0 :                         AirOutletTemp = SetPointTemp;
    1688            0 :                         thisOutAirUnit.CompOutSetTemp = AirOutletTemp;
    1689            0 :                         SimZoneOutAirUnitComps(state, OAUnitNum, FirstHVACIteration);
    1690              :                     }
    1691              :                 }
    1692              :                 // SetPoint Temperature Condition
    1693            0 :             } break;
    1694            2 :             case OAUnitCtrlType::Temperature: {
    1695            2 :                 SetPointTemp = DesOATemp;
    1696            2 :                 HiCtrlTemp = thisOutAirUnit.hiCtrlTempSched->getCurrentVal();
    1697            2 :                 LoCtrlTemp = thisOutAirUnit.loCtrlTempSched->getCurrentVal();
    1698            2 :                 if ((DesOATemp <= HiCtrlTemp) && (DesOATemp >= LoCtrlTemp)) {
    1699            0 :                     thisOutAirUnit.OperatingMode = Operation::NeutralMode;
    1700            0 :                     AirOutletTemp = DesOATemp;
    1701            0 :                     thisOutAirUnit.CompOutSetTemp = DesOATemp;
    1702            0 :                     SimZoneOutAirUnitComps(state, OAUnitNum, FirstHVACIteration);
    1703              :                 } else {
    1704            2 :                     if (SetPointTemp < LoCtrlTemp) {
    1705            2 :                         thisOutAirUnit.OperatingMode = Operation::HeatingMode;
    1706            2 :                         AirOutletTemp = LoCtrlTemp;
    1707            2 :                         thisOutAirUnit.CompOutSetTemp = AirOutletTemp;
    1708            2 :                         SimZoneOutAirUnitComps(state, OAUnitNum, FirstHVACIteration);
    1709            0 :                     } else if (SetPointTemp > HiCtrlTemp) {
    1710            0 :                         thisOutAirUnit.OperatingMode = Operation::CoolingMode;
    1711            0 :                         AirOutletTemp = HiCtrlTemp;
    1712            0 :                         thisOutAirUnit.CompOutSetTemp = AirOutletTemp;
    1713            0 :                         SimZoneOutAirUnitComps(state, OAUnitNum, FirstHVACIteration);
    1714              :                     }
    1715              :                 }
    1716            2 :             } break;
    1717            0 :             default:
    1718            0 :                 break;
    1719              :             }
    1720              : 
    1721              :             // Fan positioning
    1722            2 :             if (thisOutAirUnit.supFanPlace == HVAC::FanPlace::DrawThru) {
    1723            2 :                 state.dataFans->fans(thisOutAirUnit.SFan_Index)->simulate(state, FirstHVACIteration, _, _);
    1724              : 
    1725            2 :                 thisOutAirUnit.FanEffect = true; // RE-Simulation to take over the supply fan effect
    1726            2 :                 thisOutAirUnit.FanCorTemp = (state.dataLoopNodes->Node(OutletNode).Temp - thisOutAirUnit.CompOutSetTemp);
    1727            2 :                 SimZoneOutAirUnitComps(state, OAUnitNum, FirstHVACIteration);
    1728            2 :                 state.dataFans->fans(thisOutAirUnit.SFan_Index)->simulate(state, FirstHVACIteration, _, _);
    1729            2 :                 thisOutAirUnit.FanEffect = false;
    1730              :             }
    1731            2 :             if (thisOutAirUnit.ExtFan) {
    1732            2 :                 state.dataFans->fans(thisOutAirUnit.ExtFan_Index)->simulate(state, FirstHVACIteration, _, _);
    1733              :             }
    1734              :         } // ...end of system ON/OFF IF-THEN block
    1735              : 
    1736            2 :         AirMassFlow = state.dataLoopNodes->Node(OutletNode).MassFlowRate;
    1737            2 :         MinHumRat = min(state.dataLoopNodes->Node(OutletNode).HumRat, state.dataLoopNodes->Node(thisOutAirUnit.ZoneNodeNum).HumRat);
    1738              : 
    1739            2 :         AirInEnt = PsyHFnTdbW(state.dataLoopNodes->Node(OutletNode).Temp, MinHumRat);                   // zone supply air node enthalpy
    1740            2 :         ZoneAirEnt = PsyHFnTdbW(state.dataLoopNodes->Node(thisOutAirUnit.ZoneNodeNum).Temp, MinHumRat); // zone air enthalpy
    1741            2 :         QUnitOut = AirMassFlow * (AirInEnt - ZoneAirEnt);                                               // Senscooling
    1742              : 
    1743              :         // CR9155 Remove specific humidity calculations
    1744            2 :         SpecHumOut = state.dataLoopNodes->Node(OutletNode).HumRat;
    1745            2 :         SpecHumIn = state.dataLoopNodes->Node(thisOutAirUnit.ZoneNodeNum).HumRat;
    1746            2 :         LatentOutput = AirMassFlow * (SpecHumOut - SpecHumIn); // Latent rate (kg/s), dehumid = negative
    1747              : 
    1748              :         ZoneAirEnt =
    1749            2 :             PsyHFnTdbW(state.dataLoopNodes->Node(thisOutAirUnit.ZoneNodeNum).Temp, state.dataLoopNodes->Node(thisOutAirUnit.ZoneNodeNum).HumRat);
    1750              : 
    1751            2 :         ZoneSupAirEnt = PsyHFnTdbW(state.dataLoopNodes->Node(OutletNode).Temp, state.dataLoopNodes->Node(OutletNode).HumRat);
    1752            2 :         QTotUnitOut = AirMassFlow * (ZoneSupAirEnt - ZoneAirEnt);
    1753            2 :         LatLoadMet = QTotUnitOut - QUnitOut; // watts
    1754              : 
    1755              :         // Report variables...
    1756              : 
    1757            2 :         if (QUnitOut < 0.0) {
    1758            0 :             thisOutAirUnit.SensCoolingRate = std::abs(QUnitOut);
    1759            0 :             thisOutAirUnit.SensHeatingRate = 0.0;
    1760              :         } else {
    1761            2 :             thisOutAirUnit.SensCoolingRate = 0.0;
    1762            2 :             thisOutAirUnit.SensHeatingRate = QUnitOut;
    1763              :         }
    1764              : 
    1765            2 :         if (QTotUnitOut < 0.0) {
    1766            0 :             thisOutAirUnit.TotCoolingRate = std::abs(QTotUnitOut);
    1767            0 :             thisOutAirUnit.TotHeatingRate = 0.0;
    1768              :         } else {
    1769            2 :             thisOutAirUnit.TotCoolingRate = 0.0;
    1770            2 :             thisOutAirUnit.TotHeatingRate = QTotUnitOut;
    1771              :         }
    1772              : 
    1773            2 :         if (LatLoadMet < 0.0) {
    1774            0 :             thisOutAirUnit.LatCoolingRate = std::abs(LatLoadMet);
    1775            0 :             thisOutAirUnit.LatHeatingRate = 0.0;
    1776              :         } else {
    1777            2 :             thisOutAirUnit.LatCoolingRate = 0.0;
    1778            2 :             thisOutAirUnit.LatHeatingRate = LatLoadMet;
    1779              :         }
    1780              : 
    1781              :         // OutAirUnit( OAUnitNum ).ElecFanRate = FanElecPower;  //Issue #5524 this would only get the last fan called, not both if there are two
    1782            2 :         thisOutAirUnit.ElecFanRate = 0.0;
    1783            2 :         thisOutAirUnit.ElecFanRate += state.dataFans->fans(thisOutAirUnit.SFan_Index)->totalPower;
    1784              : 
    1785            2 :         if (thisOutAirUnit.ExtFan) {
    1786            2 :             thisOutAirUnit.ElecFanRate += state.dataFans->fans(thisOutAirUnit.ExtFan_Index)->totalPower;
    1787              :         }
    1788              : 
    1789            2 :         PowerMet = QUnitOut;
    1790            2 :         LatOutputProvided = LatentOutput;
    1791            2 :     }
    1792              : 
    1793            4 :     void SimZoneOutAirUnitComps(EnergyPlusData &state, int const OAUnitNum, bool const FirstHVACIteration)
    1794              :     {
    1795              : 
    1796              :         // SUBROUTINE INFORMATION:
    1797              :         //       AUTHOR         Fred Buhl
    1798              :         //       DATE WRITTEN   Oct 1998
    1799              :         //       MODIFIED       na
    1800              :         //       RE-ENGINEERED  na
    1801              : 
    1802              :         // PURPOSE OF THIS SUBROUTINE
    1803              :         // Simulate the controllers and components in the outside air system.
    1804              : 
    1805              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    1806            4 :         bool const Sim = true;
    1807              : 
    1808            4 :         auto &thisOutAirUnit = state.dataOutdoorAirUnit->OutAirUnit(OAUnitNum);
    1809           12 :         for (int EquipNum = 1; EquipNum <= thisOutAirUnit.NumComponents; ++EquipNum) {
    1810            8 :             auto &thisOAEquip = thisOutAirUnit.OAEquip(EquipNum);
    1811            8 :             SimOutdoorAirEquipComps(state,
    1812              :                                     OAUnitNum,
    1813            8 :                                     CompTypeNames[static_cast<int>(thisOAEquip.Type)],
    1814            8 :                                     thisOAEquip.ComponentName,
    1815              :                                     EquipNum,
    1816              :                                     thisOAEquip.Type,
    1817              :                                     FirstHVACIteration,
    1818            8 :                                     thisOAEquip.ComponentIndex,
    1819              :                                     Sim);
    1820              :         }
    1821            4 :     }
    1822              : 
    1823            8 :     void SimOutdoorAirEquipComps(EnergyPlusData &state,
    1824              :                                  int const OAUnitNum,          // actual outdoor air unit num
    1825              :                                  std::string_view EquipType,   // the component type
    1826              :                                  std::string const &EquipName, // the component Name
    1827              :                                  int const EquipNum,
    1828              :                                  [[maybe_unused]] CompType const CompTypeNum, // Component Type -- Integerized for this module
    1829              :                                  bool const FirstHVACIteration,
    1830              :                                  int &CompIndex,
    1831              :                                  bool const Sim // if TRUE, simulate component
    1832              :     )
    1833              :     {
    1834              : 
    1835              :         // SUBROUTINE INFORMATION:
    1836              :         //       AUTHOR         Young Tae Chae, Rick Strand
    1837              :         //       DATE WRITTEN   June 2008
    1838              :         //       MODIFIED
    1839              :         //       RE-ENGINEERED  na
    1840              : 
    1841              :         // PURPOSE OF THIS SUBROUTINE:
    1842              :         // Outdoor air unit has various coil options. This subroutine defines the coil loads and execute
    1843              :         // to simulate each components
    1844              :         // METHODOLOGY EMPLOYED:
    1845              : 
    1846              :         // REFERENCES:
    1847              : 
    1848              :         // USE STATEMENTS:
    1849              : 
    1850              :         // Using/Aliasing
    1851              :         using DesiccantDehumidifiers::SimDesiccantDehumidifier;
    1852              :         using HeatRecovery::SimHeatRecovery;
    1853              :         using HVAC::SmallLoad;
    1854              :         using HVACDXHeatPumpSystem::SimDXHeatPumpSystem;
    1855              :         using HVACHXAssistedCoolingCoil::SimHXAssistedCoolingCoil;
    1856              :         using WaterCoils::SimulateWaterCoilComponents;
    1857              : 
    1858              :         // SUBROUTINE LOCAL VARIABLE DEFINITIONS
    1859              :         Real64 QCompReq;
    1860              :         Real64 MaxWaterFlow;
    1861              :         Real64 MinWaterFlow;
    1862              :         Real64 QUnitOut;
    1863              :         Real64 Dxsystemouttemp;
    1864              : 
    1865            8 :         auto &thisOutAirUnit = state.dataOutdoorAirUnit->OutAirUnit(OAUnitNum);
    1866            8 :         auto &thisOAEquip = thisOutAirUnit.OAEquip(EquipNum);
    1867            8 :         int const InletNodeNum = thisOAEquip.CoilAirInletNode;
    1868            8 :         int const OutletNodeNum = thisOAEquip.CoilAirOutletNode;
    1869              : 
    1870            8 :         int UnitNum = OAUnitNum;
    1871            8 :         int SimCompNum = EquipNum;
    1872              : 
    1873            8 :         Real64 const CompAirOutTemp = thisOutAirUnit.CompOutSetTemp;
    1874            8 :         Operation const OpMode = thisOutAirUnit.OperatingMode;
    1875            8 :         CompType const EquipTypeNum = thisOAEquip.Type;
    1876            8 :         Real64 const OAMassFlow = thisOutAirUnit.OutAirMassFlow;
    1877              : 
    1878              :         // check the fan positioning
    1879            8 :         bool const DrawFan = thisOutAirUnit.FanEffect;
    1880            8 :         Real64 const FanEffect = DrawFan ? thisOutAirUnit.FanCorTemp : 0.0;
    1881              : 
    1882              :         // checking equipment index
    1883              : 
    1884              :         {
    1885            8 :             switch (EquipTypeNum) {
    1886              :             // Heat recovery
    1887            0 :             case CompType::HeatXchngrFP: // 'HeatExchanger:AirToAir:FlatPlate',
    1888              :             case CompType::HeatXchngrSL: // 'HeatExchanger:AirToAir:SensibleAndLatent',
    1889              :                                          // 'HeatExchanger:Desiccant:BalancedFlow' - unused
    1890              :             {
    1891              : 
    1892            0 :                 if (Sim) {
    1893            0 :                     SimHeatRecovery(state, EquipName, FirstHVACIteration, CompIndex, HVAC::FanOp::Continuous, _, _, _, _, false, false);
    1894              :                 }
    1895            0 :             } break;
    1896              :             // Desiccant Dehumidifier
    1897            0 :             case CompType::Desiccant: { // 'Dehumidifier:Desiccant:NoFans'
    1898            0 :                 if (Sim) {
    1899            0 :                     SimDesiccantDehumidifier(state, EquipName, FirstHVACIteration, CompIndex);
    1900              :                 }
    1901              : 
    1902            0 :             } break;
    1903            0 :             case CompType::WaterCoil_SimpleHeat: { // ('Coil:Heating:Water')
    1904              : 
    1905            0 :                 if (Sim) {
    1906            0 :                     int const ControlNode = thisOAEquip.CoilWaterInletNode;
    1907            0 :                     MaxWaterFlow = thisOAEquip.MaxWaterMassFlow;
    1908            0 :                     MinWaterFlow = thisOAEquip.MinWaterMassFlow;
    1909              :                     // On the first HVAC iteration the system values are given to the controller, but after that
    1910              :                     // the demand limits are in place and there needs to be feedback to the Zone Equipment
    1911            0 :                     if ((!FirstHVACIteration) && (ControlNode > 0)) {
    1912            0 :                         MaxWaterFlow = state.dataLoopNodes->Node(ControlNode).MassFlowRateMaxAvail;
    1913            0 :                         MinWaterFlow = state.dataLoopNodes->Node(ControlNode).MassFlowRateMinAvail;
    1914              :                     }
    1915            0 :                     auto const &whCoilInletNode = state.dataLoopNodes->Node(InletNodeNum);
    1916              :                     // auto &whCoilOutletNode = state.dataLoopNodes->Node(OutletNodeNum);
    1917              : 
    1918            0 :                     Real64 const CpAirZn = PsyCpAirFnW(whCoilInletNode.HumRat);
    1919              : 
    1920            0 :                     if ((OpMode == Operation::NeutralMode) || (OpMode == Operation::CoolingMode) || (whCoilInletNode.Temp > CompAirOutTemp)) {
    1921            0 :                         QCompReq = 0.0;
    1922              :                     } else {
    1923            0 :                         QCompReq = CpAirZn * OAMassFlow * ((CompAirOutTemp - whCoilInletNode.Temp) - FanEffect);
    1924            0 :                         if (std::abs(QCompReq) < SmallLoad) QCompReq = 0.0;
    1925            0 :                         if (QCompReq < 0.0) QCompReq = 0.0; // coil can heat only
    1926              :                     }
    1927              : 
    1928            0 :                     ControlCompOutput(state,
    1929            0 :                                       thisOutAirUnit.Name,
    1930            0 :                                       std::string(ZoneHVACOAUnit),
    1931              :                                       UnitNum,
    1932              :                                       FirstHVACIteration,
    1933              :                                       QCompReq,
    1934              :                                       ControlNode,
    1935              :                                       MaxWaterFlow,
    1936              :                                       MinWaterFlow,
    1937              :                                       0.0001,
    1938            0 :                                       thisOutAirUnit.ControlCompTypeNum,
    1939            0 :                                       thisOutAirUnit.CompErrIndex,
    1940              :                                       _,
    1941              :                                       _,
    1942              :                                       _,
    1943            0 :                                       2,
    1944              :                                       SimCompNum,
    1945            0 :                                       thisOAEquip.plantLoc);
    1946              :                 }
    1947            0 :             } break;
    1948            0 :             case CompType::SteamCoil_AirHeat: { // 'Coil:Heating:Steam'
    1949            0 :                 if (Sim) {
    1950            0 :                     CalcOAUnitCoilComps(state, UnitNum, FirstHVACIteration, SimCompNum, QUnitOut);
    1951              :                 }
    1952            0 :             } break;
    1953            4 :             case CompType::Coil_ElectricHeat: // 'Coil:Heating:Electric'
    1954              :             case CompType::Coil_GasHeat: {    // 'Coil:Heating:Fuel'
    1955            4 :                 if (Sim) {
    1956              :                     //     stand-alone coils are temperature controlled (do not pass QCoilReq in argument list, QCoilReq overrides temp SP)
    1957            4 :                     CalcOAUnitCoilComps(state, UnitNum, FirstHVACIteration, SimCompNum, QUnitOut);
    1958              :                 }
    1959            4 :             } break;
    1960              :                 // water cooling coil Types
    1961            0 :             case CompType::WaterCoil_Cooling: { // 'Coil:Cooling:Water'
    1962            0 :                 if (Sim) {
    1963            0 :                     int const ControlNode = thisOAEquip.CoilWaterInletNode;
    1964            0 :                     MaxWaterFlow = thisOAEquip.MaxWaterMassFlow;
    1965            0 :                     MinWaterFlow = thisOAEquip.MinWaterMassFlow;
    1966              :                     // On the first HVAC iteration the system values are given to the controller, but after that
    1967              :                     // the demand limits are in place and there needs to be feedback to the Zone Equipment
    1968            0 :                     if ((!FirstHVACIteration) && (ControlNode > 0)) {
    1969            0 :                         MaxWaterFlow = state.dataLoopNodes->Node(ControlNode).MassFlowRateMaxAvail;
    1970            0 :                         MinWaterFlow = state.dataLoopNodes->Node(ControlNode).MassFlowRateMinAvail;
    1971              :                     }
    1972              : 
    1973            0 :                     auto const &wcCoilInletNode = state.dataLoopNodes->Node(InletNodeNum);
    1974            0 :                     auto &wcCoilOutletNode = state.dataLoopNodes->Node(OutletNodeNum);
    1975              : 
    1976            0 :                     Real64 const CpAirZn = PsyCpAirFnW(wcCoilInletNode.HumRat);
    1977            0 :                     if ((OpMode == Operation::NeutralMode) || (OpMode == Operation::HeatingMode) || (wcCoilInletNode.Temp < CompAirOutTemp)) {
    1978            0 :                         QCompReq = 0.0;
    1979            0 :                         wcCoilOutletNode.Temp = wcCoilInletNode.Temp;
    1980            0 :                         wcCoilOutletNode.HumRat = wcCoilInletNode.HumRat;
    1981            0 :                         wcCoilOutletNode.MassFlowRate = wcCoilInletNode.MassFlowRate;
    1982              : 
    1983              :                     } else {
    1984              : 
    1985            0 :                         QCompReq = CpAirZn * OAMassFlow * ((CompAirOutTemp - wcCoilInletNode.Temp) - FanEffect);
    1986            0 :                         if (std::abs(QCompReq) < SmallLoad) QCompReq = 0.0;
    1987            0 :                         if (QCompReq > 0.0) QCompReq = 0.0; // coil can cool only
    1988              :                     }
    1989              : 
    1990            0 :                     ControlCompOutput(state,
    1991            0 :                                       thisOutAirUnit.Name,
    1992            0 :                                       std::string(ZoneHVACOAUnit),
    1993              :                                       UnitNum,
    1994              :                                       FirstHVACIteration,
    1995              :                                       QCompReq,
    1996              :                                       ControlNode,
    1997              :                                       MaxWaterFlow,
    1998              :                                       MinWaterFlow,
    1999              :                                       0.001,
    2000            0 :                                       thisOutAirUnit.ControlCompTypeNum,
    2001            0 :                                       thisOutAirUnit.CompErrIndex,
    2002              :                                       _,
    2003              :                                       _,
    2004              :                                       _,
    2005            0 :                                       1,
    2006              :                                       SimCompNum,
    2007            0 :                                       thisOAEquip.plantLoc);
    2008              :                 }
    2009            0 :             } break;
    2010            0 :             case CompType::WaterCoil_DetailedCool: { // 'Coil:Cooling:Water:DetailedGeometry'
    2011            0 :                 if (Sim) {
    2012            0 :                     int const ControlNode = thisOAEquip.CoilWaterInletNode;
    2013            0 :                     MaxWaterFlow = thisOAEquip.MaxWaterMassFlow;
    2014            0 :                     MinWaterFlow = thisOAEquip.MinWaterMassFlow;
    2015              :                     // On the first HVAC iteration the system values are given to the controller, but after that
    2016              :                     // the demand limits are in place and there needs to be feedback to the Zone Equipment
    2017            0 :                     if ((!FirstHVACIteration) && (ControlNode > 0)) {
    2018            0 :                         MaxWaterFlow = state.dataLoopNodes->Node(ControlNode).MassFlowRateMaxAvail;
    2019            0 :                         MinWaterFlow = state.dataLoopNodes->Node(ControlNode).MassFlowRateMinAvail;
    2020              :                     }
    2021            0 :                     auto const &wcCoilInletNode = state.dataLoopNodes->Node(InletNodeNum);
    2022              :                     // auto &wcCoilOutletNode = state.dataLoopNodes->Node(OutletNodeNum);
    2023              : 
    2024            0 :                     Real64 const CpAirZn = PsyCpAirFnW(wcCoilInletNode.HumRat);
    2025              : 
    2026            0 :                     if ((OpMode == Operation::NeutralMode) || (OpMode == Operation::HeatingMode) || (wcCoilInletNode.Temp < CompAirOutTemp)) {
    2027            0 :                         QCompReq = 0.0;
    2028              :                     } else {
    2029              : 
    2030            0 :                         QCompReq = CpAirZn * OAMassFlow * ((CompAirOutTemp - wcCoilInletNode.Temp) - FanEffect);
    2031            0 :                         if (std::abs(QCompReq) < SmallLoad) QCompReq = 0.0;
    2032            0 :                         if (QCompReq > 0.0) QCompReq = 0.0; // coil can cool only
    2033              :                     }
    2034              : 
    2035            0 :                     ControlCompOutput(state,
    2036            0 :                                       thisOutAirUnit.Name,
    2037              :                                       "ZONEHVAC:OUTDOORAIRUNIT",
    2038              :                                       UnitNum,
    2039              :                                       FirstHVACIteration,
    2040              :                                       QCompReq,
    2041              :                                       ControlNode,
    2042              :                                       MaxWaterFlow,
    2043              :                                       MinWaterFlow,
    2044              :                                       0.001,
    2045            0 :                                       thisOutAirUnit.ControlCompTypeNum,
    2046            0 :                                       thisOutAirUnit.CompErrIndex,
    2047              :                                       _,
    2048              :                                       _,
    2049              :                                       _,
    2050            0 :                                       1,
    2051              :                                       SimCompNum,
    2052            0 :                                       thisOAEquip.plantLoc);
    2053              :                 }
    2054            0 :             } break;
    2055            0 :             case CompType::WaterCoil_CoolingHXAsst: { // 'CoilSystem:Cooling:Water:HeatExchangerAssisted'
    2056            0 :                 if (Sim) {
    2057            0 :                     int const ControlNode = thisOAEquip.CoilWaterInletNode;
    2058            0 :                     MaxWaterFlow = thisOAEquip.MaxWaterMassFlow;
    2059            0 :                     MinWaterFlow = 0.0;
    2060              :                     // On the first HVAC iteration the system values are given to the controller, but after that
    2061              :                     // the demand limits are in place and there needs to be feedback to the Zone Equipment
    2062            0 :                     if ((!FirstHVACIteration) && (ControlNode > 0)) {
    2063            0 :                         MaxWaterFlow = state.dataLoopNodes->Node(ControlNode).MassFlowRateMaxAvail;
    2064            0 :                         MinWaterFlow = state.dataLoopNodes->Node(ControlNode).MassFlowRateMinAvail;
    2065              :                     }
    2066            0 :                     auto const &wcCoilInletNode = state.dataLoopNodes->Node(InletNodeNum);
    2067              :                     // auto &wcCoilOutletNode = state.dataLoopNodes->Node(OutletNodeNum);
    2068              : 
    2069            0 :                     Real64 const CpAirZn = PsyCpAirFnW(wcCoilInletNode.HumRat);
    2070            0 :                     if ((OpMode == Operation::NeutralMode) || (OpMode == Operation::HeatingMode) || (wcCoilInletNode.Temp < CompAirOutTemp)) {
    2071            0 :                         QCompReq = 0.0;
    2072              :                     } else {
    2073            0 :                         QCompReq = CpAirZn * OAMassFlow * ((CompAirOutTemp - wcCoilInletNode.Temp) - FanEffect);
    2074            0 :                         if (std::abs(QCompReq) < SmallLoad) QCompReq = 0.0;
    2075            0 :                         if (QCompReq > 0.0) QCompReq = 0.0; // coil can cool only
    2076              :                     }
    2077            0 :                     ControlCompOutput(state,
    2078            0 :                                       thisOutAirUnit.Name,
    2079              :                                       "ZONEHVAC:OUTDOORAIRUNIT",
    2080              :                                       UnitNum,
    2081              :                                       FirstHVACIteration,
    2082              :                                       QCompReq,
    2083              :                                       ControlNode,
    2084              :                                       MaxWaterFlow,
    2085              :                                       MinWaterFlow,
    2086              :                                       0.001,
    2087            0 :                                       thisOutAirUnit.ControlCompTypeNum,
    2088            0 :                                       thisOutAirUnit.CompErrIndex,
    2089              :                                       _,
    2090              :                                       _,
    2091              :                                       _,
    2092            0 :                                       1,
    2093              :                                       SimCompNum,
    2094            0 :                                       thisOAEquip.plantLoc);
    2095              :                 }
    2096            0 :             } break;
    2097            4 :             case CompType::DXSystem: { // CoilSystem:Cooling:DX  old 'CompType:UnitaryCoolOnly'
    2098            4 :                 if (Sim) {
    2099            4 :                     if (thisOAEquip.compPointer == nullptr) {
    2100            1 :                         UnitarySystems::UnitarySys thisSys;
    2101            1 :                         thisOAEquip.compPointer =
    2102            1 :                             thisSys.factory(state, HVAC::UnitarySysType::Unitary_AnyCoilType, thisOAEquip.ComponentName, false, OAUnitNum);
    2103            1 :                         UnitarySystems::UnitarySys::checkUnitarySysCoilInOASysExists(state, thisOAEquip.ComponentName, OAUnitNum);
    2104            1 :                     }
    2105            4 :                     if (((OpMode == Operation::NeutralMode) && (thisOutAirUnit.controlType == OAUnitCtrlType::Temperature)) ||
    2106              :                         (OpMode == Operation::HeatingMode)) {
    2107            4 :                         Dxsystemouttemp = 100.0; // There is no cooling demand for the DX system.
    2108              :                     } else {
    2109            0 :                         Dxsystemouttemp = CompAirOutTemp - FanEffect;
    2110              :                     }
    2111            4 :                     Real64 sensOut = 0.0;
    2112            4 :                     Real64 latOut = 0.0;
    2113            4 :                     int DXSystemIndex = 0;
    2114            4 :                     thisOAEquip.compPointer->simulate(state,
    2115              :                                                       EquipName,
    2116              :                                                       FirstHVACIteration,
    2117              :                                                       -1,
    2118              :                                                       DXSystemIndex,
    2119            4 :                                                       state.dataOutdoorAirUnit->HeatActive,
    2120            4 :                                                       state.dataOutdoorAirUnit->CoolActive,
    2121              :                                                       UnitNum,
    2122              :                                                       Dxsystemouttemp,
    2123              :                                                       false,
    2124              :                                                       sensOut,
    2125              :                                                       latOut);
    2126              :                 }
    2127            4 :             } break;
    2128            0 :             case CompType::DXHeatPumpSystem: {
    2129            0 :                 if (Sim) {
    2130            0 :                     if (((OpMode == Operation::NeutralMode) && (thisOutAirUnit.controlType == OAUnitCtrlType::Temperature)) ||
    2131              :                         (OpMode == Operation::CoolingMode)) {
    2132            0 :                         Dxsystemouttemp = -20.0; // There is no heating demand for the DX system.
    2133              :                     } else {
    2134            0 :                         Dxsystemouttemp = CompAirOutTemp - FanEffect;
    2135              :                     }
    2136            0 :                     int DXSystemIndex = 0;
    2137            0 :                     SimDXHeatPumpSystem(state, EquipName, FirstHVACIteration, -1, DXSystemIndex, UnitNum, Dxsystemouttemp);
    2138              :                 }
    2139            0 :             } break;
    2140              :                 // RAR need new CompType:UnitarySystem object here
    2141            0 :             case CompType::UnitarySystemModel: { // 'CompType:UnitarySystem'
    2142            0 :                 if (Sim) {
    2143              :                     // This may have to be done in the unitary system object since there can be both cooling and heating
    2144            0 :                     if (((OpMode == Operation::NeutralMode) && (thisOutAirUnit.controlType == OAUnitCtrlType::Temperature)) ||
    2145              :                         (OpMode == Operation::HeatingMode)) {
    2146            0 :                         Dxsystemouttemp = 100.0; // There is no cooling demand.
    2147            0 :                     } else if (((OpMode == Operation::NeutralMode) && (thisOutAirUnit.controlType == OAUnitCtrlType::Temperature)) ||
    2148              :                                (OpMode == Operation::CoolingMode)) {
    2149            0 :                         Dxsystemouttemp = -20.0; // There is no heating demand.
    2150              :                     } else {
    2151            0 :                         Dxsystemouttemp = CompAirOutTemp - FanEffect;
    2152              :                     }
    2153            0 :                     Real64 sensOut = 0.0;
    2154            0 :                     Real64 latOut = 0.0;
    2155            0 :                     int DXSystemIndex = 0;
    2156            0 :                     thisOAEquip.compPointer->simulate(state,
    2157              :                                                       EquipName,
    2158              :                                                       FirstHVACIteration,
    2159              :                                                       -1,
    2160              :                                                       DXSystemIndex,
    2161            0 :                                                       state.dataOutdoorAirUnit->HeatActive,
    2162            0 :                                                       state.dataOutdoorAirUnit->CoolActive,
    2163              :                                                       UnitNum,
    2164              :                                                       Dxsystemouttemp,
    2165              :                                                       false,
    2166              :                                                       sensOut,
    2167              :                                                       latOut);
    2168              :                 }
    2169            0 :             } break;
    2170            0 :             default: {
    2171            0 :                 ShowFatalError(state, format("Invalid Outdoor Air Unit Component={}", EquipType)); // validate
    2172            0 :             } break;
    2173              :             }
    2174              :         }
    2175            8 :     }
    2176              : 
    2177            4 :     void CalcOAUnitCoilComps(EnergyPlusData &state,
    2178              :                              int const CompNum, // actual outdoor air unit num
    2179              :                              bool const FirstHVACIteration,
    2180              :                              int const EquipIndex, // Component Type -- Integerized for this module
    2181              :                              Real64 &LoadMet)
    2182              :     {
    2183              : 
    2184              :         // SUBROUTINE INFORMATION:
    2185              :         //       AUTHOR         Young Tae Chae, Rick Strand
    2186              :         //       DATE WRITTEN   June 2009
    2187              :         //       MODIFIED
    2188              :         //       RE-ENGINEERED  na
    2189              : 
    2190              :         // PURPOSE OF THIS SUBROUTINE:
    2191              :         // This subroutine mainly controls the action of water components in the unit
    2192              : 
    2193              :         // METHODOLOGY EMPLOYED:
    2194              : 
    2195              :         // REFERENCES:
    2196              : 
    2197              :         // USE STATEMENTS:
    2198              : 
    2199              :         // Using/Aliasing
    2200              :         using HVAC::SmallLoad;
    2201              :         using HVACHXAssistedCoolingCoil::SimHXAssistedCoolingCoil;
    2202              :         using SteamCoils::SimulateSteamCoilComponents;
    2203              :         using WaterCoils::SimulateWaterCoilComponents;
    2204              : 
    2205              :         // SUBROUTINE ARGUMENT DEFINITIONS:
    2206              : 
    2207              :         // Locals
    2208              :         // SUBROUTINE LOCAL VARIABLE DEFINITIONS
    2209            4 :         int CoilIndex = 0;
    2210              : 
    2211            4 :         auto &thisOutAirUnit = state.dataOutdoorAirUnit->OutAirUnit(CompNum);
    2212            4 :         auto &thisOAEquip = thisOutAirUnit.OAEquip(EquipIndex);
    2213            4 :         int const InletNodeNum = thisOAEquip.CoilAirInletNode;
    2214            4 :         int const OutletNodeNum = thisOAEquip.CoilAirOutletNode;
    2215            4 :         auto const &oaInletNode = state.dataLoopNodes->Node(InletNodeNum);
    2216            4 :         auto &oaOutletNode = state.dataLoopNodes->Node(OutletNodeNum);
    2217              : 
    2218            4 :         CompType const CoilTypeNum = thisOAEquip.Type;
    2219            4 :         Operation const OpMode = thisOutAirUnit.OperatingMode;
    2220            4 :         Real64 const CoilAirOutTemp = thisOutAirUnit.CompOutSetTemp;
    2221            4 :         bool const DrawFan = thisOutAirUnit.FanEffect;
    2222            4 :         Real64 const FanEffect = DrawFan ? thisOutAirUnit.FanCorTemp : 0.0;
    2223              : 
    2224              :         // Actual equipment load
    2225            4 :         auto setupQCompReq = [&OpMode, &oaInletNode, &oaOutletNode, &CoilAirOutTemp, &FanEffect]() -> Real64 {
    2226            4 :             Real64 QCompReq = 0.0;
    2227            4 :             if ((OpMode == Operation::NeutralMode) || (OpMode == Operation::CoolingMode) || (oaInletNode.Temp > CoilAirOutTemp)) {
    2228            0 :                 QCompReq = 0.0;
    2229              :             } else {
    2230            4 :                 oaOutletNode.MassFlowRate = oaInletNode.MassFlowRate;
    2231            4 :                 Real64 const CpAirZn = PsyCpAirFnW(oaInletNode.HumRat);
    2232            4 :                 QCompReq = oaInletNode.MassFlowRate * CpAirZn * ((CoilAirOutTemp - oaInletNode.Temp) - FanEffect);
    2233            4 :                 if (std::abs(QCompReq) < SmallLoad) {
    2234            0 :                     QCompReq = 0.0;
    2235              :                 }
    2236              :             }
    2237            4 :             if (QCompReq <= 0.0) {
    2238            0 :                 QCompReq = 0.0; // a heating coil can only heat, not cool
    2239            0 :                 oaOutletNode.Temp = oaInletNode.Temp;
    2240            0 :                 oaOutletNode.HumRat = oaInletNode.HumRat;
    2241            0 :                 oaOutletNode.MassFlowRate = oaInletNode.MassFlowRate;
    2242              :             }
    2243            4 :             return QCompReq;
    2244            4 :         };
    2245              : 
    2246            4 :         switch (CoilTypeNum) {
    2247            4 :         case CompType::Coil_ElectricHeat: {
    2248            4 :             Real64 const QCompReq = setupQCompReq();
    2249            4 :             HeatingCoils::SimulateHeatingCoilComponents(state, thisOAEquip.ComponentName, FirstHVACIteration, QCompReq, CoilIndex);
    2250            4 :             Real64 const AirMassFlow = oaInletNode.MassFlowRate;
    2251            4 :             LoadMet = AirMassFlow * (PsyHFnTdbW(oaOutletNode.Temp, oaInletNode.HumRat) - PsyHFnTdbW(oaInletNode.Temp, oaInletNode.HumRat));
    2252              : 
    2253            4 :         } break;
    2254            0 :         case CompType::Coil_GasHeat: { // 'Coil:Heating:Steam'
    2255            0 :             Real64 const QCompReq = setupQCompReq();
    2256            0 :             HeatingCoils::SimulateHeatingCoilComponents(state, thisOAEquip.ComponentName, FirstHVACIteration, QCompReq, CoilIndex);
    2257            0 :             Real64 const AirMassFlow = oaInletNode.MassFlowRate;
    2258            0 :             LoadMet = AirMassFlow * (PsyHFnTdbW(oaOutletNode.Temp, oaInletNode.HumRat) - PsyHFnTdbW(oaInletNode.Temp, oaInletNode.HumRat));
    2259              : 
    2260            0 :         } break;
    2261            0 :         case CompType::SteamCoil_AirHeat: { // 'Coil:Heating:Steam'
    2262            0 :             Real64 const QCompReq = setupQCompReq();
    2263            0 :             SimulateSteamCoilComponents(state, thisOAEquip.ComponentName, FirstHVACIteration, CoilIndex, QCompReq);
    2264            0 :             Real64 const AirMassFlow = oaInletNode.MassFlowRate;
    2265            0 :             LoadMet = AirMassFlow * (PsyHFnTdbW(oaOutletNode.Temp, oaInletNode.HumRat) - PsyHFnTdbW(oaInletNode.Temp, oaInletNode.HumRat));
    2266              : 
    2267            0 :         } break;
    2268            0 :         case CompType::WaterCoil_SimpleHeat: // 'Coil:Heating:Water')
    2269              :         case CompType::WaterCoil_Cooling:    // 'Coil:Cooling:Water'
    2270              :         case CompType::WaterCoil_DetailedCool: {
    2271            0 :             SimulateWaterCoilComponents(state, thisOAEquip.ComponentName, FirstHVACIteration, CoilIndex);
    2272            0 :             Real64 const AirMassFlow = oaInletNode.MassFlowRate;
    2273            0 :             LoadMet = AirMassFlow * (PsyHFnTdbW(oaOutletNode.Temp, oaInletNode.HumRat) - PsyHFnTdbW(oaInletNode.Temp, oaInletNode.HumRat));
    2274              : 
    2275            0 :         } break;
    2276            0 :         case CompType::WaterCoil_CoolingHXAsst: {
    2277            0 :             SimHXAssistedCoolingCoil(
    2278              :                 state, thisOAEquip.ComponentName, FirstHVACIteration, HVAC::CompressorOp::On, 0.0, CoilIndex, HVAC::FanOp::Continuous);
    2279            0 :             Real64 const AirMassFlow = oaInletNode.MassFlowRate;
    2280            0 :             LoadMet = AirMassFlow * (PsyHFnTdbW(oaOutletNode.Temp, oaInletNode.HumRat) - PsyHFnTdbW(oaInletNode.Temp, oaInletNode.HumRat));
    2281            0 :         } break;
    2282            0 :         default:
    2283            0 :             ShowFatalError(state, format("Invalid Coil Type = {}", CoilTypeNum)); // validate
    2284            0 :             break;
    2285              :         }
    2286            4 :     }
    2287              : 
    2288              :     // SUBROUTINE UpdateOutdoorAirUnit
    2289              : 
    2290              :     // No update routine needed in this module since all of the updates happen on
    2291              :     // the Node derived type directly and these updates are done by other routines.
    2292              : 
    2293              :     // END SUBROUTINE UpdateOutdoorAirUnit
    2294              : 
    2295            1 :     void ReportOutdoorAirUnit(EnergyPlusData &state,
    2296              :                               int const OAUnitNum) // Index for the outdoor air unit under consideration within the derived types
    2297              :     {
    2298              : 
    2299              :         // SUBROUTINE INFORMATION:
    2300              :         //       AUTHOR         Young T. Chae
    2301              :         //       DATE WRITTEN   Oct. 2009
    2302              :         //       MODIFIED       na
    2303              :         //       RE-ENGINEERED  na
    2304              : 
    2305              :         // PURPOSE OF THIS SUBROUTINE:
    2306              :         // This subroutine simply produces output for the outdoor air unit.
    2307              :         // METHODOLOGY EMPLOYED:
    2308              :         // Standard EnergyPlus methodology.
    2309              : 
    2310              :         // Using/Aliasing
    2311            1 :         Real64 const TimeStepSysSec = state.dataHVACGlobal->TimeStepSysSec;
    2312              : 
    2313            1 :         auto &thisOutAirUnit = state.dataOutdoorAirUnit->OutAirUnit(OAUnitNum);
    2314            1 :         thisOutAirUnit.TotHeatingEnergy = thisOutAirUnit.TotHeatingRate * TimeStepSysSec;
    2315            1 :         thisOutAirUnit.SensHeatingEnergy = thisOutAirUnit.SensHeatingRate * TimeStepSysSec;
    2316            1 :         thisOutAirUnit.LatHeatingEnergy = thisOutAirUnit.LatHeatingRate * TimeStepSysSec;
    2317            1 :         thisOutAirUnit.SensCoolingEnergy = thisOutAirUnit.SensCoolingRate * TimeStepSysSec;
    2318            1 :         thisOutAirUnit.LatCoolingEnergy = thisOutAirUnit.LatCoolingRate * TimeStepSysSec;
    2319            1 :         thisOutAirUnit.TotCoolingEnergy = thisOutAirUnit.TotCoolingRate * TimeStepSysSec;
    2320            1 :         thisOutAirUnit.AirMassFlow = thisOutAirUnit.OutAirMassFlow;
    2321            1 :         thisOutAirUnit.ElecFanEnergy = thisOutAirUnit.ElecFanRate * TimeStepSysSec;
    2322              : 
    2323            1 :         if (thisOutAirUnit.FirstPass) { // reset sizing flags so other zone equipment can size normally
    2324            1 :             if (!state.dataGlobal->SysSizingCalc) {
    2325            1 :                 DataSizing::resetHVACSizingGlobals(state, state.dataSize->CurZoneEqNum, 0, thisOutAirUnit.FirstPass);
    2326              :             }
    2327              :         }
    2328            1 :     }
    2329              : 
    2330            1 :     int GetOutdoorAirUnitOutAirNode(EnergyPlusData &state, int const OAUnitNum)
    2331              :     {
    2332              : 
    2333              :         // FUNCTION INFORMATION:
    2334              :         //       AUTHOR         B Griffith
    2335              :         //       DATE WRITTEN   Dec  2006
    2336              :         //       MODIFIED       na
    2337              :         //       RE-ENGINEERED  na
    2338              : 
    2339              :         // PURPOSE OF THIS FUNCTION:
    2340              :         // lookup function for OA inlet node
    2341              : 
    2342              :         // Return value
    2343            1 :         int GetOutdoorAirUnitOutAirNode = 0;
    2344              : 
    2345            1 :         if (state.dataOutdoorAirUnit->GetOutdoorAirUnitInputFlag) {
    2346            0 :             OutdoorAirUnit::GetOutdoorAirUnitInputs(state);
    2347            0 :             state.dataOutdoorAirUnit->GetOutdoorAirUnitInputFlag = false;
    2348              :         }
    2349              : 
    2350            1 :         if (OAUnitNum > 0 && OAUnitNum <= state.dataOutdoorAirUnit->NumOfOAUnits) {
    2351            1 :             GetOutdoorAirUnitOutAirNode = state.dataOutdoorAirUnit->OutAirUnit(OAUnitNum).OutsideAirNode;
    2352              :         }
    2353              : 
    2354            1 :         return GetOutdoorAirUnitOutAirNode;
    2355              :     }
    2356              : 
    2357            2 :     int GetOutdoorAirUnitZoneInletNode(EnergyPlusData &state, int const OAUnitNum)
    2358              :     {
    2359              : 
    2360              :         // FUNCTION INFORMATION:
    2361              :         //       AUTHOR         B Griffith
    2362              :         //       DATE WRITTEN   Dec  2006
    2363              :         //       MODIFIED       na
    2364              :         //       RE-ENGINEERED  na
    2365              : 
    2366              :         // PURPOSE OF THIS FUNCTION:
    2367              :         // lookup function for OA inlet node
    2368              : 
    2369              :         // Return value
    2370            2 :         int GetOutdoorAirUnitZoneInletNode = 0;
    2371              : 
    2372            2 :         if (state.dataOutdoorAirUnit->GetOutdoorAirUnitInputFlag) {
    2373            1 :             OutdoorAirUnit::GetOutdoorAirUnitInputs(state);
    2374            1 :             state.dataOutdoorAirUnit->GetOutdoorAirUnitInputFlag = false;
    2375              :         }
    2376              : 
    2377            2 :         if (OAUnitNum > 0 && OAUnitNum <= state.dataOutdoorAirUnit->NumOfOAUnits) {
    2378            2 :             GetOutdoorAirUnitZoneInletNode = state.dataOutdoorAirUnit->OutAirUnit(OAUnitNum).AirOutletNode;
    2379              :         }
    2380              : 
    2381            2 :         return GetOutdoorAirUnitZoneInletNode;
    2382              :     }
    2383              : 
    2384            1 :     int GetOutdoorAirUnitReturnAirNode(EnergyPlusData &state, int const OAUnitNum)
    2385              :     {
    2386              : 
    2387              :         // FUNCTION INFORMATION:
    2388              :         //       AUTHOR         B Griffith
    2389              :         //       DATE WRITTEN   Dec  2006
    2390              :         //       MODIFIED       na
    2391              :         //       RE-ENGINEERED  na
    2392              : 
    2393              :         // PURPOSE OF THIS FUNCTION:
    2394              :         // lookup function for OA inlet node
    2395              : 
    2396              :         // Return value
    2397            1 :         int GetOutdoorAirUnitReturnAirNode = 0;
    2398              : 
    2399            1 :         if (state.dataOutdoorAirUnit->GetOutdoorAirUnitInputFlag) {
    2400            0 :             OutdoorAirUnit::GetOutdoorAirUnitInputs(state);
    2401            0 :             state.dataOutdoorAirUnit->GetOutdoorAirUnitInputFlag = false;
    2402              :         }
    2403              : 
    2404            1 :         if (OAUnitNum > 0 && OAUnitNum <= state.dataOutdoorAirUnit->NumOfOAUnits) {
    2405            1 :             GetOutdoorAirUnitReturnAirNode = state.dataOutdoorAirUnit->OutAirUnit(OAUnitNum).AirInletNode;
    2406              :         }
    2407              : 
    2408            1 :         return GetOutdoorAirUnitReturnAirNode;
    2409              :     }
    2410              : 
    2411            1 :     int getOutdoorAirUnitEqIndex(EnergyPlusData &state, std::string_view EquipName)
    2412              :     {
    2413            1 :         if (state.dataOutdoorAirUnit->GetOutdoorAirUnitInputFlag) {
    2414            0 :             OutdoorAirUnit::GetOutdoorAirUnitInputs(state);
    2415            0 :             state.dataOutdoorAirUnit->GetOutdoorAirUnitInputFlag = false;
    2416              :         }
    2417              : 
    2418            1 :         for (int OAUnitNum = 1; OAUnitNum <= state.dataOutdoorAirUnit->NumOfOAUnits; ++OAUnitNum) {
    2419            1 :             if (Util::SameString(state.dataOutdoorAirUnit->OutAirUnit(OAUnitNum).Name, EquipName)) {
    2420            1 :                 return OAUnitNum;
    2421              :             }
    2422              :         }
    2423              : 
    2424            0 :         return 0;
    2425              :     }
    2426              : 
    2427              : } // namespace OutdoorAirUnit
    2428              : 
    2429              : } // namespace EnergyPlus
        

Generated by: LCOV version 2.0-1