LCOV - code coverage report
Current view: top level - EnergyPlus - MixedAir.cc (source / functions) Coverage Total Hit
Test: lcov.output.filtered Lines: 73.0 % 2890 2111
Test Date: 2025-06-02 07:23:51 Functions: 94.6 % 56 53

            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              : #include <string>
      51              : 
      52              : // ObjexxFCL Headers
      53              : #include <ObjexxFCL/Array.functions.hh>
      54              : #include <ObjexxFCL/Fmath.hh>
      55              : 
      56              : // EnergyPlus Headers
      57              : #include <EnergyPlus/Autosizing/Base.hh>
      58              : #include <EnergyPlus/BranchNodeConnections.hh>
      59              : #include <EnergyPlus/CurveManager.hh>
      60              : #include <EnergyPlus/Data/EnergyPlusData.hh>
      61              : #include <EnergyPlus/DataContaminantBalance.hh>
      62              : #include <EnergyPlus/DataDefineEquip.hh>
      63              : #include <EnergyPlus/DataEnvironment.hh>
      64              : #include <EnergyPlus/DataHVACGlobals.hh>
      65              : #include <EnergyPlus/DataHeatBalance.hh>
      66              : #include <EnergyPlus/DataIPShortCuts.hh>
      67              : #include <EnergyPlus/DataLoopNode.hh>
      68              : #include <EnergyPlus/DataSizing.hh>
      69              : #include <EnergyPlus/DataZoneControls.hh>
      70              : #include <EnergyPlus/DataZoneEnergyDemands.hh>
      71              : #include <EnergyPlus/DataZoneEquipment.hh>
      72              : #include <EnergyPlus/DesiccantDehumidifiers.hh>
      73              : #include <EnergyPlus/EMSManager.hh>
      74              : #include <EnergyPlus/EvaporativeCoolers.hh>
      75              : #include <EnergyPlus/Fans.hh>
      76              : #include <EnergyPlus/FaultsManager.hh>
      77              : #include <EnergyPlus/General.hh>
      78              : #include <EnergyPlus/GeneralRoutines.hh>
      79              : #include <EnergyPlus/GlobalNames.hh>
      80              : #include <EnergyPlus/HVACControllers.hh>
      81              : #include <EnergyPlus/HVACDXHeatPumpSystem.hh>
      82              : #include <EnergyPlus/HVACHXAssistedCoolingCoil.hh>
      83              : #include <EnergyPlus/HVACVariableRefrigerantFlow.hh>
      84              : #include <EnergyPlus/HeatRecovery.hh>
      85              : #include <EnergyPlus/HeatingCoils.hh>
      86              : #include <EnergyPlus/Humidifiers.hh>
      87              : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
      88              : #include <EnergyPlus/MixedAir.hh>
      89              : #include <EnergyPlus/NodeInputManager.hh>
      90              : #include <EnergyPlus/OutAirNodeManager.hh>
      91              : #include <EnergyPlus/OutputProcessor.hh>
      92              : #include <EnergyPlus/OutputReportPredefined.hh>
      93              : #include <EnergyPlus/PhotovoltaicThermalCollectors.hh>
      94              : #include <EnergyPlus/Psychrometrics.hh>
      95              : #include <EnergyPlus/ScheduleManager.hh>
      96              : #include <EnergyPlus/SetPointManager.hh>
      97              : #include <EnergyPlus/SteamCoils.hh>
      98              : #include <EnergyPlus/TranspiredCollector.hh>
      99              : #include <EnergyPlus/UnitarySystem.hh>
     100              : #include <EnergyPlus/UserDefinedComponents.hh>
     101              : #include <EnergyPlus/UtilityRoutines.hh>
     102              : #include <EnergyPlus/WaterCoils.hh>
     103              : 
     104              : namespace EnergyPlus::MixedAir {
     105              : 
     106              : // Module containing the routines dealing with the mixed air portion
     107              : // of the HVAC air loop.
     108              : 
     109              : // MODULE INFORMATION:
     110              : //       AUTHOR         Fred Buhl
     111              : //       DATE WRITTEN   October 1998
     112              : //       MODIFIED       Shirey/Raustad FSEC, June/Aug 2003, Jan 2004
     113              : //                      Lawrie, March 2006 - Module order (per template)
     114              : //                      Craig Wray 22Aug2010 - Added Fan ComponentModel
     115              : //                      Chandan Sharma, FSEC, 25Aug 2011 - Added ProportionalControl
     116              : //                           to enhance CO2 based DCV control
     117              : //                      Feb 2013 Bereket Nigusse, FSEC
     118              : //                        Added DX Coil Model For 100% OA systems
     119              : //       RE-ENGINEERED  na
     120              : 
     121              : // PURPOSE OF THIS MODULE:
     122              : // To encapsulate the data and algorithms required to
     123              : // simulate the mixed air portion of the EPlus air loop.
     124              : 
     125              : // METHODOLOGY EMPLOYED:
     126              : // An algorithmic controller will be employed - there is no attempt to
     127              : // simulate real controllers for the economizer. The mixed air controller
     128              : // will sense various node conditions and set some node flow rates.  Mixed
     129              : // air components will operate with predetermined flow rates.
     130              : 
     131              : // Using/Aliasing
     132              : using namespace DataLoopNode;
     133              : using namespace DataAirLoop;
     134              : using namespace DataEnvironment;
     135              : using namespace DataSizing;
     136              : using namespace FaultsManager;
     137              : 
     138              : constexpr std::array<std::string_view, static_cast<int>(ControllerKind::Num)> ControllerKindNamesUC{"CONTROLLER:WATERCOIL", "CONTROLLER:OUTDOORAIR"};
     139              : 
     140              : constexpr std::array<std::string_view, static_cast<int>(MixedAirControllerType::Num)> MixedAirControllerTypeNames{
     141              :     "Controller:OutdoorAir", "ZoneHVAC:EnergyRecoveryVentilator:Controller"};
     142              : 
     143              : constexpr std::array<std::string_view, static_cast<int>(CMO::Num)> CurrentModuleObjects{"None",
     144              :                                                                                         "AirLoopHVAC:OutdoorAirSystem",
     145              :                                                                                         "AirLoopHVAC:OutdoorAirSystem:EquipmentList",
     146              :                                                                                         "AirLoopHVAC:ControllerList",
     147              :                                                                                         "AvailabilityManagerAssignmentList",
     148              :                                                                                         "Controller:OutdoorAir",
     149              :                                                                                         "ZoneHVAC:EnergyRecoveryVentilator:Controller",
     150              :                                                                                         "Controller:MechanicalVentilation",
     151              :                                                                                         "OutdoorAir:Mixer"};
     152              : 
     153              : constexpr std::array<std::string_view, static_cast<int>(DataSizing::SysOAMethod::Num)> SOAMNamesUC{"ZONESUM",
     154              :                                                                                                    "STANDARD62.1VENTILATIONRATEPROCEDURE",
     155              :                                                                                                    "INDOORAIRQUALITYPROCEDURE",
     156              :                                                                                                    "PROPORTIONALCONTROLBASEDONOCCUPANCYSCHEDULE",
     157              :                                                                                                    "INDOORAIRQUALITYPROCEDUREGENERICCONTAMINANT",
     158              :                                                                                                    "INDOORAIRQUALITYPROCEDURECOMBINED",
     159              :                                                                                                    "PROPORTIONALCONTROLBASEDONDESIGNOCCUPANCY",
     160              :                                                                                                    "PROPORTIONALCONTROLBASEDONDESIGNOARATE",
     161              :                                                                                                    "STANDARD62.1SIMPLIFIEDPROCEDURE",
     162              :                                                                                                    "STANDARD62.1VENTILATIONRATEPROCEDUREWITHLIMIT"};
     163              : 
     164              : constexpr std::array<std::string_view, static_cast<int>(SimAirServingZones::CompType::Num)> CompTypeNamesUC{
     165              :     "OUTDOORAIR:MIXER",
     166              :     "FAN:CONSTANTVOLUME",
     167              :     "FAN:VARIABLEVOLUME",
     168              :     "COIL:COOLING:WATER",
     169              :     "COIL:HEATING:WATER",
     170              :     "COIL:HEATING:STEAM",
     171              :     "COIL:COOLING:WATER:DETAILEDGEOMETRY",
     172              :     "COIL:HEATING:ELECTRIC",
     173              :     "COIL:HEATING:FUEL",
     174              :     "COILSYSTEM:COOLING:WATER:HEATEXCHANGERASSISTED",
     175              :     "COIL:HEATING:DESUPERHEATER",
     176              :     "COILSYSTEM:COOLING:DX",
     177              :     "HEATEXCHANGER:AIRTOAIR:FLATPLATE",
     178              :     "DEHUMIDIFIER:DESICCANT:NOFANS",
     179              :     "SOLARCOLLECTOR:UNGLAZEDTRANSPIRED",
     180              :     "EVAPORATIVECOOLER:DIRECT:CELDEKPAD",
     181              :     "AIRLOOPHVAC:UNITARY:FURNACE:HEATONLY",
     182              :     "AIRLOOPHVAC:UNITARY:FURNACE:HEATCOOL",
     183              :     "HUMIDIFIER:STEAM:ELECTRIC",
     184              :     "DUCT",
     185              :     "AIRLOOPHVAC:UNITARYHEATCOOL:VAVCHANGEOVERBYPASS",
     186              :     "AIRLOOPHVAC:UNITARYHEATPUMP:AIRTOAIR:MULTISPEED",
     187              :     "FAN:COMPONENTMODEL",
     188              :     "COILSYSTEM:HEATING:DX",
     189              :     "COIL:USERDEFINED",
     190              :     "FAN:SYSTEMMODEL",
     191              :     "AIRLOOPHVAC:UNITARYSYSTEM",
     192              :     "ZONEHVAC:TERMINALUNIT:VARIABLEREFRIGERANTFLOW",
     193              :     "SOLARCOLLECTOR:FLATPLATE:PHOTOVOLTAICTHERMAL",
     194              :     "COILSYSTEM:COOLING:WATER"};
     195              : 
     196              : static constexpr std::array<std::string_view, static_cast<int>(DataSizing::SysOAMethod::Num)> printSysOAMethod{
     197              :     "ZoneSum,",
     198              :     "Standard62.1VentilationRateProcedure,",
     199              :     "IndoorAirQualityProcedure,",
     200              :     "ProportionalControlBasedOnOccupancySchedule,",
     201              :     "IndoorAirQualityGenericContaminant,",
     202              :     "IndoorAirQualityProcedureCombined,",
     203              :     "ProportionalControlBasedOnDesignOccupancy,",
     204              :     "ProportionalControlBasedOnDesignOARate,",
     205              :     "Standard62.1SimplifiedProcedure,",
     206              :     "Standard62.1VentilationRateProcedureWithLimit,"};
     207              : 
     208          977 : Real64 OAGetFlowRate(EnergyPlusData &state, int OAPtr)
     209              : {
     210          977 :     Real64 FlowRate(0);
     211          977 :     if ((OAPtr > 0) && (OAPtr <= state.dataMixedAir->NumOAControllers) && (state.dataEnvrn->StdRhoAir != 0)) {
     212          977 :         FlowRate = state.dataMixedAir->OAController(OAPtr).OAMassFlow / state.dataEnvrn->StdRhoAir;
     213              :     }
     214          977 :     return FlowRate;
     215              : }
     216            0 : Real64 OAGetMinFlowRate(EnergyPlusData &state, int OAPtr)
     217              : {
     218            0 :     Real64 MinFlowRate(0);
     219            0 :     if ((OAPtr > 0) && (OAPtr <= state.dataMixedAir->NumOAControllers)) {
     220            0 :         MinFlowRate = state.dataMixedAir->OAController(OAPtr).MinOA;
     221              :     }
     222            0 :     return MinFlowRate;
     223              : }
     224           84 : void OASetDemandManagerVentilationState(EnergyPlusData &state, int OAPtr, bool aState)
     225              : {
     226           84 :     if ((OAPtr > 0) && (OAPtr <= state.dataMixedAir->NumOAControllers)) {
     227           84 :         state.dataMixedAir->OAController(OAPtr).ManageDemand = aState;
     228              :     }
     229           84 : }
     230           42 : void OASetDemandManagerVentilationFlow(EnergyPlusData &state, int OAPtr, Real64 aFlow)
     231              : {
     232           42 :     if ((OAPtr > 0) && (OAPtr <= state.dataMixedAir->NumOAControllers)) {
     233           42 :         state.dataMixedAir->OAController(OAPtr).DemandLimitFlowRate = aFlow * state.dataEnvrn->StdRhoAir;
     234              :     }
     235           42 : }
     236         1077 : int GetOAController(EnergyPlusData &state, std::string const &OAName)
     237              : {
     238         1077 :     int CurrentOAController(0);
     239        13271 :     for (int i = 1; i <= state.dataMixedAir->NumOAControllers; i++) {
     240        13271 :         if (OAName == state.dataMixedAir->OAController(i).Name) {
     241         1077 :             CurrentOAController = i;
     242         1077 :             break;
     243              :         }
     244              :     }
     245         1077 :     return CurrentOAController;
     246              : }
     247              : 
     248     27043260 : void ManageOutsideAirSystem(EnergyPlusData &state, std::string const &OASysName, bool const FirstHVACIteration, int const AirLoopNum, int &OASysNum)
     249              : {
     250              : 
     251              :     // SUBROUTINE INFORMATION:
     252              :     //       AUTHOR         Fred Buhl
     253              :     //       DATE WRITTEN   Oct 1998
     254              : 
     255              :     // PURPOSE OF THIS SUBROUTINE
     256              :     // Manage the outside air system
     257              : 
     258     27043260 :     if (state.dataMixedAir->GetOASysInputFlag) {
     259            0 :         GetOutsideAirSysInputs(state);
     260            0 :         state.dataMixedAir->GetOASysInputFlag = false;
     261              :     }
     262              : 
     263     27043260 :     if (OASysNum == 0) {
     264         1067 :         OASysNum = Util::FindItemInList(OASysName, state.dataAirLoop->OutsideAirSys);
     265         1067 :         if (OASysNum == 0) {
     266            0 :             ShowFatalError(state, format("ManageOutsideAirSystem: AirLoopHVAC:OutdoorAirSystem not found={}", OASysName));
     267              :         }
     268              :     }
     269              : 
     270     27043260 :     InitOutsideAirSys(state, OASysNum, AirLoopNum);
     271              : 
     272     27043260 :     SimOutsideAirSys(state, OASysNum, FirstHVACIteration, AirLoopNum);
     273     27043260 : }
     274              : 
     275     27118012 : void SimOASysComponents(EnergyPlusData &state, int const OASysNum, bool const FirstHVACIteration, int const AirLoopNum)
     276              : {
     277     27118012 :     auto &CompType = state.dataMixedAir->CompType;
     278     27118012 :     auto &CompName = state.dataMixedAir->CompName;
     279     27118012 :     bool ReSim(false);
     280     27118012 :     bool Sim(true);
     281     27118012 :     bool OAHeatCoil(false);
     282     27118012 :     bool OACoolCoil(false);
     283     27118012 :     bool OAHX(false);
     284              : 
     285     60050076 :     for (int CompNum = 1; CompNum <= state.dataAirLoop->OutsideAirSys(OASysNum).NumComponents; ++CompNum) {
     286     32932064 :         CompType = state.dataAirLoop->OutsideAirSys(OASysNum).ComponentType(CompNum);
     287     32932064 :         CompName = state.dataAirLoop->OutsideAirSys(OASysNum).ComponentName(CompNum);
     288    131728256 :         SimOAComponent(state,
     289              :                        CompType,
     290              :                        CompName,
     291     32932064 :                        state.dataAirLoop->OutsideAirSys(OASysNum).ComponentTypeEnum(CompNum),
     292              :                        FirstHVACIteration,
     293     32932064 :                        state.dataAirLoop->OutsideAirSys(OASysNum).ComponentIndex(CompNum),
     294              :                        AirLoopNum,
     295              :                        Sim,
     296              :                        OASysNum,
     297              :                        OAHeatCoil,
     298              :                        OACoolCoil,
     299              :                        OAHX);
     300     32932064 :         if (OAHX) {
     301       668052 :             ReSim = true;
     302              :         }
     303              :     }
     304              :     // if there were heat exchangers and/or desiccant wheel in the OA path, need to simulate again in reverse
     305              :     // order to propagate the air flow and conditions out the relief air path to the relief air exit node
     306     27118012 :     if (ReSim) {
     307      1275022 :         for (int CompNum = state.dataAirLoop->OutsideAirSys(OASysNum).NumComponents - 1; CompNum >= 1; --CompNum) {
     308       692864 :             CompType = state.dataAirLoop->OutsideAirSys(OASysNum).ComponentType(CompNum);
     309       692864 :             CompName = state.dataAirLoop->OutsideAirSys(OASysNum).ComponentName(CompNum);
     310      2771456 :             SimOAComponent(state,
     311              :                            CompType,
     312              :                            CompName,
     313       692864 :                            state.dataAirLoop->OutsideAirSys(OASysNum).ComponentTypeEnum(CompNum),
     314              :                            FirstHVACIteration,
     315       692864 :                            state.dataAirLoop->OutsideAirSys(OASysNum).ComponentIndex(CompNum),
     316              :                            AirLoopNum,
     317              :                            Sim,
     318              :                            OASysNum,
     319              :                            OAHeatCoil,
     320              :                            OACoolCoil,
     321              :                            OAHX);
     322              :         }
     323              :         // now simulate again propagate current temps back through OA system
     324      1857180 :         for (int CompNum = 1; CompNum <= state.dataAirLoop->OutsideAirSys(OASysNum).NumComponents; ++CompNum) {
     325      1275022 :             CompType = state.dataAirLoop->OutsideAirSys(OASysNum).ComponentType(CompNum);
     326      1275022 :             CompName = state.dataAirLoop->OutsideAirSys(OASysNum).ComponentName(CompNum);
     327      5100088 :             SimOAComponent(state,
     328              :                            CompType,
     329              :                            CompName,
     330      1275022 :                            state.dataAirLoop->OutsideAirSys(OASysNum).ComponentTypeEnum(CompNum),
     331              :                            FirstHVACIteration,
     332      1275022 :                            state.dataAirLoop->OutsideAirSys(OASysNum).ComponentIndex(CompNum),
     333              :                            AirLoopNum,
     334              :                            Sim,
     335              :                            OASysNum,
     336              :                            OAHeatCoil,
     337              :                            OACoolCoil,
     338              :                            OAHX);
     339              :         }
     340              :     }
     341     27118012 : }
     342              : 
     343     27043260 : void SimOutsideAirSys(EnergyPlusData &state, int const OASysNum, bool const FirstHVACIteration, int const AirLoopNum)
     344              : {
     345              : 
     346              :     // SUBROUTINE INFORMATION:
     347              :     //       AUTHOR         Fred Buhl
     348              :     //       DATE WRITTEN   Oct 1998
     349              : 
     350              :     // PURPOSE OF THIS SUBROUTINE
     351              :     // Simulate the controllers and components in the outside air system.
     352              : 
     353              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     354     27043260 :     state.dataSize->CurOASysNum = OASysNum;
     355     27043260 :     auto &CurrentOASystem(state.dataAirLoop->OutsideAirSys(OASysNum));
     356     27043260 :     if (state.dataAirLoop->OutsideAirSys(OASysNum).AirLoopDOASNum == -1) {
     357     27032378 :         SimOAController(state, CurrentOASystem.OAControllerName, CurrentOASystem.OAControllerIndex, FirstHVACIteration, AirLoopNum);
     358              :     }
     359     27043260 :     SimOASysComponents(state, OASysNum, FirstHVACIteration, AirLoopNum);
     360              : 
     361     27043260 :     if (state.dataMixedAir->MyOneTimeErrorFlag(OASysNum)) {
     362         1068 :         bool FatalErrorFlag(false);
     363         1068 :         if (CurrentOASystem.NumControllers - CurrentOASystem.NumSimpleControllers > 1) {
     364            0 :             ShowWarningError(
     365              :                 state,
     366            0 :                 format("AirLoopHVAC:OutdoorAirSystem {} has more than 1 outside air controller; only the 1st will be used", CurrentOASystem.Name));
     367              :         }
     368         2273 :         for (int CompNum = 1; CompNum <= CurrentOASystem.NumComponents; ++CompNum) {
     369         1205 :             auto &CompType = CurrentOASystem.ComponentType(CompNum);
     370         1205 :             auto &CompName = CurrentOASystem.ComponentName(CompNum);
     371         1205 :             if (Util::SameString(CompType, "OutdoorAir:Mixer")) {
     372         1067 :                 int OAMixerNum = Util::FindItemInList(CompName, state.dataMixedAir->OAMixer);
     373         1067 :                 int OAControllerNum = CurrentOASystem.OAControllerIndex;
     374         1067 :                 if (state.dataMixedAir->OAController(OAControllerNum).MixNode != state.dataMixedAir->OAMixer(OAMixerNum).MixNode) {
     375            0 :                     ShowSevereError(
     376            0 :                         state, format("The mixed air node of Controller:OutdoorAir=\"{}\"", state.dataMixedAir->OAController(OAControllerNum).Name));
     377            0 :                     ShowContinueError(state,
     378            0 :                                       format("should be the same node as the mixed air node of OutdoorAir:Mixer=\"{}\".",
     379            0 :                                              state.dataMixedAir->OAMixer(OAMixerNum).Name));
     380            0 :                     ShowContinueError(state,
     381            0 :                                       format("Controller:OutdoorAir mixed air node=\"{}\".",
     382            0 :                                              state.dataLoopNodes->NodeID(state.dataMixedAir->OAController(OAControllerNum).MixNode)));
     383            0 :                     ShowContinueError(state,
     384            0 :                                       format("OutdoorAir:Mixer mixed air node=\"{}\".",
     385            0 :                                              state.dataLoopNodes->NodeID(state.dataMixedAir->OAMixer(OAMixerNum).MixNode)));
     386            0 :                     FatalErrorFlag = true;
     387              :                 }
     388         1067 :                 if (state.dataMixedAir->OAController(OAControllerNum).RelNode != state.dataMixedAir->OAMixer(OAMixerNum).RelNode) {
     389            0 :                     ShowSevereError(
     390            0 :                         state, format("The relief air node of Controller:OutdoorAir=\"{}\"", state.dataMixedAir->OAController(OAControllerNum).Name));
     391            0 :                     ShowContinueError(state,
     392            0 :                                       format("should be the same node as the relief air node of OutdoorAir:Mixer=\"{}\".",
     393            0 :                                              state.dataMixedAir->OAMixer(OAMixerNum).Name));
     394            0 :                     ShowContinueError(state,
     395            0 :                                       format("Controller:OutdoorAir relief air node=\"{}\".",
     396            0 :                                              state.dataLoopNodes->NodeID(state.dataMixedAir->OAController(OAControllerNum).RelNode)));
     397            0 :                     ShowContinueError(state,
     398            0 :                                       format("OutdoorAir:Mixer relief air node=\"{}\".",
     399            0 :                                              state.dataLoopNodes->NodeID(state.dataMixedAir->OAMixer(OAMixerNum).RelNode)));
     400            0 :                     FatalErrorFlag = true;
     401              :                 }
     402         1067 :                 if (state.dataMixedAir->OAController(OAControllerNum).RetNode != state.dataMixedAir->OAMixer(OAMixerNum).RetNode) {
     403            0 :                     ShowSevereError(
     404            0 :                         state, format("The return air node of Controller:OutdoorAir=\"{}\"", state.dataMixedAir->OAController(OAControllerNum).Name));
     405            0 :                     ShowContinueError(state,
     406            0 :                                       format("should be the same node as the return air node of OutdoorAir:Mixer=\"{}\".",
     407            0 :                                              state.dataMixedAir->OAMixer(OAMixerNum).Name));
     408            0 :                     ShowContinueError(state,
     409            0 :                                       format("Controller:OutdoorAir return air node=\"{}\".",
     410            0 :                                              state.dataLoopNodes->NodeID(state.dataMixedAir->OAController(OAControllerNum).RetNode)));
     411            0 :                     ShowContinueError(state,
     412            0 :                                       format("OutdoorAir:Mixer return air node=\"{}\".",
     413            0 :                                              state.dataLoopNodes->NodeID(state.dataMixedAir->OAMixer(OAMixerNum).RetNode)));
     414            0 :                     FatalErrorFlag = true;
     415              :                 }
     416              :             }
     417              :         }
     418         1068 :         state.dataMixedAir->MyOneTimeErrorFlag(OASysNum) = false;
     419         1068 :         if (FatalErrorFlag) {
     420            0 :             ShowFatalError(state, "Previous severe error(s) cause program termination");
     421              :         }
     422              :     }
     423              : 
     424     27043260 :     state.dataSize->CurOASysNum = 0;
     425     27043260 :     if (state.dataAirLoop->OutsideAirSys(OASysNum).AirLoopDOASNum == -1) {
     426     27032378 :         state.dataAirLoop->AirLoopControlInfo(AirLoopNum).OASysComponentsSimulated = true;
     427              :     }
     428     27043260 : }
     429              : 
     430     34902364 : void SimOAComponent(EnergyPlusData &state,
     431              :                     std::string const &CompType,                    // the component type
     432              :                     std::string const &CompName,                    // the component Name
     433              :                     SimAirServingZones::CompType const CompTypeNum, // Component Type -- Integerized for this module
     434              :                     bool const FirstHVACIteration,
     435              :                     int &CompIndex,
     436              :                     int const AirLoopNum, // air loop index for economizer lockout coordination
     437              :                     bool const Sim,       // if TRUE, simulate component; if FALSE, just set the coil existence flags
     438              :                     int const OASysNum,   // index to outside air system
     439              :                     bool &OAHeatingCoil,  // TRUE indicates a heating coil has been found
     440              :                     bool &OACoolingCoil,  // TRUE indicates a cooling coil has been found
     441              :                     bool &OAHX)           // TRUE indicates a heat exchanger has been found
     442              : {
     443              : 
     444              :     // SUBROUTINE INFORMATION
     445              :     //             AUTHOR:  Russ Taylor, Dan Fisher, Fred Buhl
     446              :     //       DATE WRITTEN:  Oct 1997
     447              :     //           MODIFIED:  Dec 1997 Fred Buhl, D Shirey Feb/Sept 2003
     448              :     //                      Nov 2004 M. J. Witte, GARD Analytics, Inc.
     449              :     //                        Add DXSystem:AirLoop as valid OA system equipment
     450              :     //                        Work supported by ASHRAE research project 1254-RP
     451              : 
     452              :     // PURPOSE OF THIS SUBROUTINE:
     453              :     // Calls the individual air loop component simulation routines
     454              : 
     455              :     // SUBROUTINE LOCAL VARIABLE DEFINITIONS
     456     34902364 :     OAHeatingCoil = false;
     457     34902364 :     OACoolingCoil = false;
     458     34902364 :     OAHX = false;
     459              :     HVAC::FanOp fanOp;
     460     34902364 :     Real64 sensOut = 0.0;
     461     34902364 :     int constexpr zoneOAUnitNum = -1;
     462     34902364 :     Real64 constexpr OAUCoilOutTemp = 0.0;
     463     34902364 :     bool constexpr ZoneEquipFlag = false;
     464     34902364 :     bool HeatingActive = false; // why isn't this returning that a coil is active?
     465     34902364 :     bool CoolingActive = false;
     466              : 
     467     34902364 :     switch (CompTypeNum) {
     468     27691432 :     case SimAirServingZones::CompType::OAMixer_Num: { // OutdoorAir:Mixer
     469     27691432 :         if (Sim) {
     470     27689288 :             SimOAMixer(state, CompName, CompIndex);
     471              :         }
     472     27691432 :         break;
     473              :     }
     474        46356 :     case SimAirServingZones::CompType::Fan_Simple_CV:        // Fan:ConstantVolume
     475              :     case SimAirServingZones::CompType::Fan_Simple_VAV:       // Fan:VariableVolume
     476              :     case SimAirServingZones::CompType::Fan_System_Object:    // Fan:SystemModel
     477              :     case SimAirServingZones::CompType::Fan_ComponentModel: { // Fan:ComponentModel
     478        46356 :         if (Sim) {
     479        46352 :             if (CompIndex == 0) { // TODO: get rid of this stuff
     480            2 :                 CompIndex = Fans::GetFanIndex(state, CompName);
     481            2 :                 assert(CompIndex > 0);
     482              :             }
     483              : 
     484        46352 :             state.dataFans->fans(CompIndex)->simulate(state, FirstHVACIteration);
     485              :         }
     486        46356 :     } break;
     487      1316240 :     case SimAirServingZones::CompType::WaterCoil_Cooling: { // Coil:Cooling:Water
     488      1316240 :         if (Sim) {
     489              :             // get water coil and controller data if not called previously
     490      1316182 :             if (CompIndex == 0) {
     491           30 :                 WaterCoils::SimulateWaterCoilComponents(state, CompName, FirstHVACIteration, CompIndex);
     492              :             }
     493              :             // iterate on OA sys controller and water coil at the same time
     494      1316182 :             if (!state.dataWaterCoils->WaterCoil(CompIndex).heatRecoveryCoil) {
     495      2600684 :                 SimAirServingZones::SolveWaterCoilController(state,
     496              :                                                              FirstHVACIteration,
     497              :                                                              AirLoopNum,
     498              :                                                              CompName,
     499              :                                                              CompIndex,
     500      1300342 :                                                              state.dataWaterCoils->WaterCoil(CompIndex).ControllerName,
     501      1300342 :                                                              state.dataWaterCoils->WaterCoil(CompIndex).ControllerIndex,
     502              :                                                              false);
     503              :                 // set flag to tell HVAC controller it will be simulated only in SolveWaterCoilController()
     504      1300342 :                 state.dataHVACControllers->ControllerProps(state.dataWaterCoils->WaterCoil(CompIndex).ControllerIndex).BypassControllerCalc = true;
     505              :             } else {
     506        15840 :                 WaterCoils::SimulateWaterCoilComponents(state, CompName, FirstHVACIteration, CompIndex);
     507              :             }
     508              :         } else {
     509              :             // This is not working as intended ... don't want to include the HR coil in sizing.
     510              :             // But if the water coil is called to get this index, then the controller is called to set the
     511              :             // controller index and the simulation sizes the controller before the cooling coil.
     512              :             // Pushing this aspect forward to a follow up issue where the
     513              :             // controller index call is moved out of water coils getInput.
     514              :             // if (CompIndex == 0) {
     515              :             //    bool errFound = false;
     516              :             //    CompIndex = WaterCoils::GetWaterCoilIndex(state, CompType, CompName, errFound);
     517              :             //    if (errFound) ShowFatalError(state, "SimOAComponent: Program terminates for preceding reason.");
     518              :             // }
     519              :             // if (!state.dataWaterCoils->WaterCoil(CompIndex).heatRecoveryCoil) OACoolingCoil = true;
     520              :             // should not include heat recovery coils in sizing since heat transfer at peak cooling is minimal.
     521           58 :             OACoolingCoil = true;
     522              :         }
     523      1316240 :     } break;
     524      1327114 :     case SimAirServingZones::CompType::WaterCoil_SimpleHeat: { // Coil:Heating:Water
     525      1327114 :         if (Sim) {
     526              :             // get water coil and controller data if not called previously
     527      1327054 :             if (CompIndex == 0) {
     528           31 :                 WaterCoils::SimulateWaterCoilComponents(state, CompName, FirstHVACIteration, CompIndex);
     529              :             }
     530              :             // iterate on OA sys controller and water coil at the same time
     531      2654108 :             SimAirServingZones::SolveWaterCoilController(state,
     532              :                                                          FirstHVACIteration,
     533              :                                                          AirLoopNum,
     534              :                                                          CompName,
     535              :                                                          CompIndex,
     536      1327054 :                                                          state.dataWaterCoils->WaterCoil(CompIndex).ControllerName,
     537      1327054 :                                                          state.dataWaterCoils->WaterCoil(CompIndex).ControllerIndex,
     538              :                                                          false);
     539              :             // set flag to tell HVAC controller it will be simulated only in SolveWaterCoilController()
     540      1327054 :             state.dataHVACControllers->ControllerProps(state.dataWaterCoils->WaterCoil(CompIndex).ControllerIndex).BypassControllerCalc = true;
     541              :         }
     542      1327114 :         OAHeatingCoil = true;
     543      1327114 :     } break;
     544            0 :     case SimAirServingZones::CompType::SteamCoil_AirHeat: { // Coil:Heating:Steam
     545            0 :         if (Sim) {
     546            0 :             SteamCoils::SimulateSteamCoilComponents(state, CompName, FirstHVACIteration, CompIndex, 0.0);
     547              :         }
     548            0 :         OAHeatingCoil = true;
     549            0 :     } break;
     550            0 :     case SimAirServingZones::CompType::WaterCoil_DetailedCool: { // Coil:Cooling:Water:DetailedGeometry
     551            0 :         if (Sim) {
     552              :             // get water coil and controller data if not called previously
     553            0 :             if (CompIndex == 0) {
     554            0 :                 WaterCoils::SimulateWaterCoilComponents(state, CompName, FirstHVACIteration, CompIndex);
     555              :             }
     556              :             // iterate on OA sys controller and water coil at the same time
     557            0 :             SimAirServingZones::SolveWaterCoilController(state,
     558              :                                                          FirstHVACIteration,
     559              :                                                          AirLoopNum,
     560              :                                                          CompName,
     561              :                                                          CompIndex,
     562            0 :                                                          state.dataWaterCoils->WaterCoil(CompIndex).ControllerName,
     563            0 :                                                          state.dataWaterCoils->WaterCoil(CompIndex).ControllerIndex,
     564              :                                                          false);
     565              :             // set flag to tell HVAC controller it will be simulated only in SolveWaterCoilController()
     566            0 :             state.dataHVACControllers->ControllerProps(state.dataWaterCoils->WaterCoil(CompIndex).ControllerIndex).BypassControllerCalc = true;
     567              :         }
     568            0 :         OACoolingCoil = true;
     569            0 :     } break;
     570        26588 :     case SimAirServingZones::CompType::Coil_ElectricHeat: // Coil:Heating:Electric
     571              :     case SimAirServingZones::CompType::Coil_GasHeat: {    // Coil:Heating:Fuel
     572        26588 :         if (Sim) {
     573              :             //     stand-alone coils are temperature controlled (do not pass QCoilReq in argument list, QCoilReq overrides temp SP)
     574        26586 :             HeatingCoils::SimulateHeatingCoilComponents(state, CompName, FirstHVACIteration, _, CompIndex);
     575              :         }
     576        26588 :         OAHeatingCoil = true;
     577        26588 :     } break;
     578            0 :     case SimAirServingZones::CompType::WaterCoil_CoolingHXAsst: { // CoilSystem:Cooling:Water:HeatExchangerAssisted
     579            0 :         if (Sim) {
     580              :             // get water coil and controller data if not called previously
     581            0 :             if (CompIndex == 0) {
     582            0 :                 HVACHXAssistedCoolingCoil::SimHXAssistedCoolingCoil(
     583              :                     state, CompName, FirstHVACIteration, HVAC::CompressorOp::On, 0.0, CompIndex, HVAC::FanOp::Continuous);
     584              :             }
     585              :             // iterate on OA sys controller and water coil at the same time
     586            0 :             SimAirServingZones::SolveWaterCoilController(state,
     587              :                                                          FirstHVACIteration,
     588              :                                                          AirLoopNum,
     589              :                                                          CompName,
     590              :                                                          CompIndex,
     591            0 :                                                          state.dataHVACAssistedCC->HXAssistedCoil(CompIndex).ControllerName,
     592            0 :                                                          state.dataHVACAssistedCC->HXAssistedCoil(CompIndex).ControllerIndex,
     593              :                                                          true);
     594              :             // set flag to tell HVAC controller it will be simulated only in SolveWaterCoilController()
     595            0 :             state.dataHVACControllers->ControllerProps(state.dataHVACAssistedCC->HXAssistedCoil(CompIndex).ControllerIndex).BypassControllerCalc =
     596              :                 true;
     597              :         }
     598            0 :         OACoolingCoil = true;
     599            0 :     } break;
     600        19512 :     case SimAirServingZones::CompType::DXSystem:             // CoilSystem:Cooling:DX
     601              :     case SimAirServingZones::CompType::CoilSystemWater:      // CoilSystem:Cooling:Water
     602              :     case SimAirServingZones::CompType::UnitarySystemModel: { // AirloopHVAC:UnitarySystem
     603        19512 :         if (Sim) {
     604        19508 :             Real64 latOut = 0.0;     // does the air loop not need to know what the latent capacity is?
     605        19508 :             int compNum = CompIndex; // use local so return value of compNum from simulate call does not overwrite CompIndex
     606        19508 :             state.dataAirLoop->OutsideAirSys(OASysNum).compPointer[compNum]->simulate(state,
     607              :                                                                                       CompName,
     608              :                                                                                       FirstHVACIteration,
     609              :                                                                                       AirLoopNum,
     610              :                                                                                       compNum,
     611              :                                                                                       HeatingActive,
     612              :                                                                                       CoolingActive,
     613              :                                                                                       zoneOAUnitNum,
     614              :                                                                                       OAUCoilOutTemp,
     615              :                                                                                       ZoneEquipFlag,
     616              :                                                                                       sensOut,
     617              :                                                                                       latOut);
     618              :         }
     619        19512 :         if (state.dataMixedAir->MyOneTimeCheckUnitarySysFlag(OASysNum) && CompTypeNum == SimAirServingZones::CompType::UnitarySystemModel) {
     620            0 :             UnitarySystems::UnitarySys::getUnitarySysHeatCoolCoil(state, CompName, OACoolingCoil, OAHeatingCoil, 0);
     621            0 :             UnitarySystems::UnitarySys::checkUnitarySysCoilInOASysExists(state, CompName, 0);
     622            0 :             if (Sim) {
     623            0 :                 state.dataMixedAir->MyOneTimeCheckUnitarySysFlag(OASysNum) = false;
     624              :             }
     625              :         } else {
     626        19512 :             OACoolingCoil = true;
     627              :         }
     628        19512 :     } break;
     629            0 :     case SimAirServingZones::CompType::DXHeatPumpSystem: { // CoilSystem:IntegratedHeatPump:AirSource
     630            0 :         if (Sim) {
     631            0 :             HVACDXHeatPumpSystem::SimDXHeatPumpSystem(state, CompName, FirstHVACIteration, AirLoopNum, CompIndex);
     632              :         }
     633            0 :         OAHeatingCoil = true;
     634            0 :     } break;
     635        26716 :     case SimAirServingZones::CompType::CoilUserDefined: { // Coil:UserDefined
     636        26716 :         if (Sim) {
     637        26712 :             UserDefinedComponents::SimCoilUserDefined(state, CompName, CompIndex, AirLoopNum, OAHeatingCoil, OACoolingCoil);
     638              :         }
     639        26716 :     } break;
     640      1746532 :     case SimAirServingZones::CompType::HeatXchngr: {
     641              :         // HeatExchanger:AirToAir:FlatPlate, HeatExchanger:AirToAir:SensibleAndLatent, HeatExchanger:Desiccant:BalancedFlow
     642      1746532 :         if (Sim) {
     643      1746474 :             Real64 AirloopPLR = 1;
     644      1746474 :             if (state.dataAirLoop->OutsideAirSys(OASysNum).AirLoopDOASNum > -1) {
     645            0 :                 fanOp = HVAC::FanOp::Continuous;
     646              :             } else {
     647      1746474 :                 if (state.dataAirLoop->AirLoopControlInfo(AirLoopNum).fanOp == HVAC::FanOp::Cycling) {
     648            0 :                     fanOp = HVAC::FanOp::Cycling;
     649              :                 } else {
     650      1746474 :                     fanOp = HVAC::FanOp::Continuous;
     651              :                 }
     652              : 
     653      1746474 :                 if (fanOp == HVAC::FanOp::Cycling) {
     654              :                     // HX's in the OA system can be troublesome given that the OA flow rate is not necessarily proportional to air loop PLR
     655              :                     // adding that user input for branch flow rate, HX nominal flow rate, OA system min/max flow rate will not necessarily be
     656              :                     // perfectly input, a compromise is used for OA sys HX's as the ratio of flow to max. Issue #4298.
     657              :                     //                    AirloopPLR = AirLoopFlow( AirLoopNum ).FanPLR;
     658            0 :                     AirloopPLR = state.dataMixedAir->OAController(OASysNum).OAMassFlow / state.dataMixedAir->OAController(OASysNum).MaxOAMassFlowRate;
     659              :                 }
     660              :             }
     661      1746474 :             if (state.dataAirLoop->OutsideAirSys(OASysNum).AirLoopDOASNum > -1) {
     662            0 :                 HeatRecovery::SimHeatRecovery(state, CompName, FirstHVACIteration, CompIndex, fanOp, AirloopPLR, _, _, _, _, _);
     663              :             } else {
     664      3492948 :                 HeatRecovery::SimHeatRecovery(state,
     665              :                                               CompName,
     666              :                                               FirstHVACIteration,
     667              :                                               CompIndex,
     668              :                                               fanOp,
     669              :                                               AirloopPLR,
     670              :                                               _,
     671              :                                               _,
     672              :                                               _,
     673      1746474 :                                               state.dataAirLoop->AirLoopControlInfo(AirLoopNum).HeatRecoveryBypass,
     674      1746474 :                                               state.dataAirLoop->AirLoopControlInfo(AirLoopNum).HighHumCtrlActive);
     675              :             }
     676              :         }
     677      1746532 :         OAHX = true;
     678      1746532 :     } break;
     679       257692 :     case SimAirServingZones::CompType::Desiccant: { // Dehumidifier:Desiccant:NoFans,  Dehumidifier:Desiccant:NoFans, Dehumidifier:Desiccant:System
     680       257692 :         if (Sim) {
     681       257682 :             DesiccantDehumidifiers::SimDesiccantDehumidifier(state, CompName, FirstHVACIteration, CompIndex);
     682              :         }
     683       257692 :         OAHX = true;
     684       257692 :     } break;
     685        47852 :     case SimAirServingZones::CompType::Humidifier: { // Humidifier:Steam:Electric Humidifier:Steam:Gas
     686        47852 :         if (Sim) {
     687        47850 :             Humidifiers::SimHumidifier(state, CompName, FirstHVACIteration, CompIndex);
     688              :         }
     689        47852 :     } break;
     690        41455 :     case SimAirServingZones::CompType::Unglazed_SolarCollector: { // SolarCollector:UnglazedTranspired
     691        41455 :         if (Sim) {
     692        41437 :             TranspiredCollector::SimTranspiredCollector(state, CompName, CompIndex);
     693              :         }
     694        41455 :     } break;
     695        93252 :     case SimAirServingZones::CompType::PVT_AirBased: { // SolarCollector:FlatPlate:PhotovoltaicThermal
     696        93252 :         if (Sim) {
     697        93232 :             if (CompIndex == 0) {
     698           10 :                 CompIndex = PhotovoltaicThermalCollectors::getPVTindexFromName(state, CompName);
     699              :             }
     700        93232 :             PhotovoltaicThermalCollectors::simPVTfromOASys(state, CompIndex, FirstHVACIteration);
     701              :         }
     702        93252 :     } break;
     703      2258433 :     case SimAirServingZones::CompType::EvapCooler: { // EvaporativeCooler:Direct:CelDekPad, EvaporativeCooler:Indirect:CelDekPad
     704              :         // EvaporativeCooler:Indirect:WetCoil, EvaporativeCooler:Indirect:ResearchSpecial
     705      2258433 :         if (Sim) {
     706      2258405 :             EvaporativeCoolers::SimEvapCooler(state, CompName, CompIndex);
     707              :         }
     708      2258433 :     } break;
     709         3190 :     case SimAirServingZones::CompType::ZoneVRFasAirLoopEquip: { // ZoneHVAC:TerminalUnit:VariableRefrigerantFlow
     710         3190 :         if (Sim) {
     711         3188 :             int ControlledZoneNum = 0;
     712         3188 :             int constexpr OAUnitNum = 0;
     713         3188 :             Real64 constexpr OAUCoilOutTemp = 0.0;
     714         3188 :             bool constexpr ZoneEquipment = false;
     715         3188 :             Real64 sysOut = 0.0;
     716         3188 :             Real64 latOut = 0.0;
     717         3188 :             HVACVariableRefrigerantFlow::SimulateVRF(state,
     718              :                                                      CompName,
     719              :                                                      FirstHVACIteration,
     720              :                                                      ControlledZoneNum,
     721              :                                                      CompIndex,
     722              :                                                      HeatingActive,
     723              :                                                      CoolingActive,
     724              :                                                      OAUnitNum,
     725              :                                                      OAUCoilOutTemp,
     726              :                                                      ZoneEquipment,
     727              :                                                      sysOut,
     728              :                                                      latOut);
     729              :         } else {
     730            2 :             HVACVariableRefrigerantFlow::isVRFCoilPresent(state, CompName, OACoolingCoil, OAHeatingCoil);
     731              :         }
     732         3190 :     } break;
     733            0 :     default:
     734            0 :         ShowFatalError(state, format("Invalid Outside Air Component={}", CompType));
     735              :     }
     736     34902364 : }
     737              : 
     738     60004604 : void SimOAMixer(EnergyPlusData &state, std::string const &CompName, int &CompIndex)
     739              : {
     740              : 
     741              :     // SUBROUTINE INFORMATION:
     742              :     //       AUTHOR         Fred Buhl
     743              :     //       DATE WRITTEN   Oct 1998
     744              : 
     745              :     // PURPOSE OF THIS SUBROUTINE
     746              :     // Simulate an Outside Air Mixer component
     747              : 
     748              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     749              :     int OAMixerNum;
     750              : 
     751     60004604 :     if (state.dataMixedAir->GetOAMixerInputFlag) {
     752            0 :         GetOAMixerInputs(state);
     753            0 :         state.dataMixedAir->GetOAMixerInputFlag = false;
     754              :     }
     755              : 
     756     60004604 :     if (CompIndex == 0) {
     757         1214 :         OAMixerNum = Util::FindItemInList(CompName, state.dataMixedAir->OAMixer);
     758         1214 :         CompIndex = OAMixerNum;
     759         1214 :         if (OAMixerNum == 0) {
     760            0 :             ShowFatalError(state, format("SimOAMixer: OutdoorAir:Mixer not found={}", CompName));
     761              :         }
     762              :     } else {
     763     60003390 :         OAMixerNum = CompIndex;
     764              :     }
     765              : 
     766     60004604 :     auto &mixer = state.dataMixedAir->OAMixer(OAMixerNum);
     767              : 
     768     60004604 :     mixer.InitOAMixer(state);
     769              : 
     770     60004604 :     mixer.CalcOAMixer(state);
     771              : 
     772     60004604 :     mixer.UpdateOAMixer(state);
     773     60004604 : }
     774              : 
     775     27596359 : void SimOAController(EnergyPlusData &state, std::string const &CtrlName, int &CtrlIndex, bool const FirstHVACIteration, int const AirLoopNum)
     776              : {
     777              : 
     778              :     // SUBROUTINE INFORMATION:
     779              :     //       AUTHOR         Fred Buhl
     780              :     //       DATE WRITTEN   Oct 1998
     781              : 
     782              :     // PURPOSE OF THIS SUBROUTINE
     783              :     // Simulate an Outside Air Controller component
     784              : 
     785              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     786              :     int OAControllerNum;
     787              : 
     788     27596359 :     if ((state.dataMixedAir->GetOAControllerInputFlag) &&
     789              :         (AirLoopNum > 0)) { // Gets input for object  first time Sim routine is called from an airloop
     790          413 :         GetOAControllerInputs(state);
     791          413 :         state.dataMixedAir->GetOAControllerInputFlag = false;
     792              :     }
     793              : 
     794              :     // check that the economizer staging operation EconomizerFirst is only used with an sensible load-based controlled AirLoopHVAC:UnitarySystem
     795     27596359 :     if (AirLoopNum > 0) {
     796     27032378 :         auto &primaryAirSystems = state.dataAirSystemsData->PrimaryAirSystems(AirLoopNum);
     797     27032378 :         if (primaryAirSystems.EconomizerStagingCheckFlag == false) {
     798         1067 :             OAControllerNum = Util::FindItemInList(CtrlName, state.dataMixedAir->OAController);
     799         1067 :             if (state.dataMixedAir->OAController(OAControllerNum).EconomizerStagingType == HVAC::EconomizerStagingType::EconomizerFirst) {
     800            4 :                 bool sensLoadCtrlUnitarySystemFound = false;
     801            8 :                 for (int BranchNum = 1; BranchNum <= primaryAirSystems.NumBranches; ++BranchNum) {
     802            8 :                     for (int CompNum = 1; CompNum <= primaryAirSystems.Branch(BranchNum).TotalComponents; ++CompNum) {
     803            8 :                         if (primaryAirSystems.Branch(BranchNum).Comp(CompNum).CompType_Num == SimAirServingZones::CompType::UnitarySystemModel) {
     804            4 :                             std::string_view unitarySystemName = primaryAirSystems.Branch(BranchNum).Comp(CompNum).Name;
     805            8 :                             int unitarySystemNum = Util::FindItemInList(
     806            4 :                                 unitarySystemName, state.dataUnitarySystems->unitarySys, state.dataUnitarySystems->numUnitarySystems);
     807            4 :                             if (state.dataUnitarySystems->unitarySys[unitarySystemNum - 1].m_ControlType ==
     808              :                                 UnitarySystems::UnitarySys::UnitarySysCtrlType::Load) {
     809            4 :                                 if (state.dataUnitarySystems->unitarySys[unitarySystemNum - 1].m_CoolingCoilType_Num ==
     810            3 :                                         HVAC::CoilDX_MultiSpeedCooling ||
     811            3 :                                     state.dataUnitarySystems->unitarySys[unitarySystemNum - 1].m_CoolingCoilType_Num ==
     812            7 :                                         HVAC::Coil_CoolingAirToAirVariableSpeed ||
     813            2 :                                     state.dataUnitarySystems->unitarySys[unitarySystemNum - 1].m_CoolingCoilType_Num == HVAC::CoilDX_Cooling) {
     814            4 :                                     sensLoadCtrlUnitarySystemFound = true;
     815            4 :                                     break;
     816              :                                 }
     817              :                             }
     818              :                         }
     819              :                     }
     820              :                 }
     821            4 :                 if (!sensLoadCtrlUnitarySystemFound) {
     822            0 :                     ShowWarningError(
     823              :                         state,
     824            0 :                         format(
     825              :                             "SimOAController: EconomizerFirst was selected in the \"{}\" Controller:OutdoorAir object but the air loop it belongs to "
     826              :                             "does not include an AirLoopHVAC:UnitarySystem with a \"Load\" Control Type input and cooling coil of one of the "
     827              :                             "following types: Coil:Cooling:DX:MultiSpeed,"
     828              :                             " Coil:Cooling:DX:VariableSpeed, or Coil:Cooling:DX. EconomizerFirst will not be enforced.",
     829            0 :                             state.dataMixedAir->OAController(OAControllerNum).Name));
     830              :                 }
     831              :             }
     832         1067 :             primaryAirSystems.EconomizerStagingCheckFlag = true;
     833              :         }
     834              :     }
     835              : 
     836     27596359 :     if (CtrlIndex == 0) {
     837         1067 :         if (state.dataMixedAir->NumOAControllers > 0) {
     838         1067 :             OAControllerNum = Util::FindItemInList(CtrlName, state.dataMixedAir->OAController);
     839              :         } else {
     840            0 :             OAControllerNum = 0;
     841              :         }
     842         1067 :         CtrlIndex = OAControllerNum;
     843         1067 :         if (OAControllerNum == 0) {
     844            0 :             ShowFatalError(state, format("SimOAController: Outside Air Controller not found={}", CtrlName));
     845              :         }
     846              :     } else {
     847     27595292 :         OAControllerNum = CtrlIndex;
     848              :     }
     849              : 
     850     27596359 :     InitOAController(state, OAControllerNum, FirstHVACIteration, AirLoopNum);
     851              : 
     852     27596359 :     state.dataMixedAir->OAController(OAControllerNum).CalcOAController(state, AirLoopNum, FirstHVACIteration);
     853     27596359 :     state.dataMixedAir->OAController(OAControllerNum).UpdateOAController(state);
     854     27596359 : }
     855              : 
     856              : // Get Input Section of the Module
     857              : //******************************************************************************
     858              : 
     859          801 : void GetOutsideAirSysInputs(EnergyPlusData &state)
     860              : {
     861              : 
     862              :     // SUBROUTINE INFORMATION:
     863              :     //       AUTHOR         Fred Buhl
     864              :     //       DATE WRITTEN   Oct 1998
     865              : 
     866              :     // PURPOSE OF THIS SUBROUTINE
     867              :     // Input the Outside Air System data and store it in the OutsideAirSys array.
     868              : 
     869              :     // METHODOLOGY EMPLOYED:
     870              :     // Use the Get routines from the InputProcessor module.
     871              : 
     872              :     // SUBROUTINE PARAMETER DEFINITIONS:
     873              :     static constexpr std::string_view RoutineName("GetOutsideAirSysInputs: "); // include trailing blank space
     874              : 
     875              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     876          801 :     bool ErrorsFound(false);
     877              :     int NumNums;      // Number of real numbers returned by GetObjectItem
     878              :     int NumAlphas;    // Number of alphanumerics returned by GetObjectItem
     879          801 :     int TotalArgs(0); // Total number of alpha and numeric arguments (max) for a
     880              :     int IOStat;
     881          801 :     Array1D<Real64> NumArray;
     882          801 :     Array1D_string AlphArray;
     883          801 :     Array1D_string cAlphaFields;   // Alpha field names
     884          801 :     Array1D_string cNumericFields; // Numeric field names
     885          801 :     Array1D_bool lAlphaBlanks;     // Logical array, alpha field input BLANK = .TRUE.
     886          801 :     Array1D_bool lNumericBlanks;   // Logical array, numeric field input BLANK = .TRUE.
     887              : 
     888          801 :     if (!state.dataMixedAir->GetOASysInputFlag) {
     889            0 :         return;
     890              :     }
     891              : 
     892         1602 :     state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(
     893          801 :         state, CurrentModuleObjects[static_cast<int>(CMO::OASystem)], TotalArgs, NumAlphas, NumNums);
     894          801 :     int MaxNums = NumNums;
     895          801 :     int MaxAlphas = NumAlphas;
     896         1602 :     state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(
     897          801 :         state, CurrentModuleObjects[static_cast<int>(CMO::AirLoopEqList)], TotalArgs, NumAlphas, NumNums);
     898          801 :     MaxNums = max(MaxNums, NumNums);
     899          801 :     MaxAlphas = max(MaxAlphas, NumAlphas);
     900         1602 :     state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(
     901          801 :         state, CurrentModuleObjects[static_cast<int>(CMO::ControllerList)], TotalArgs, NumAlphas, NumNums);
     902          801 :     MaxNums = max(MaxNums, NumNums);
     903          801 :     MaxAlphas = max(MaxAlphas, NumAlphas);
     904              : 
     905          801 :     AlphArray.allocate(MaxAlphas);
     906          801 :     cAlphaFields.allocate(MaxAlphas);
     907          801 :     NumArray.dimension(MaxNums, 0.0);
     908          801 :     cNumericFields.allocate(MaxNums);
     909          801 :     lAlphaBlanks.dimension(MaxAlphas, true);
     910          801 :     lNumericBlanks.dimension(MaxNums, true);
     911              : 
     912          801 :     std::string_view CurrentModuleObject = CurrentModuleObjects[static_cast<int>(CMO::ControllerList)];
     913          801 :     state.dataMixedAir->NumControllerLists = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject);
     914              : 
     915          801 :     state.dataMixedAir->ControllerLists.allocate(state.dataMixedAir->NumControllerLists);
     916              : 
     917         2315 :     for (int Item = 1; Item <= state.dataMixedAir->NumControllerLists; ++Item) {
     918              : 
     919              :         // create a reference for convenience
     920         1514 :         auto &thisControllerList(state.dataMixedAir->ControllerLists(Item));
     921         1514 :         state.dataInputProcessing->inputProcessor->getObjectItem(state,
     922              :                                                                  CurrentModuleObject,
     923              :                                                                  Item,
     924              :                                                                  AlphArray,
     925              :                                                                  NumAlphas,
     926              :                                                                  NumArray,
     927              :                                                                  NumNums,
     928              :                                                                  IOStat,
     929              :                                                                  lNumericBlanks,
     930              :                                                                  lAlphaBlanks,
     931              :                                                                  cAlphaFields,
     932              :                                                                  cNumericFields);
     933         1514 :         thisControllerList.Name = AlphArray(1); // no need to check if AlphaArray(1) is empty since Json will catch missing required fields
     934         1514 :         thisControllerList.NumControllers = (NumAlphas - 1) / 2;
     935         1514 :         thisControllerList.ControllerType.dimension(thisControllerList.NumControllers, ControllerKind::Invalid);
     936         1514 :         thisControllerList.ControllerName.allocate(thisControllerList.NumControllers);
     937         1514 :         int AlphaNum = 2;
     938         3488 :         for (int CompNum = 1; CompNum <= thisControllerList.NumControllers; ++CompNum) {
     939              :             // Json will catch any object types that are not the correct key choice of Controller:OutdoorAir or Controller:WaterCoil
     940         3948 :             thisControllerList.ControllerType(CompNum) =
     941         1974 :                 static_cast<ControllerKind>(getEnumValue(ControllerKindNamesUC, Util::makeUPPER(AlphArray(AlphaNum))));
     942         1974 :             thisControllerList.ControllerName(CompNum) = AlphArray(AlphaNum + 1);
     943              :             // loop over all previous controller lists to check if this controllers is also present on previous controllers
     944         9833 :             for (int previousListNum = 1; previousListNum < Item; ++previousListNum) {
     945              :                 // loop over each of the controllers listed for this list
     946         7859 :                 auto &previousList(state.dataMixedAir->ControllerLists(previousListNum));
     947        18706 :                 for (int PreviousListControllerNum = 1; PreviousListControllerNum <= previousList.NumControllers; ++PreviousListControllerNum) {
     948        19034 :                     if ((previousList.ControllerType(PreviousListControllerNum) == thisControllerList.ControllerType(CompNum)) &&
     949         8187 :                         (previousList.ControllerName(PreviousListControllerNum) == thisControllerList.ControllerName(CompNum))) {
     950            0 :                         ShowSevereError(state, format("Controller instance repeated in multiple {} objects", CurrentModuleObject));
     951            0 :                         ShowContinueError(state, format("Found in {} = {}", CurrentModuleObject, thisControllerList.Name));
     952            0 :                         ShowContinueError(state, format("Also found in {} = {}", CurrentModuleObject, previousList.Name));
     953            0 :                         ErrorsFound = true;
     954              :                     }
     955              :                 }
     956              :             }
     957         1974 :             AlphaNum += 2;
     958              :         }
     959              :     }
     960              : 
     961          801 :     CurrentModuleObject = CurrentModuleObjects[static_cast<int>(CMO::OASystem)];
     962              : 
     963          801 :     state.dataAirLoop->NumOASystems = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject);
     964              : 
     965          801 :     state.dataAirLoop->OutsideAirSys.allocate(state.dataAirLoop->NumOASystems);
     966          801 :     state.dataSize->OASysEqSizing.allocate(state.dataAirLoop->NumOASystems);
     967          801 :     state.dataMixedAir->ControllerListUniqueNames.reserve(static_cast<unsigned>(state.dataAirLoop->NumOASystems));
     968          801 :     state.dataMixedAir->MyOneTimeErrorFlag.dimension(state.dataAirLoop->NumOASystems, true);
     969          801 :     state.dataMixedAir->MyOneTimeCheckUnitarySysFlag.dimension(state.dataAirLoop->NumOASystems, true);
     970          801 :     state.dataMixedAir->initOASysFlag.dimension(state.dataAirLoop->NumOASystems, true);
     971              : 
     972         1874 :     for (int OASysNum = 1; OASysNum <= state.dataAirLoop->NumOASystems; ++OASysNum) {
     973         1073 :         auto &OASys = state.dataAirLoop->OutsideAirSys(OASysNum);
     974         1073 :         state.dataInputProcessing->inputProcessor->getObjectItem(state,
     975              :                                                                  CurrentModuleObject,
     976              :                                                                  OASysNum,
     977              :                                                                  AlphArray,
     978              :                                                                  NumAlphas,
     979              :                                                                  NumArray,
     980              :                                                                  NumNums,
     981              :                                                                  IOStat,
     982              :                                                                  lNumericBlanks,
     983              :                                                                  lAlphaBlanks,
     984              :                                                                  cAlphaFields,
     985              :                                                                  cNumericFields);
     986         1073 :         OASys.Name = AlphArray(1); // no need to check if AlphaArray(1) is empty since Json will catch missing required fields
     987         1073 :         if (!AlphArray(2).empty()) {
     988         2146 :             GlobalNames::IntraObjUniquenessCheck(
     989         1073 :                 state, AlphArray(2), CurrentModuleObject, cAlphaFields(2), state.dataMixedAir->ControllerListUniqueNames, ErrorsFound);
     990              :         }
     991         1073 :         OASys.ControllerListName = AlphArray(2);
     992         1073 :         OASys.ComponentListName = AlphArray(3);
     993              : 
     994         5365 :         BranchNodeConnections::TestCompSet(state, CurrentModuleObject, OASys.Name, "UNDEFINED", "UNDEFINED", "Air Nodes");
     995              : 
     996         1073 :         if (!lAlphaBlanks(3)) {
     997         2146 :             int ListNum = state.dataInputProcessing->inputProcessor->getObjectItemNum(
     998         1073 :                 state, CurrentModuleObjects[static_cast<int>(CMO::AirLoopEqList)], OASys.ComponentListName);
     999         1073 :             if (ListNum > 0) {
    1000         2146 :                 state.dataInputProcessing->inputProcessor->getObjectItem(
    1001         1073 :                     state, CurrentModuleObjects[static_cast<int>(CMO::AirLoopEqList)], ListNum, AlphArray, NumAlphas, NumArray, NumNums, IOStat);
    1002         1073 :                 int NumInList = (NumAlphas - 1) / 2;
    1003         1073 :                 OASys.NumComponents = NumInList;
    1004         1073 :                 OASys.ComponentName.allocate(NumInList);
    1005         1073 :                 OASys.ComponentType.allocate(NumInList);
    1006         1073 :                 OASys.ComponentTypeEnum.dimension(NumInList, SimAirServingZones::CompType::Invalid);
    1007         1073 :                 OASys.ComponentIndex.dimension(NumInList, 0);
    1008         1073 :                 OASys.InletNodeNum.dimension(NumInList, 0);
    1009         1073 :                 OASys.OutletNodeNum.dimension(NumInList, 0);
    1010         1073 :                 OASys.compPointer.resize(NumInList + 1, nullptr);
    1011         2283 :                 for (int InListNum = 1; InListNum <= NumInList; ++InListNum) {
    1012         1210 :                     OASys.ComponentName(InListNum) = AlphArray(InListNum * 2 + 1);
    1013         1210 :                     OASys.ComponentType(InListNum) = AlphArray(InListNum * 2);
    1014              : 
    1015              :                     // Add equipment to component sets array
    1016         2420 :                     BranchNodeConnections::SetUpCompSets(state,
    1017              :                                                          CurrentModuleObject,
    1018              :                                                          OASys.Name,
    1019         1210 :                                                          OASys.ComponentType(InListNum),
    1020         1210 :                                                          OASys.ComponentName(InListNum),
    1021              :                                                          "UNDEFINED",
    1022              :                                                          "UNDEFINED");
    1023              :                 }
    1024              :             } else {
    1025            0 :                 ShowSevereError(
    1026              :                     state,
    1027            0 :                     format("{} = \"{}\" invalid {}=\"{}\" not found.", CurrentModuleObject, OASys.Name, cAlphaFields(3), OASys.ComponentListName));
    1028            0 :                 ErrorsFound = true;
    1029              :             }
    1030              :         } else {
    1031            0 :             ShowSevereError(state, format("{} = \"{}\" invalid {} is blank and must be entered.", CurrentModuleObject, OASys.Name, cAlphaFields(3)));
    1032            0 :             ErrorsFound = true;
    1033              :         }
    1034              : 
    1035         1073 :         int ListNum = 0;
    1036         1073 :         int NumSimpControllers = 0; // number of Controller:Simple objects in an OA System
    1037         1073 :         if (!lAlphaBlanks(2)) {
    1038         2146 :             ListNum = state.dataInputProcessing->inputProcessor->getObjectItemNum(
    1039         1073 :                 state, CurrentModuleObjects[static_cast<int>(CMO::ControllerList)], OASys.ControllerListName);
    1040         1073 :             if (ListNum > 0) {
    1041         2146 :                 state.dataInputProcessing->inputProcessor->getObjectItem(
    1042         1073 :                     state, CurrentModuleObjects[static_cast<int>(CMO::ControllerList)], ListNum, AlphArray, NumAlphas, NumArray, NumNums, IOStat);
    1043         1073 :                 int NumInList = (NumAlphas - 1) / 2;
    1044         1073 :                 OASys.NumControllers = NumInList;
    1045         1073 :                 OASys.ControllerName.allocate(NumInList);
    1046         1073 :                 OASys.ControllerType.allocate(NumInList);
    1047         1073 :                 OASys.controllerTypeEnum.dimension(NumInList, DataAirLoop::ControllerKind::Invalid);
    1048         1073 :                 OASys.ControllerIndex.dimension(NumInList, 0);
    1049         2205 :                 for (int InListNum = 1; InListNum <= NumInList; ++InListNum) {
    1050         1132 :                     OASys.ControllerName(InListNum) = AlphArray(InListNum * 2 + 1);
    1051         1132 :                     OASys.ControllerType(InListNum) = AlphArray(InListNum * 2);
    1052         2264 :                     OASys.controllerTypeEnum(InListNum) =
    1053         1132 :                         static_cast<DataAirLoop::ControllerKind>(getEnumValue(ControllerKindNamesUC, OASys.ControllerType(InListNum)));
    1054              :                     // only count Controller:OutdoorAir types as valid simple controllers
    1055         1132 :                     if (OASys.controllerTypeEnum(InListNum) != DataAirLoop::ControllerKind::OutdoorAir) {
    1056           60 :                         ++NumSimpControllers;
    1057              :                     }
    1058              :                 }
    1059              :             } else {
    1060            0 :                 ShowSevereError(state,
    1061            0 :                                 format("{} = \"{}\" invalid {}=\"{}\" not found.", CurrentModuleObject, AlphArray(1), cAlphaFields(2), AlphArray(2)));
    1062            0 :                 ErrorsFound = true;
    1063              :             }
    1064              :         } else {
    1065            0 :             if (state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "AirLoopHVAC:DedicatedOutdoorAirSystem") == 0) {
    1066            0 :                 ShowSevereError(state,
    1067            0 :                                 format("{} = \"{}\" invalid {} is blank and must be entered.", CurrentModuleObject, AlphArray(1), cAlphaFields(2)));
    1068            0 :                 ErrorsFound = true;
    1069              :             } else {
    1070            0 :                 ShowWarningError(state,
    1071            0 :                                  format("{} = \"{}\": blank {} must be used with AirLoopHVAC:DedicatedOutdoorAirSystem.",
    1072              :                                         CurrentModuleObject,
    1073              :                                         AlphArray(1),
    1074              :                                         cAlphaFields(2)));
    1075              :             }
    1076              :         }
    1077         1073 :         OASys.ControllerListNum = ListNum;
    1078         1073 :         OASys.NumSimpleControllers = NumSimpControllers;
    1079              :     }
    1080              : 
    1081         1874 :     for (int OASysNum = 1; OASysNum <= state.dataAirLoop->NumOASystems; ++OASysNum) {
    1082         1073 :         auto &OASys = state.dataAirLoop->OutsideAirSys(OASysNum);
    1083         2283 :         for (int CompNum = 1; CompNum <= OASys.NumComponents; ++CompNum) {
    1084         1210 :             OASys.ComponentTypeEnum(CompNum) = static_cast<SimAirServingZones::CompType>(getEnumValue(CompTypeNamesUC, OASys.ComponentType(CompNum)));
    1085         1210 :             if (OASys.ComponentTypeEnum(CompNum) == SimAirServingZones::CompType::Fan_System_Object) {
    1086              :                 // construct fan object
    1087            1 :                 OASys.ComponentIndex(CompNum) = Fans::GetFanIndex(state, OASys.ComponentName(CompNum));
    1088         1209 :             } else if (OASys.ComponentTypeEnum(CompNum) == SimAirServingZones::CompType::CoilSystemWater ||
    1089         2417 :                        OASys.ComponentTypeEnum(CompNum) == SimAirServingZones::CompType::UnitarySystemModel ||
    1090         1208 :                        OASys.ComponentTypeEnum(CompNum) == SimAirServingZones::CompType::DXSystem) {
    1091            2 :                 OASys.ComponentIndex(CompNum) = CompNum;
    1092         1207 :             } else if (OASys.ComponentTypeEnum(CompNum) == SimAirServingZones::CompType::Invalid) {
    1093           40 :                 std::string const thisComp = OASys.ComponentType(CompNum);
    1094           40 :                 if (thisComp == "HEATEXCHANGER:AIRTOAIR:SENSIBLEANDLATENT" || thisComp == "HEATEXCHANGER:DESICCANT:BALANCEDFLOW") {
    1095           24 :                     OASys.ComponentTypeEnum(CompNum) = SimAirServingZones::CompType::HeatXchngr;
    1096           16 :                 } else if (thisComp == "DEHUMIDIFIER:DESICCANT:SYSTEM") {
    1097            2 :                     OASys.ComponentTypeEnum(CompNum) = SimAirServingZones::CompType::Desiccant;
    1098           28 :                 } else if (thisComp == "EVAPORATIVECOOLER:INDIRECT:CELDEKPAD" || thisComp == "EVAPORATIVECOOLER:INDIRECT:WETCOIL" ||
    1099           28 :                            thisComp == "EVAPORATIVECOOLER:INDIRECT:RESEARCHSPECIAL" || thisComp == "EVAPORATIVECOOLER:DIRECT:RESEARCHSPECIAL") {
    1100           14 :                     OASys.ComponentTypeEnum(CompNum) = SimAirServingZones::CompType::EvapCooler;
    1101            0 :                 } else if (thisComp == "HUMIDIFIER:STEAM:GAS") {
    1102            0 :                     OASys.ComponentTypeEnum(CompNum) = SimAirServingZones::CompType::Humidifier;
    1103              :                 } else {
    1104            0 :                     ShowSevereError(
    1105              :                         state,
    1106            0 :                         format("{} = \"{}\" invalid Outside Air Component=\"{}\".", CurrentModuleObject, AlphArray(1), OASys.ComponentType(CompNum)));
    1107            0 :                     ErrorsFound = true;
    1108              :                 }
    1109           40 :             }
    1110              :         }
    1111              : 
    1112              :         // loop through the controllers in the controller list for OA system and save the pointer to the OA controller index
    1113         1075 :         for (int OAControllerNum = 1; OAControllerNum <= state.dataAirLoop->OutsideAirSys(OASysNum).NumControllers; ++OAControllerNum) {
    1114         1074 :             if (state.dataAirLoop->OutsideAirSys(OASysNum).controllerTypeEnum(OAControllerNum) == DataAirLoop::ControllerKind::OutdoorAir) {
    1115         1072 :                 state.dataAirLoop->OutsideAirSys(OASysNum).OAControllerName =
    1116         2144 :                     state.dataAirLoop->OutsideAirSys(OASysNum).ControllerName(OAControllerNum);
    1117         1072 :                 break;
    1118              :             }
    1119              :         }
    1120              :     }
    1121              : 
    1122          801 :     if (ErrorsFound) {
    1123            0 :         ShowFatalError(state, format("{}Errors found in getting {}.", RoutineName, CurrentModuleObject));
    1124              :     }
    1125              : 
    1126          801 :     AlphArray.deallocate();
    1127          801 :     cAlphaFields.deallocate();
    1128          801 :     NumArray.deallocate();
    1129          801 :     cNumericFields.deallocate();
    1130          801 :     lAlphaBlanks.deallocate();
    1131          801 :     lNumericBlanks.deallocate();
    1132              : 
    1133          801 :     state.dataMixedAir->GetOASysInputFlag = false;
    1134              : 
    1135              :     // once GetOASysInputFlag is set to false other calls to objects can occur without worry that GetOutsideAirSysInputs will be called again
    1136              :     // now get the pointer for UnitarySystem - doing this earlier can cause recursion which trips IntraObjUniquenessCheck warnings
    1137         1874 :     for (int OASysNum = 1; OASysNum <= state.dataAirLoop->NumOASystems; ++OASysNum) {
    1138         2283 :         for (int CompNum = 1; CompNum <= state.dataAirLoop->OutsideAirSys(OASysNum).NumComponents; ++CompNum) {
    1139         1210 :             if (state.dataAirLoop->OutsideAirSys(OASysNum).ComponentTypeEnum(CompNum) == SimAirServingZones::CompType::CoilSystemWater ||
    1140         2419 :                 state.dataAirLoop->OutsideAirSys(OASysNum).ComponentTypeEnum(CompNum) == SimAirServingZones::CompType::UnitarySystemModel ||
    1141         1209 :                 state.dataAirLoop->OutsideAirSys(OASysNum).ComponentTypeEnum(CompNum) == SimAirServingZones::CompType::DXSystem) {
    1142            2 :                 state.dataAirLoop->OutsideAirSys(OASysNum).compPointer[CompNum] = UnitarySystems::UnitarySys::factory(
    1143            2 :                     state, HVAC::UnitarySysType::Unitary_AnyCoilType, state.dataAirLoop->OutsideAirSys(OASysNum).ComponentName(CompNum), false, 0);
    1144              :             }
    1145              :         }
    1146              :     }
    1147          801 : }
    1148              : 
    1149          413 : void GetOAControllerInputs(EnergyPlusData &state)
    1150              : {
    1151              : 
    1152              :     // SUBROUTINE INFORMATION:
    1153              :     //       AUTHOR         Fred Buhl
    1154              :     //       DATE WRITTEN   Oct 1998
    1155              :     //       MODIFIED       Shirey/Raustad FSEC, June 2003, Jan 2004
    1156              :     //                      Mangesh Basarkar, 06/2011: Getting zone OA specifications from Design Specification Object
    1157              :     //                      Tianzhen Hong, 3/2012: getting zone air distribution effectiveness and secondary recirculation
    1158              :     //                       from DesignSpecification:ZoneAirDistribution objects
    1159              : 
    1160              :     // PURPOSE OF THIS SUBROUTINE
    1161              :     // Input the OAController data and store it in the OAController array.
    1162              :     // Input the Ventilation:Mechanical data and store it in the VentilationMechanical array.
    1163              :     //  Condense Ventilation:Mechanical data array to include only unique zones specified for each instance of this object.
    1164              : 
    1165              :     // METHODOLOGY EMPLOYED:
    1166              :     // Use the Get routines from the InputProcessor module.
    1167              : 
    1168              :     // SUBROUTINE PARAMETER DEFINITIONS:
    1169              :     static constexpr std::string_view RoutineName("GetOAControllerInputs: "); // include trailing blank space
    1170              :     static constexpr std::string_view routineName = "GetOAControllerInputs";  // include trailing blank space
    1171              : 
    1172              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    1173              :     int NumArg;    // Number of arguments from GetObjectDefMaxArgs call
    1174              :     int NumNums;   // Number of real numbers returned by GetObjectItem
    1175              :     int NumAlphas; // Number of alphanumerics returned by GetObjectItem
    1176              :     int IOStat;    // Status of GetObjectItem call
    1177          413 :     Array1D<Real64> NumArray;
    1178          413 :     Array1D_string AlphArray;
    1179          413 :     std::string_view CurrentModuleObject; // Object type for getting and messages
    1180          413 :     Array1D_string cAlphaFields;          // Alpha field names
    1181          413 :     Array1D_string cNumericFields;        // Numeric field names
    1182          413 :     Array1D_bool lAlphaBlanks;            // Logical array, alpha field input BLANK = .TRUE.
    1183          413 :     Array1D_bool lNumericBlanks;          // Logical array, numeric field input BLANK = .TRUE.
    1184          413 :     bool ErrorsFound(false);              // Flag identifying errors found during get input
    1185              : 
    1186              :     // First, call other get input routines in this module to make sure data is filled during this routine.
    1187          413 :     if (state.dataMixedAir->GetOASysInputFlag) { // Gets input for object  first time Sim routine is called
    1188            0 :         GetOutsideAirSysInputs(state);
    1189            0 :         state.dataMixedAir->GetOASysInputFlag = false;
    1190              :     }
    1191          413 :     if (state.dataMixedAir->GetOAMixerInputFlag) { // Gets input for object  first time Sim routine is called
    1192            0 :         GetOAMixerInputs(state);
    1193            0 :         state.dataMixedAir->GetOAMixerInputFlag = false;
    1194              :     }
    1195              : 
    1196          413 :     FaultsManager::CheckAndReadFaults(state);
    1197              : 
    1198          826 :     state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(
    1199          413 :         state, CurrentModuleObjects[static_cast<int>(CMO::OAController)], NumArg, NumAlphas, NumNums);
    1200          413 :     int MaxAlphas = NumAlphas;
    1201          413 :     int MaxNums = NumNums;
    1202          826 :     state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(
    1203          413 :         state, CurrentModuleObjects[static_cast<int>(CMO::ERVController)], NumArg, NumAlphas, NumNums);
    1204          413 :     MaxAlphas = max(MaxAlphas, NumAlphas);
    1205          413 :     MaxNums = max(MaxNums, NumNums);
    1206          826 :     state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(
    1207          413 :         state, CurrentModuleObjects[static_cast<int>(CMO::MechVentilation)], NumArg, NumAlphas, NumNums);
    1208          413 :     MaxAlphas = max(MaxAlphas, NumAlphas);
    1209          413 :     MaxNums = max(MaxNums, NumNums);
    1210              : 
    1211          413 :     AlphArray.allocate(MaxAlphas);
    1212          413 :     NumArray.dimension(MaxNums, 0.0);
    1213          413 :     lAlphaBlanks.dimension(MaxAlphas, true);
    1214          413 :     lNumericBlanks.dimension(MaxNums, true);
    1215          413 :     cAlphaFields.allocate(MaxAlphas);
    1216          413 :     cNumericFields.allocate(MaxNums);
    1217              : 
    1218              :     // Count OAcontrollers and ERVcontrollers and allocate arrays
    1219          413 :     AllocateOAControllers(state);
    1220              : 
    1221              :     // If there are ERV controllers, they have been filled before now NumOAControllers includes the count of NumERVControllers
    1222          413 :     if (state.dataMixedAir->NumOAControllers > state.dataMixedAir->NumERVControllers) {
    1223          413 :         CurrentModuleObject = CurrentModuleObjects[static_cast<int>(CMO::OAController)];
    1224          413 :         int currentOAControllerNum = 0;
    1225         1480 :         for (int OutAirNum = state.dataMixedAir->NumERVControllers + 1; OutAirNum <= state.dataMixedAir->NumOAControllers; ++OutAirNum) {
    1226         1067 :             ++currentOAControllerNum;
    1227         1067 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
    1228              :                                                                      CurrentModuleObject,
    1229              :                                                                      currentOAControllerNum,
    1230              :                                                                      AlphArray,
    1231              :                                                                      NumAlphas,
    1232              :                                                                      NumArray,
    1233              :                                                                      NumNums,
    1234              :                                                                      IOStat,
    1235              :                                                                      lNumericBlanks,
    1236              :                                                                      lAlphaBlanks,
    1237              :                                                                      cAlphaFields,
    1238              :                                                                      cNumericFields);
    1239         2134 :             GlobalNames::VerifyUniqueInterObjectName(
    1240         1067 :                 state, state.dataMixedAir->OAControllerUniqueNames, AlphArray(1), CurrentModuleObject, cAlphaFields(1), ErrorsFound);
    1241              : 
    1242         1067 :             ProcessOAControllerInputs(state,
    1243              :                                       CurrentModuleObject,
    1244              :                                       OutAirNum,
    1245              :                                       AlphArray,
    1246              :                                       NumAlphas,
    1247              :                                       NumArray,
    1248              :                                       NumNums,
    1249              :                                       lNumericBlanks,
    1250              :                                       lAlphaBlanks,
    1251              :                                       cAlphaFields,
    1252              :                                       cNumericFields,
    1253              :                                       ErrorsFound);
    1254              : 
    1255              :             // add applicable faults identifier to avoid string comparison at each time step
    1256              :             //  loop through each fault for each OA controller and determine economizer faults
    1257         1087 :             for (int i = 1; i <= state.dataFaultsMgr->NumFaultyEconomizer; ++i) {
    1258           20 :                 if (state.dataFaultsMgr->FaultsEconomizer(i).ControllerTypeEnum != iController_AirEconomizer) {
    1259            0 :                     continue;
    1260              :                 }
    1261           20 :                 if (Util::SameString(state.dataMixedAir->OAController(OutAirNum).Name, state.dataFaultsMgr->FaultsEconomizer(i).ControllerName)) {
    1262            5 :                     state.dataFaultsMgr->FaultsEconomizer(i).ControllerID = OutAirNum;
    1263            5 :                     ++state.dataMixedAir->OAController(OutAirNum).NumFaultyEconomizer;
    1264              :                 }
    1265              :             }
    1266              :             //  loop through each fault for each OA controller to determine faulty counts
    1267         1067 :             state.dataMixedAir->OAController(OutAirNum).EconmizerFaultNum.allocate(state.dataMixedAir->OAController(OutAirNum).NumFaultyEconomizer);
    1268         1067 :             if (state.dataMixedAir->OAController(OutAirNum).NumFaultyEconomizer > 0) {
    1269           12 :                 for (int j = 0, i = 1; i <= state.dataFaultsMgr->NumFaultyEconomizer; ++i) {
    1270           10 :                     if (state.dataFaultsMgr->FaultsEconomizer(i).ControllerTypeEnum != iController_AirEconomizer) {
    1271            0 :                         continue;
    1272              :                     }
    1273           10 :                     if (Util::SameString(state.dataMixedAir->OAController(OutAirNum).Name, state.dataFaultsMgr->FaultsEconomizer(i).ControllerName)) {
    1274            5 :                         state.dataMixedAir->OAController(OutAirNum).EconmizerFaultNum(++j) = i;
    1275              :                     }
    1276              :                 }
    1277              :             }
    1278              :         } // LOOP FOR OutAirNum
    1279              : 
    1280          413 :         if (ErrorsFound) {
    1281            0 :             AlphArray.deallocate();
    1282            0 :             NumArray.deallocate();
    1283            0 :             lNumericBlanks.deallocate();
    1284            0 :             lAlphaBlanks.deallocate();
    1285            0 :             cAlphaFields.deallocate();
    1286            0 :             cNumericFields.deallocate();
    1287            0 :             ShowFatalError(state, format("{}Errors found in getting {} inputs.", RoutineName, CurrentModuleObject));
    1288              :         }
    1289              :     }
    1290              : 
    1291          413 :     state.dataMixedAir->GetOAControllerInputFlag = false;
    1292              : 
    1293              :     // Process Controller:MechanicalVentilation objects
    1294          413 :     CurrentModuleObject = CurrentModuleObjects[static_cast<int>(CMO::MechVentilation)];
    1295          413 :     state.dataMixedAir->NumVentMechControllers = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject);
    1296          413 :     if (state.dataMixedAir->NumVentMechControllers > 0) {
    1297           26 :         state.dataMixedAir->VentilationMechanical.allocate(state.dataMixedAir->NumVentMechControllers);
    1298           80 :         for (int VentMechNum = 1; VentMechNum <= state.dataMixedAir->NumVentMechControllers; ++VentMechNum) {
    1299           54 :             auto &thisVentilationMechanical(state.dataMixedAir->VentilationMechanical(VentMechNum));
    1300           54 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
    1301              :                                                                      CurrentModuleObject,
    1302              :                                                                      VentMechNum,
    1303              :                                                                      AlphArray,
    1304              :                                                                      NumAlphas,
    1305              :                                                                      NumArray,
    1306              :                                                                      NumNums,
    1307              :                                                                      IOStat,
    1308              :                                                                      lNumericBlanks,
    1309              :                                                                      lAlphaBlanks,
    1310              :                                                                      cAlphaFields,
    1311              :                                                                      cNumericFields);
    1312              : 
    1313           54 :             ErrorObjectHeader eoh{routineName, CurrentModuleObject, AlphArray(1)};
    1314              : 
    1315           54 :             int MechVentZoneCount = 0;
    1316              : 
    1317           54 :             int NumGroups = (NumAlphas + NumNums - 5) / 3; // Number of extensible input groups of the VentilationMechanical object
    1318           54 :             if (mod((NumAlphas + NumNums - 5), 3) != 0) {
    1319            0 :                 ++NumGroups;
    1320              :             }
    1321           54 :             thisVentilationMechanical.Name = AlphArray(1); // no need to check if AlphaArray(1) is empty since Json will catch missing required fields
    1322              : 
    1323           54 :             if (lAlphaBlanks(2)) {
    1324            3 :                 thisVentilationMechanical.availSched = Sched::GetScheduleAlwaysOn(state);
    1325           51 :             } else if ((thisVentilationMechanical.availSched = Sched::GetSchedule(state, AlphArray(2))) == nullptr) {
    1326            0 :                 ShowSevereItemNotFound(state, eoh, cAlphaFields(2), AlphArray(2));
    1327            0 :                 ErrorsFound = true;
    1328              :             }
    1329              : 
    1330              :             // Adding new flag for DCV
    1331           54 :             if (Util::SameString(AlphArray(3), "Yes")) {
    1332           51 :                 thisVentilationMechanical.DCVFlag = true;
    1333            3 :             } else if (Util::SameString(AlphArray(3), "No") || lAlphaBlanks(3)) {
    1334            3 :                 thisVentilationMechanical.DCVFlag = false;
    1335              :             } else {
    1336            0 :                 ShowSevereError(state,
    1337            0 :                                 format("{}=\"{}\" invalid value {}=\"{}\".", CurrentModuleObject, AlphArray(1), cAlphaFields(3), AlphArray(3)));
    1338            0 :                 ShowContinueError(state, "...Valid values are \"Yes\" or \"No\".");
    1339            0 :                 ErrorsFound = true;
    1340              :             }
    1341              : 
    1342              :             // System outdoor air method
    1343           54 :             thisVentilationMechanical.SystemOAMethod = static_cast<DataSizing::SysOAMethod>(getEnumValue(SOAMNamesUC, Util::makeUPPER(AlphArray(4))));
    1344              : 
    1345           54 :             if (thisVentilationMechanical.SystemOAMethod == DataSizing::SysOAMethod::IAQP ||
    1346           53 :                 thisVentilationMechanical.SystemOAMethod == DataSizing::SysOAMethod::ProportionalControlSchOcc ||
    1347           52 :                 thisVentilationMechanical.SystemOAMethod == DataSizing::SysOAMethod::ProportionalControlDesOcc ||
    1348           51 :                 thisVentilationMechanical.SystemOAMethod == DataSizing::SysOAMethod::ProportionalControlDesOARate ||
    1349           50 :                 thisVentilationMechanical.SystemOAMethod == DataSizing::SysOAMethod::IAQPCOM) {
    1350            4 :                 if (!state.dataContaminantBalance->Contaminant.CO2Simulation) {
    1351            0 :                     ShowSevereError(
    1352              :                         state,
    1353            0 :                         format(
    1354              :                             "{}=\"{}\" valid {}=\"{}\" requires CO2 simulation.", CurrentModuleObject, AlphArray(1), cAlphaFields(2), AlphArray(2)));
    1355            0 :                     ShowContinueError(state, "The choice must be Yes for the field Carbon Dioxide Concentration in ZoneAirContaminantBalance");
    1356            0 :                     ErrorsFound = true;
    1357              :                 }
    1358              :             }
    1359              : 
    1360           54 :             if (thisVentilationMechanical.SystemOAMethod == DataSizing::SysOAMethod::IAQPGC ||
    1361           53 :                 thisVentilationMechanical.SystemOAMethod == DataSizing::SysOAMethod::IAQPCOM) {
    1362            1 :                 if (!state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
    1363            0 :                     ShowSevereError(state,
    1364            0 :                                     format("{}=\"{}\" valid {}=\"{}\" requires generic contaminant simulation.",
    1365              :                                            CurrentModuleObject,
    1366              :                                            AlphArray(1),
    1367              :                                            cAlphaFields(2),
    1368              :                                            AlphArray(2)));
    1369            0 :                     ShowContinueError(state, "The choice must be Yes for the field Generic Contaminant Concentration in ZoneAirContaminantBalance");
    1370            0 :                     ErrorsFound = true;
    1371              :                 }
    1372              :             }
    1373              : 
    1374           54 :             if (thisVentilationMechanical.SystemOAMethod == DataSizing::SysOAMethod::Invalid) { // If specified incorrectly, show errors
    1375            0 :                 thisVentilationMechanical.SystemOAMethod = DataSizing::SysOAMethod::ZoneSum;
    1376            0 :                 ShowWarningError(state,
    1377            0 :                                  format("{}=\"{}\" incorrect specification for {}, the ZoneSum method will be used.",
    1378              :                                         CurrentModuleObject,
    1379              :                                         AlphArray(1),
    1380              :                                         cAlphaFields(4)));
    1381              :                 // ErrorsFound=.TRUE.
    1382              :             }
    1383              : 
    1384              :             // Zone maximum outdoor air fraction
    1385           54 :             thisVentilationMechanical.ZoneMaxOAFraction = NumArray(1);
    1386              : 
    1387           54 :             state.dataMixedAir->VentMechZoneOrListName.allocate(NumGroups);
    1388           54 :             state.dataMixedAir->DesignSpecOAObjName.allocate(NumGroups);
    1389           54 :             state.dataMixedAir->DesignSpecOAObjIndex.dimension(NumGroups, 0);
    1390           54 :             state.dataMixedAir->DesignSpecZoneADObjName.allocate(NumGroups);
    1391           54 :             state.dataMixedAir->DesignSpecZoneADObjIndex.dimension(NumGroups, 0);
    1392              : 
    1393              :             //   First time through find the total number of zones requiring mechanical ventilation
    1394              :             //   May include duplicate zones. Will check for duplicate zones further down in this subroutine.
    1395          452 :             for (int groupNum = 1; groupNum <= NumGroups; ++groupNum) {
    1396          398 :                 state.dataMixedAir->VentMechZoneOrListName(groupNum) = AlphArray((groupNum - 1) * 3 + 5);
    1397              : 
    1398              :                 //     Getting OA details from design specification OA object
    1399          398 :                 if (!lAlphaBlanks((groupNum - 1) * 3 + 6)) {
    1400          398 :                     state.dataMixedAir->DesignSpecOAObjName(groupNum) = AlphArray((groupNum - 1) * 3 + 6);
    1401          398 :                     int ObjIndex = Util::FindItemInList(state.dataMixedAir->DesignSpecOAObjName(groupNum), state.dataSize->OARequirements);
    1402          398 :                     state.dataMixedAir->DesignSpecOAObjIndex(groupNum) = ObjIndex;
    1403              : 
    1404          398 :                     if (ObjIndex == 0) {
    1405            0 :                         ShowSevereError(state, format("{}{}=\"{}\", invalid", RoutineName, CurrentModuleObject, thisVentilationMechanical.Name));
    1406            0 :                         ShowContinueError(state,
    1407            0 :                                           format("... not found {}=\"{}\".",
    1408            0 :                                                  cAlphaFields((groupNum - 1) * 3 + 6),
    1409            0 :                                                  state.dataMixedAir->DesignSpecOAObjName(groupNum)));
    1410            0 :                         ErrorsFound = true;
    1411              :                     }
    1412              :                 }
    1413              : 
    1414              :                 // Get zone air distribution details from design specification Zone Air Distribution object
    1415          398 :                 if (!lAlphaBlanks((groupNum - 1) * 3 + 7)) {
    1416          398 :                     state.dataMixedAir->DesignSpecZoneADObjName(groupNum) = AlphArray((groupNum - 1) * 3 + 7);
    1417          398 :                     int ObjIndex = Util::FindItemInList(state.dataMixedAir->DesignSpecZoneADObjName(groupNum), state.dataSize->ZoneAirDistribution);
    1418          398 :                     state.dataMixedAir->DesignSpecZoneADObjIndex(groupNum) = ObjIndex;
    1419              : 
    1420          398 :                     if (ObjIndex == 0) {
    1421              :                         // Cannot find the design specification Zone Air Distribution object
    1422            0 :                         ShowSevereError(state, format("{}{}=\"{}\", invalid", RoutineName, CurrentModuleObject, thisVentilationMechanical.Name));
    1423            0 :                         ShowContinueError(state,
    1424            0 :                                           format("... not found {}=\"{}\".",
    1425            0 :                                                  cAlphaFields((groupNum - 1) * 3 + 7),
    1426            0 :                                                  state.dataMixedAir->DesignSpecZoneADObjName(groupNum)));
    1427            0 :                         ErrorsFound = true;
    1428              :                     }
    1429              :                 }
    1430              : 
    1431          398 :                 int ZoneNum = Util::FindItemInList(state.dataMixedAir->VentMechZoneOrListName(groupNum), state.dataHeatBal->Zone);
    1432          398 :                 if (ZoneNum > 0) {
    1433          391 :                     ++MechVentZoneCount;
    1434              :                 } else {
    1435            7 :                     int ZoneListNum = Util::FindItemInList(state.dataMixedAir->VentMechZoneOrListName(groupNum), state.dataHeatBal->ZoneList);
    1436            7 :                     if (ZoneListNum > 0) {
    1437            7 :                         MechVentZoneCount += state.dataHeatBal->ZoneList(ZoneListNum).NumOfZones;
    1438              :                     } else {
    1439            0 :                         ShowWarningError(
    1440              :                             state,
    1441            0 :                             format("{}=\"{}\" invalid {} not found.", CurrentModuleObject, AlphArray(1), cAlphaFields((groupNum - 1) * 3 + 5)));
    1442            0 :                         ShowContinueError(
    1443              :                             state,
    1444            0 :                             format("Missing {} = {}", cAlphaFields((groupNum - 1) * 3 + 5), state.dataMixedAir->VentMechZoneOrListName(groupNum)));
    1445            0 :                         ErrorsFound = true;
    1446              :                     }
    1447              :                 }
    1448              :             }
    1449              : 
    1450           54 :             thisVentilationMechanical.NumofVentMechZones = MechVentZoneCount;
    1451              : 
    1452              :             // Now allocate and store unique zone and associated ventilation rate information
    1453           54 :             thisVentilationMechanical.VentMechZone.allocate(MechVentZoneCount);
    1454              : 
    1455           54 :             MechVentZoneCount = 0;
    1456              : 
    1457              :             //   Loop through zone names and list of zone names, remove duplicate zones, and store designspec names and indexes
    1458          452 :             for (int groupNum = 1; groupNum <= NumGroups; ++groupNum) {
    1459          398 :                 int ZoneNum = Util::FindItemInList(state.dataMixedAir->VentMechZoneOrListName(groupNum), state.dataHeatBal->Zone);
    1460          398 :                 if (ZoneNum > 0) {
    1461          391 :                     if (std::any_of(thisVentilationMechanical.VentMechZone.begin(),
    1462          782 :                                     thisVentilationMechanical.VentMechZone.end(),
    1463         9045 :                                     [ZoneNum](auto const &vmZone) { return vmZone.zoneNum == ZoneNum; })) {
    1464              :                         //          Disregard duplicate zone names, show warning and do not store data for this zone
    1465            0 :                         ShowWarningError(state,
    1466            0 :                                          format("Zone name = {} for {} object = {}",
    1467            0 :                                                 state.dataMixedAir->VentMechZoneOrListName(groupNum),
    1468              :                                                 CurrentModuleObject,
    1469            0 :                                                 thisVentilationMechanical.Name));
    1470            0 :                         ShowContinueError(state, "is specified more than once. The first ventilation values specified for this zone will be used");
    1471            0 :                         ShowContinueError(state, "and the rest will be ignored. Simulation will continue..");
    1472              :                     } else {
    1473              :                         //          Store unique zone names
    1474          391 :                         ++MechVentZoneCount;
    1475          391 :                         auto &thisMechVentZone = thisVentilationMechanical.VentMechZone(MechVentZoneCount);
    1476          391 :                         thisMechVentZone.zoneNum = ZoneNum;
    1477          391 :                         thisMechVentZone.name = state.dataHeatBal->Zone(ZoneNum).Name;
    1478              : 
    1479              :                         // Populating new temp array to hold design spec OA object for each zone
    1480          391 :                         if (state.dataMixedAir->DesignSpecOAObjIndex(groupNum) > 0) {
    1481          391 :                             thisMechVentZone.ZoneDesignSpecOAObjName = state.dataMixedAir->DesignSpecOAObjName(groupNum);
    1482          391 :                             thisMechVentZone.ZoneDesignSpecOAObjIndex = state.dataMixedAir->DesignSpecOAObjIndex(groupNum);
    1483              :                         } else {
    1484            0 :                             if (state.dataGlobal->DoZoneSizing) {
    1485            0 :                                 int ObjIndex = Util::FindItemInList(state.dataMixedAir->VentMechZoneOrListName(groupNum),
    1486            0 :                                                                     state.dataSize->ZoneSizingInput,
    1487              :                                                                     &ZoneSizingInputData::ZoneName);
    1488            0 :                                 if (ObjIndex > 0) {
    1489            0 :                                     thisMechVentZone.ZoneDesignSpecOAObjName = state.dataSize->ZoneSizingInput(ObjIndex).DesignSpecOAObjName;
    1490            0 :                                     thisMechVentZone.ZoneDesignSpecOAObjIndex = state.dataSize->ZoneSizingInput(ObjIndex).ZoneDesignSpecOAIndex;
    1491              :                                 }
    1492              :                             }
    1493              :                         }
    1494              :                         // Zone Air Distribution inputs
    1495          391 :                         if (state.dataMixedAir->DesignSpecZoneADObjIndex(groupNum) > 0) {
    1496              :                             // new DCV inputs
    1497          391 :                             thisMechVentZone.ZoneDesignSpecADObjName = state.dataMixedAir->DesignSpecZoneADObjName(groupNum);
    1498          391 :                             thisMechVentZone.ZoneDesignSpecADObjIndex = state.dataMixedAir->DesignSpecZoneADObjIndex(groupNum);
    1499              :                         } else {
    1500            0 :                             if (state.dataGlobal->DoZoneSizing) {
    1501            0 :                                 int ObjIndex = Util::FindItemInList(state.dataMixedAir->VentMechZoneOrListName(groupNum),
    1502            0 :                                                                     state.dataSize->ZoneSizingInput,
    1503              :                                                                     &ZoneSizingInputData::ZoneName);
    1504            0 :                                 if (ObjIndex > 0) {
    1505            0 :                                     thisMechVentZone.ZoneDesignSpecADObjName = state.dataSize->ZoneSizingInput(ObjIndex).ZoneAirDistEffObjName;
    1506            0 :                                     thisMechVentZone.ZoneDesignSpecADObjIndex = state.dataSize->ZoneSizingInput(ObjIndex).ZoneAirDistributionIndex;
    1507              :                                 }
    1508              :                             }
    1509              :                         }
    1510              :                     }
    1511              :                 } else {
    1512              :                     //       Not a zone name, must be a zone list
    1513            7 :                     int ZoneListNum = Util::FindItemInList(state.dataMixedAir->VentMechZoneOrListName(groupNum), state.dataHeatBal->ZoneList);
    1514            7 :                     if (ZoneListNum > 0) {
    1515           21 :                         for (int ScanZoneListNum = 1; ScanZoneListNum <= state.dataHeatBal->ZoneList(ZoneListNum).NumOfZones; ++ScanZoneListNum) {
    1516              :                             // check to make sure zone name is unique (not listed more than once)...
    1517           14 :                             int zoneNum2 = state.dataHeatBal->ZoneList(ZoneListNum).Zone(ScanZoneListNum);
    1518           14 :                             if (std::any_of(thisVentilationMechanical.VentMechZone.begin(),
    1519           28 :                                             thisVentilationMechanical.VentMechZone.end(),
    1520           42 :                                             [zoneNum2](auto const &vmZone) { return vmZone.zoneNum == zoneNum2; })) {
    1521              :                                 //             Disregard duplicate zone names, show warning and do not store data for this zone
    1522            0 :                                 ShowWarningError(state,
    1523            0 :                                                  format("Zone name = {} in ZoneList = {} for {} object = {}",
    1524            0 :                                                         state.dataHeatBal->Zone(zoneNum2).Name,
    1525            0 :                                                         state.dataMixedAir->VentMechZoneOrListName(groupNum),
    1526              :                                                         CurrentModuleObject,
    1527            0 :                                                         thisVentilationMechanical.Name));
    1528            0 :                                 ShowContinueError(state, "is a duplicate. The first ventilation values specified for this zone will be used ");
    1529            0 :                                 ShowContinueError(state, "and the rest will be ignored. The simulation will continue...");
    1530              :                             } else {
    1531              :                                 //           Store data for each zone name from zone list (duplicate zone names accounted for in
    1532              :                                 //           HeatBalanceManager)
    1533           14 :                                 ++MechVentZoneCount;
    1534           14 :                                 auto &thisMechVentZone = thisVentilationMechanical.VentMechZone(MechVentZoneCount);
    1535           14 :                                 thisMechVentZone.zoneNum = zoneNum2;
    1536           14 :                                 thisMechVentZone.name = state.dataHeatBal->Zone(zoneNum2).Name;
    1537              :                                 // Populating new temp array to hold design spec OA object for each zone
    1538           14 :                                 if (state.dataMixedAir->DesignSpecOAObjIndex(groupNum) > 0) {
    1539           14 :                                     thisMechVentZone.ZoneDesignSpecOAObjName = state.dataMixedAir->DesignSpecOAObjName(groupNum);
    1540           14 :                                     thisMechVentZone.ZoneDesignSpecOAObjIndex = state.dataMixedAir->DesignSpecOAObjIndex(groupNum);
    1541              :                                 } else {
    1542            0 :                                     if (state.dataGlobal->DoZoneSizing) {
    1543            0 :                                         int ObjIndex = Util::FindItemInList(
    1544            0 :                                             state.dataHeatBal->Zone(zoneNum2).Name, state.dataSize->ZoneSizingInput, &ZoneSizingInputData::ZoneName);
    1545            0 :                                         if (ObjIndex > 0) {
    1546            0 :                                             thisMechVentZone.ZoneDesignSpecOAObjName = state.dataSize->ZoneSizingInput(ObjIndex).DesignSpecOAObjName;
    1547            0 :                                             thisMechVentZone.ZoneDesignSpecOAObjIndex =
    1548            0 :                                                 state.dataSize->ZoneSizingInput(ObjIndex).ZoneDesignSpecOAIndex;
    1549              :                                         }
    1550              :                                     }
    1551              :                                 }
    1552              : 
    1553           14 :                                 if (state.dataMixedAir->DesignSpecZoneADObjIndex(groupNum) > 0) {
    1554              :                                     // new DCV inputs
    1555           14 :                                     thisMechVentZone.ZoneDesignSpecADObjName = state.dataMixedAir->DesignSpecZoneADObjName(groupNum);
    1556           14 :                                     thisMechVentZone.ZoneDesignSpecADObjIndex = state.dataMixedAir->DesignSpecZoneADObjIndex(groupNum);
    1557              :                                 } else {
    1558            0 :                                     if (state.dataGlobal->DoZoneSizing) {
    1559            0 :                                         int ObjIndex = Util::FindItemInList(
    1560            0 :                                             state.dataHeatBal->Zone(zoneNum2).Name, state.dataSize->ZoneSizingInput, &ZoneSizingInputData::ZoneName);
    1561            0 :                                         if (ObjIndex > 0) {
    1562              :                                             thisMechVentZone.ZoneDesignSpecADObjName =
    1563            0 :                                                 state.dataSize->ZoneSizingInput(ObjIndex).ZoneAirDistEffObjName;
    1564            0 :                                             thisMechVentZone.ZoneDesignSpecADObjIndex =
    1565            0 :                                                 state.dataSize->ZoneSizingInput(ObjIndex).ZoneAirDistributionIndex;
    1566              :                                         }
    1567              :                                     }
    1568              :                                 }
    1569              :                             }
    1570              :                         }
    1571              :                     }
    1572              :                 }
    1573              :             }
    1574              : 
    1575           54 :             if (MechVentZoneCount <= 0) {
    1576            0 :                 ShowSevereError(state,
    1577            0 :                                 format("{}{}=\"{}\", invalid input. At least one Zone or ZoneList Name must be entered.",
    1578              :                                        RoutineName,
    1579              :                                        CurrentModuleObject,
    1580            0 :                                        thisVentilationMechanical.Name));
    1581            0 :                 ErrorsFound = true;
    1582              :             }
    1583              : 
    1584              :             //   Overwrite previous number of zones with number that does not include duplicates
    1585           54 :             thisVentilationMechanical.NumofVentMechZones = MechVentZoneCount;
    1586              : 
    1587              :             // Loop over zones and fill OA and AD specs, if none were found, use defaults
    1588          459 :             for (int ventMechZoneNum = 1; ventMechZoneNum <= MechVentZoneCount; ++ventMechZoneNum) {
    1589          405 :                 auto &thisVentMechZone = thisVentilationMechanical.VentMechZone(ventMechZoneNum);
    1590          405 :                 int zoneOAReqObjIndex = thisVentMechZone.ZoneDesignSpecOAObjIndex;
    1591          405 :                 if (zoneOAReqObjIndex > 0) {
    1592          405 :                     auto const &curOARequirements(state.dataSize->OARequirements(zoneOAReqObjIndex));
    1593          405 :                     thisVentMechZone.ZoneOAAreaRate = curOARequirements.OAFlowPerArea;
    1594          405 :                     thisVentMechZone.ZoneOAPeopleRate = curOARequirements.OAFlowPerPerson;
    1595          405 :                     thisVentMechZone.ZoneOAFlowRate = curOARequirements.OAFlowPerZone;
    1596          405 :                     thisVentMechZone.ZoneOAACHRate = curOARequirements.OAFlowACH;
    1597          405 :                     thisVentMechZone.ZoneOAFlowMethod = curOARequirements.OAFlowMethod;
    1598          405 :                     thisVentMechZone.zoneOASched = curOARequirements.oaFlowFracSched;
    1599          405 :                     thisVentMechZone.oaPropCtlMinRateSched = curOARequirements.oaPropCtlMinRateSched;
    1600          405 :                     if (thisVentilationMechanical.SystemOAMethod == DataSizing::SysOAMethod::ProportionalControlDesOARate) {
    1601            3 :                         if (thisVentMechZone.ZoneOAPeopleRate == 0.0 && thisVentMechZone.ZoneOAAreaRate == 0.0) {
    1602            0 :                             ShowSevereError(
    1603              :                                 state,
    1604            0 :                                 format("{}{}=\"{}\", invalid input with System Outdoor Air Method = ProportionalControlBasedOnDesignOARate.",
    1605              :                                        RoutineName,
    1606              :                                        CurrentModuleObject,
    1607            0 :                                        thisVentilationMechanical.Name));
    1608            0 :                             ShowContinueError(state,
    1609              :                                               " The values of Outdoor Air Flow per Person and Outdoor Air Flow per Zone Floor Area in the same "
    1610              :                                               "object can not be zero.");
    1611            0 :                             ErrorsFound = true;
    1612              :                         }
    1613              :                     }
    1614              :                 } else { // use defaults
    1615            0 :                     thisVentMechZone.ZoneOAAreaRate = 0.0;
    1616              :                     // since this is case with no DesSpcOA object, cannot determine the method and default would be Flow/Person which should
    1617              :                     // default to this flow rate
    1618            0 :                     thisVentMechZone.ZoneOAPeopleRate = 0.00944;
    1619            0 :                     thisVentMechZone.ZoneOAFlowRate = 0.0;
    1620            0 :                     thisVentMechZone.ZoneOAACHRate = 0.0;
    1621            0 :                     thisVentMechZone.ZoneOAFlowMethod = OAFlowCalcMethod::PerPerson;
    1622            0 :                     thisVentMechZone.zoneOASched =
    1623            0 :                         Sched::GetScheduleAlwaysOn(state); // defaults to constant-1.0. TODO: what is this really suppoed to be?
    1624            0 :                     ShowWarningError(state, format("{}{}=\"{}", RoutineName, CurrentModuleObject, thisVentilationMechanical.Name));
    1625            0 :                     ShowContinueError(
    1626            0 :                         state, format("Cannot locate a matching DesignSpecification:OutdoorAir object for Zone=\"{}\".", thisVentMechZone.name));
    1627            0 :                     ShowContinueError(state, "Using default OA of 0.00944 m3/s-person and 0.0 m3/s-m2.");
    1628              :                 }
    1629          405 :                 int zoneAirDistObjIndex = thisVentMechZone.ZoneDesignSpecADObjIndex;
    1630          405 :                 if (zoneAirDistObjIndex > 0) {
    1631          405 :                     auto const &curZoneAirDistribution(state.dataSize->ZoneAirDistribution(zoneAirDistObjIndex));
    1632          405 :                     thisVentMechZone.ZoneADEffCooling = curZoneAirDistribution.ZoneADEffCooling;
    1633          405 :                     thisVentMechZone.ZoneADEffHeating = curZoneAirDistribution.ZoneADEffHeating;
    1634          405 :                     thisVentMechZone.zoneADEffSched = curZoneAirDistribution.zoneADEffSched;
    1635          405 :                     thisVentMechZone.ZoneSecondaryRecirculation = curZoneAirDistribution.ZoneSecondaryRecirculation;
    1636              :                 } else { // use defaults
    1637            0 :                     thisVentMechZone.ZoneADEffCooling = 1.0;
    1638            0 :                     thisVentMechZone.ZoneADEffHeating = 1.0;
    1639            0 :                     thisVentMechZone.ZoneSecondaryRecirculation = 0.0;
    1640            0 :                     ShowWarningError(state, format("{}{}=\"{}\"", RoutineName, CurrentModuleObject, thisVentilationMechanical.Name));
    1641            0 :                     ShowContinueError(
    1642              :                         state,
    1643            0 :                         format("Cannot locate a matching DesignSpecification:ZoneAirDistribution object for Zone=\"{}\".", thisVentMechZone.name));
    1644            0 :                     ShowContinueError(state, "Using default zone air distribution effectiveness of 1.0 for heating and cooling.");
    1645              :                 }
    1646              :             }
    1647           54 :             state.dataMixedAir->VentMechZoneOrListName.deallocate();
    1648           54 :             state.dataMixedAir->DesignSpecOAObjName.deallocate();
    1649           54 :             state.dataMixedAir->DesignSpecOAObjIndex.deallocate();
    1650           54 :             state.dataMixedAir->DesignSpecZoneADObjName.deallocate();
    1651           54 :             state.dataMixedAir->DesignSpecZoneADObjIndex.deallocate();
    1652              :         }
    1653              : 
    1654           80 :         for (int VentMechNum = 1; VentMechNum <= state.dataMixedAir->NumVentMechControllers; ++VentMechNum) {
    1655           54 :             auto &thisVentilationMechanical(state.dataMixedAir->VentilationMechanical(VentMechNum));
    1656          459 :             for (int jZone = 1; jZone <= thisVentilationMechanical.NumofVentMechZones; ++jZone) {
    1657          405 :                 auto &thisVentMechZone = thisVentilationMechanical.VentMechZone(jZone);
    1658          405 :                 if (thisVentilationMechanical.SystemOAMethod == DataSizing::SysOAMethod::ProportionalControlSchOcc) {
    1659            3 :                     if (thisVentMechZone.ZoneOAACHRate > 0.0 || thisVentMechZone.ZoneOAFlowRate > 0.0) {
    1660            0 :                         ShowWarningError(state,
    1661            0 :                                          format("{}=\"{}\", inappropriate outdoor air method", CurrentModuleObject, thisVentilationMechanical.Name));
    1662            0 :                         ShowContinueError(state,
    1663            0 :                                           format("Inappropriate method for Design Specification Outdoor Air Object Name=\"{}\".",
    1664            0 :                                                  thisVentMechZone.ZoneDesignSpecOAObjName));
    1665            0 :                         ShowContinueError(state, format("For Zone=\"{}\".", thisVentMechZone.name));
    1666            0 :                         ShowContinueError(state,
    1667              :                                           "Since System Outdoor Air Method= ProportionalControlBasedOnOccupancySchedule\", AirChanges/Hour or "
    1668              :                                           "Flow/Zone outdoor air methods are not valid. Simulation continues.... ");
    1669              :                     }
    1670              :                 }
    1671          405 :                 if (thisVentilationMechanical.SystemOAMethod == DataSizing::SysOAMethod::ProportionalControlDesOcc) {
    1672            3 :                     if (thisVentMechZone.ZoneOAACHRate > 0.0 || thisVentMechZone.ZoneOAFlowRate > 0.0) {
    1673            0 :                         ShowWarningError(state,
    1674            0 :                                          format("{}=\"{}\", inappropriate outdoor air method", CurrentModuleObject, thisVentilationMechanical.Name));
    1675            0 :                         ShowContinueError(state,
    1676            0 :                                           format("Inappropriate method for Design Specification Outdoor Air Object Name=\"{}\".",
    1677            0 :                                                  thisVentMechZone.ZoneDesignSpecOAObjName));
    1678            0 :                         ShowContinueError(state, format("For Zone=\"{}\".", thisVentMechZone.name));
    1679            0 :                         ShowContinueError(state,
    1680              :                                           "Since System Outdoor Air Method= ProportionalControlBasedOnDesignOccupancy\", AirChanges/Hour or "
    1681              :                                           "Flow/Zone outdoor air methods are not valid. Simulation continues.... ");
    1682              :                     }
    1683              :                 }
    1684              : 
    1685              :                 // Error check to see if a single duct air terminal is assigned to a zone that has zone secondary recirculation
    1686          405 :                 if (thisVentMechZone.ZoneSecondaryRecirculation > 0.0) {
    1687            5 :                     int ZoneNum = thisVentMechZone.zoneNum;
    1688            5 :                     if (ZoneNum > 0) {
    1689            5 :                         int EquipListIndex = state.dataZoneEquip->ZoneEquipConfig(ZoneNum).EquipListIndex;
    1690            5 :                         if (EquipListIndex > 0) {
    1691           15 :                             for (int EquipListNum = 1; EquipListNum <= state.dataZoneEquip->NumOfZoneEquipLists; ++EquipListNum) {
    1692           15 :                                 if (EquipListNum == EquipListIndex) {
    1693            5 :                                     for (int EquipNum = 1; EquipNum <= state.dataZoneEquip->ZoneEquipList(EquipListNum).NumOfEquipTypes; ++EquipNum) {
    1694            5 :                                         if (Util::SameString(state.dataZoneEquip->ZoneEquipList(EquipListNum).EquipTypeName(EquipNum),
    1695              :                                                              "ZONEHVAC:AIRDISTRIBUTIONUNIT")) {
    1696           15 :                                             for (int ADUNum = 1; ADUNum <= (int)state.dataDefineEquipment->AirDistUnit.size(); ++ADUNum) {
    1697           15 :                                                 if (Util::SameString(state.dataZoneEquip->ZoneEquipList(EquipListNum).EquipName(EquipNum),
    1698           15 :                                                                      state.dataDefineEquipment->AirDistUnit(ADUNum).Name)) {
    1699            5 :                                                     if ((state.dataDefineEquipment->AirDistUnit(ADUNum).EquipTypeEnum(EquipNum) ==
    1700            1 :                                                          DataDefineEquip::ZnAirLoopEquipType::SingleDuctVAVReheat) ||
    1701            1 :                                                         (state.dataDefineEquipment->AirDistUnit(ADUNum).EquipTypeEnum(EquipNum) ==
    1702            1 :                                                          DataDefineEquip::ZnAirLoopEquipType::SingleDuctConstVolNoReheat) ||
    1703            1 :                                                         (state.dataDefineEquipment->AirDistUnit(ADUNum).EquipTypeEnum(EquipNum) ==
    1704            1 :                                                          DataDefineEquip::ZnAirLoopEquipType::SingleDuctConstVolReheat) ||
    1705            1 :                                                         (state.dataDefineEquipment->AirDistUnit(ADUNum).EquipTypeEnum(EquipNum) ==
    1706            1 :                                                          DataDefineEquip::ZnAirLoopEquipType::SingleDuctVAVNoReheat) ||
    1707            1 :                                                         (state.dataDefineEquipment->AirDistUnit(ADUNum).EquipTypeEnum(EquipNum) ==
    1708            1 :                                                          DataDefineEquip::ZnAirLoopEquipType::SingleDuctVAVReheatVSFan) ||
    1709            1 :                                                         (state.dataDefineEquipment->AirDistUnit(ADUNum).EquipTypeEnum(EquipNum) ==
    1710            1 :                                                          DataDefineEquip::ZnAirLoopEquipType::SingleDuctCBVAVReheat) ||
    1711            1 :                                                         (state.dataDefineEquipment->AirDistUnit(ADUNum).EquipTypeEnum(EquipNum) ==
    1712            1 :                                                          DataDefineEquip::ZnAirLoopEquipType::SingleDuctCBVAVNoReheat) ||
    1713            1 :                                                         (state.dataDefineEquipment->AirDistUnit(ADUNum).EquipTypeEnum(EquipNum) ==
    1714            1 :                                                          DataDefineEquip::ZnAirLoopEquipType::SingleDuctConstVolCooledBeam) ||
    1715            1 :                                                         (state.dataDefineEquipment->AirDistUnit(ADUNum).EquipTypeEnum(EquipNum) ==
    1716            6 :                                                          DataDefineEquip::ZnAirLoopEquipType::SingleDuctConstVolFourPipeBeam) ||
    1717            1 :                                                         (state.dataDefineEquipment->AirDistUnit(ADUNum).EquipTypeEnum(EquipNum) ==
    1718              :                                                          DataDefineEquip::ZnAirLoopEquipType::DualDuctVAVOutdoorAir)) {
    1719            8 :                                                         ShowWarningError(state,
    1720            8 :                                                                          format("{}=\"{}\", inappropriate use of Zone secondary recirculation",
    1721              :                                                                                 CurrentModuleObject,
    1722            4 :                                                                                 thisVentilationMechanical.Name));
    1723            8 :                                                         ShowContinueError(state,
    1724              :                                                                           "A zone secondary recirculation fraction is specified for zone served by ");
    1725            8 :                                                         ShowContinueError(state,
    1726            8 :                                                                           format("...terminal unit \"{}\" , that indicates a single path system",
    1727            4 :                                                                                  state.dataDefineEquipment->AirDistUnit(ADUNum).Name));
    1728            4 :                                                         ShowContinueError(state, format("For Zone=\"{}\".", thisVentMechZone.name));
    1729            8 :                                                         ShowContinueError(state, "...The zone secondary recirculation for that zone was set to 0.0");
    1730            4 :                                                         thisVentMechZone.ZoneSecondaryRecirculation = 0.0;
    1731              :                                                     }
    1732            5 :                                                     goto EquipLoop_exit;
    1733              :                                                 }
    1734              :                                             }
    1735              :                                         }
    1736              :                                     }
    1737              :                                 }
    1738              :                             }
    1739            5 :                         EquipLoop_exit:;
    1740              :                         }
    1741              :                     }
    1742              :                 }
    1743          405 :                 if (thisVentMechZone.ZoneDesignSpecOAObjName.empty()) {
    1744            0 :                     ShowSevereError(
    1745              :                         state,
    1746            0 :                         format("{}=\"{}\", Design Specification Outdoor Air Object Name blank", CurrentModuleObject, thisVentilationMechanical.Name));
    1747            0 :                     ShowContinueError(state, format("For Zone=\"{}\".", thisVentMechZone.name));
    1748            0 :                     ShowContinueError(state, "This field either needs to be filled in in this object or Sizing:Zone object.");
    1749            0 :                     ShowContinueError(state, "For this run, default values for these fields will be used.");
    1750              :                 }
    1751          405 :                 if (thisVentMechZone.ZoneOAPeopleRate <= 0.0 && thisVentilationMechanical.DCVFlag) {
    1752            2 :                     ShowWarningError(state, format("{}=\"{}\", Zone OA/person rate", CurrentModuleObject, thisVentilationMechanical.Name));
    1753            2 :                     ShowContinueError(state, format("For Zone=\"{}\".", thisVentMechZone.name));
    1754            4 :                     ShowContinueError(state,
    1755            4 :                                       format("Zone outside air per person rate not set in Design Specification Outdoor Air Object=\"{}\".",
    1756            2 :                                              thisVentMechZone.ZoneDesignSpecOAObjName));
    1757              :                 }
    1758              : 
    1759          405 :                 if (thisVentMechZone.ZoneOAAreaRate < 0.0) {
    1760            0 :                     ShowSevereError(state,
    1761            0 :                                     format("{}=\"{}\", invalid Outdoor Air flow per area", CurrentModuleObject, thisVentilationMechanical.Name));
    1762            0 :                     ShowContinueError(state, format("For Zone=\"{}\".", thisVentMechZone.name));
    1763            0 :                     ShowContinueError(state,
    1764            0 :                                       format("invalid Outdoor Air flow per area specified in object=\"{}\". Value must be >= 0.0.",
    1765            0 :                                              thisVentMechZone.ZoneDesignSpecOAObjName));
    1766            0 :                     ErrorsFound = true;
    1767              :                 }
    1768          405 :                 if (thisVentMechZone.ZoneOAPeopleRate < 0.0) {
    1769            0 :                     ShowSevereError(state,
    1770            0 :                                     format("{}=\"{}\", invalid Outdoor Air flow per person", CurrentModuleObject, thisVentilationMechanical.Name));
    1771            0 :                     ShowContinueError(state, format("For Zone=\"{}\".", thisVentMechZone.name));
    1772            0 :                     ShowContinueError(state,
    1773            0 :                                       format("invalid Outdoor Air flow per person specified in object \"{}\". Value must be >= 0.0.",
    1774            0 :                                              thisVentMechZone.ZoneDesignSpecOAObjName));
    1775            0 :                     ErrorsFound = true;
    1776              :                 }
    1777              :             }
    1778              :         }
    1779              : 
    1780              :         // Link OA controller object with mechanical ventilation object
    1781          115 :         for (int OAControllerNum = 1; OAControllerNum <= state.dataMixedAir->NumOAControllers; ++OAControllerNum) {
    1782           89 :             state.dataMixedAir->OAController(OAControllerNum).VentMechObjectNum = Util::FindItemInList(
    1783           89 :                 state.dataMixedAir->OAController(OAControllerNum).VentilationMechanicalName, state.dataMixedAir->VentilationMechanical);
    1784          124 :             if (state.dataMixedAir->OAController(OAControllerNum).VentMechObjectNum == 0 &&
    1785           35 :                 !state.dataMixedAir->OAController(OAControllerNum).VentilationMechanicalName.empty()) {
    1786            0 :                 ShowSevereError(state,
    1787            0 :                                 format("{}=\"{}\", non-match to Controller:OutdoorAir",
    1788              :                                        CurrentModuleObject,
    1789            0 :                                        state.dataMixedAir->OAController(OAControllerNum).VentilationMechanicalName));
    1790            0 :                 ShowContinueError(
    1791            0 :                     state, format("Invalid specified in Controller:OutdoorAir object = {}", state.dataMixedAir->OAController(OAControllerNum).Name));
    1792            0 :                 ShowContinueError(state,
    1793            0 :                                   format("{} object name must match the {} object name specified in Controller:OutdoorAir.",
    1794              :                                          CurrentModuleObject,
    1795              :                                          CurrentModuleObject));
    1796            0 :                 ErrorsFound = true;
    1797              :             }
    1798              :         }
    1799              : 
    1800              :         // write to .eio file
    1801              :         static constexpr std::string_view Format_700(
    1802              :             "!<Controller:MechanicalVentilation>,Name,Availability Schedule Name,Demand Controlled Ventilation "
    1803              :             "{Yes/No},System Outdoor Air Method,Zone Maximum Outdoor Air Fraction,Number of Zones,Zone Name,DSOA "
    1804              :             "Name,DSZAD Name");
    1805           26 :         print(state.files.eio, "{}\n", Format_700);
    1806           80 :         for (auto const &ventMech : state.dataMixedAir->VentilationMechanical) {
    1807           54 :             print(state.files.eio, " Controller:MechanicalVentilation,{},{},", ventMech.Name, ventMech.availSched ? ventMech.availSched->Name : "");
    1808              : 
    1809           54 :             print(state.files.eio, format("{},", yesNoNames[(int)ventMech.DCVFlag]));
    1810              : 
    1811           54 :             if (ventMech.SystemOAMethod != DataSizing::SysOAMethod::Invalid) {
    1812           54 :                 print(state.files.eio, printSysOAMethod[(int)ventMech.SystemOAMethod]);
    1813              :             } else {
    1814            0 :                 print(state.files.eio, "Invalid/Unknown,");
    1815              :             }
    1816              : 
    1817           54 :             print(state.files.eio, "{:.2R},", ventMech.ZoneMaxOAFraction);
    1818           54 :             print(state.files.eio, "{},", ventMech.NumofVentMechZones);
    1819              : 
    1820          459 :             for (int jZone = 1; jZone <= ventMech.NumofVentMechZones; ++jZone) {
    1821          405 :                 auto &thisVentMechZone = ventMech.VentMechZone(jZone);
    1822          405 :                 if (jZone < ventMech.NumofVentMechZones) {
    1823          351 :                     print(state.files.eio,
    1824              :                           "{},{},{},",
    1825          351 :                           state.dataHeatBal->Zone(thisVentMechZone.zoneNum).Name,
    1826          351 :                           thisVentMechZone.ZoneDesignSpecOAObjName,
    1827          351 :                           thisVentMechZone.ZoneDesignSpecADObjName);
    1828              :                 } else {
    1829           54 :                     print(state.files.eio,
    1830              :                           "{},{},{}\n",
    1831           54 :                           state.dataHeatBal->Zone(thisVentMechZone.zoneNum).Name,
    1832           54 :                           thisVentMechZone.ZoneDesignSpecOAObjName,
    1833           54 :                           thisVentMechZone.ZoneDesignSpecADObjName);
    1834              :                 }
    1835              :             }
    1836           26 :         }
    1837              : 
    1838              :     } // Number of Mechanical Ventilation Objects > 0
    1839              : 
    1840          413 :     AlphArray.deallocate();
    1841          413 :     NumArray.deallocate();
    1842          413 :     lNumericBlanks.deallocate();
    1843          413 :     lAlphaBlanks.deallocate();
    1844          413 :     cAlphaFields.deallocate();
    1845          413 :     cNumericFields.deallocate();
    1846              : 
    1847          413 :     if (ErrorsFound) {
    1848            0 :         ShowFatalError(state, format("{}Errors found when getting {} inputs.", RoutineName, CurrentModuleObject));
    1849              :     }
    1850          413 : }
    1851              : 
    1852          416 : void AllocateOAControllers(EnergyPlusData &state)
    1853              : {
    1854              :     // PURPOSE OF THIS SUBROUTINE:
    1855              :     // Allocate the OA controller arrays which are shared by Controller:OutdoorAir and ZoneHVAC:EnergyRecoveryVentilator:Controller
    1856              : 
    1857          416 :     if (state.dataMixedAir->AllocateOAControllersFlag) {
    1858          828 :         state.dataMixedAir->NumOAControllers =
    1859          414 :             state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObjects[static_cast<int>(CMO::OAController)]);
    1860          828 :         state.dataMixedAir->NumERVControllers =
    1861          414 :             state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObjects[static_cast<int>(CMO::ERVController)]);
    1862          414 :         state.dataMixedAir->NumOAControllers += state.dataMixedAir->NumERVControllers;
    1863          414 :         state.dataMixedAir->OAController.allocate(state.dataMixedAir->NumOAControllers);
    1864          414 :         state.dataMixedAir->OAControllerUniqueNames.reserve(static_cast<unsigned>(state.dataMixedAir->NumOAControllers));
    1865          414 :         state.dataMixedAir->AllocateOAControllersFlag = false;
    1866              :     }
    1867          416 : }
    1868              : 
    1869          456 : void GetOAMixerInputs(EnergyPlusData &state)
    1870              : {
    1871              : 
    1872              :     // SUBROUTINE INFORMATION:
    1873              :     //       AUTHOR         Fred Buhl
    1874              :     //       DATE WRITTEN   Oct 1998
    1875              : 
    1876              :     // PURPOSE OF THIS SUBROUTINE
    1877              :     // Input the OAMixer data and store it in the OAMixer array.
    1878              : 
    1879              :     // METHODOLOGY EMPLOYED:
    1880              :     // Use the Get routines from the InputProcessor module.
    1881              : 
    1882              :     // SUBROUTINE PARAMETER DEFINITIONS:
    1883              :     static constexpr std::string_view RoutineName("GetOAMixerInputs: "); // include trailing blank space
    1884              : 
    1885              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    1886              : 
    1887              :     int NumNums;                   // Number of REAL(r64) numbers returned by GetObjectItem
    1888              :     int NumAlphas;                 // Number of alphanumerics returned by GetObjectItem
    1889              :     int NumArg;                    // Number of arguments from GetObjectDefMaxArgs call
    1890          456 :     Array1D<Real64> NumArray;      // array that holds numeric input values
    1891          456 :     Array1D_string AlphArray;      // array that holds alpha input values
    1892          456 :     Array1D_string cAlphaFields;   // Alpha field names
    1893          456 :     Array1D_string cNumericFields; // Numeric field names
    1894          456 :     Array1D_bool lAlphaBlanks;     // Logical array, alpha field input BLANK = .TRUE.
    1895          456 :     Array1D_bool lNumericBlanks;   // Logical array, numeric field input BLANK = .TRUE.
    1896          456 :     bool ErrorsFound(false);
    1897              : 
    1898          456 :     if (!state.dataMixedAir->GetOAMixerInputFlag) {
    1899            0 :         return;
    1900              :     }
    1901              : 
    1902          912 :     state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(
    1903          456 :         state, CurrentModuleObjects[static_cast<int>(CMO::OAMixer)], NumArg, NumAlphas, NumNums);
    1904              : 
    1905          456 :     AlphArray.allocate(NumAlphas);
    1906          456 :     NumArray.dimension(NumNums, 0.0);
    1907          456 :     lNumericBlanks.dimension(NumNums, true);
    1908          456 :     lAlphaBlanks.dimension(NumAlphas, true);
    1909          456 :     cAlphaFields.allocate(NumAlphas);
    1910          456 :     cNumericFields.allocate(NumNums);
    1911              : 
    1912          456 :     std::string_view const CurrentModuleObject = CurrentModuleObjects[static_cast<int>(CMO::OAMixer)];
    1913              : 
    1914          456 :     state.dataMixedAir->NumOAMixers = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject);
    1915              : 
    1916          456 :     if (state.dataMixedAir->NumOAMixers > 0) {
    1917              : 
    1918          456 :         state.dataMixedAir->OAMixer.allocate(state.dataMixedAir->NumOAMixers);
    1919              :         int IOStat;
    1920              : 
    1921         1975 :         for (int OutAirNum = 1; OutAirNum <= state.dataMixedAir->NumOAMixers; ++OutAirNum) {
    1922         1519 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
    1923              :                                                                      CurrentModuleObject,
    1924              :                                                                      OutAirNum,
    1925              :                                                                      AlphArray,
    1926              :                                                                      NumAlphas,
    1927              :                                                                      NumArray,
    1928              :                                                                      NumNums,
    1929              :                                                                      IOStat,
    1930              :                                                                      lNumericBlanks,
    1931              :                                                                      lAlphaBlanks,
    1932              :                                                                      cAlphaFields,
    1933              :                                                                      cNumericFields);
    1934              :             // no need to check if AlphaArray(1) is empty since Json will catch missing required fields
    1935         1519 :             state.dataMixedAir->OAMixer(OutAirNum).Name = AlphArray(1);
    1936         3038 :             state.dataMixedAir->OAMixer(OutAirNum).MixNode = NodeInputManager::GetOnlySingleNode(state,
    1937         1519 :                                                                                                  AlphArray(2),
    1938              :                                                                                                  ErrorsFound,
    1939              :                                                                                                  DataLoopNode::ConnectionObjectType::OutdoorAirMixer,
    1940         1519 :                                                                                                  AlphArray(1),
    1941              :                                                                                                  DataLoopNode::NodeFluidType::Air,
    1942              :                                                                                                  DataLoopNode::ConnectionType::Outlet,
    1943              :                                                                                                  NodeInputManager::CompFluidStream::Primary,
    1944              :                                                                                                  ObjectIsNotParent);
    1945              :             //  Set connection type to 'Inlet', because this is not necessarily directly from
    1946              :             //  outside air.  Outside Air Inlet Node List will set the connection to outside air
    1947         1519 :             state.dataMixedAir->OAMixer(OutAirNum).InletNode =
    1948         3038 :                 NodeInputManager::GetOnlySingleNode(state,
    1949         1519 :                                                     AlphArray(3),
    1950              :                                                     ErrorsFound,
    1951              :                                                     DataLoopNode::ConnectionObjectType::OutdoorAirMixer,
    1952         1519 :                                                     AlphArray(1),
    1953              :                                                     DataLoopNode::NodeFluidType::Air,
    1954              :                                                     DataLoopNode::ConnectionType::Inlet,
    1955              :                                                     NodeInputManager::CompFluidStream::Primary,
    1956              :                                                     ObjectIsNotParent);
    1957         3038 :             state.dataMixedAir->OAMixer(OutAirNum).RelNode = NodeInputManager::GetOnlySingleNode(state,
    1958         1519 :                                                                                                  AlphArray(4),
    1959              :                                                                                                  ErrorsFound,
    1960              :                                                                                                  DataLoopNode::ConnectionObjectType::OutdoorAirMixer,
    1961         1519 :                                                                                                  AlphArray(1),
    1962              :                                                                                                  DataLoopNode::NodeFluidType::Air,
    1963              :                                                                                                  DataLoopNode::ConnectionType::ReliefAir,
    1964              :                                                                                                  NodeInputManager::CompFluidStream::Primary,
    1965              :                                                                                                  ObjectIsNotParent);
    1966         3038 :             state.dataMixedAir->OAMixer(OutAirNum).RetNode = NodeInputManager::GetOnlySingleNode(state,
    1967         1519 :                                                                                                  AlphArray(5),
    1968              :                                                                                                  ErrorsFound,
    1969              :                                                                                                  DataLoopNode::ConnectionObjectType::OutdoorAirMixer,
    1970         1519 :                                                                                                  AlphArray(1),
    1971              :                                                                                                  DataLoopNode::NodeFluidType::Air,
    1972              :                                                                                                  DataLoopNode::ConnectionType::Inlet,
    1973              :                                                                                                  NodeInputManager::CompFluidStream::Primary,
    1974              :                                                                                                  ObjectIsNotParent);
    1975              :             // Check for dupes in the four nodes.
    1976         1519 :             if (state.dataMixedAir->OAMixer(OutAirNum).MixNode == state.dataMixedAir->OAMixer(OutAirNum).InletNode) {
    1977            0 :                 ShowSevereError(state,
    1978            0 :                                 format("{} = {} {} = {} duplicates the {}.",
    1979              :                                        CurrentModuleObject,
    1980            0 :                                        state.dataMixedAir->OAMixer(OutAirNum).Name,
    1981              :                                        cAlphaFields(3),
    1982            0 :                                        state.dataLoopNodes->NodeID(state.dataMixedAir->OAMixer(OutAirNum).InletNode),
    1983              :                                        cAlphaFields(2)));
    1984            0 :                 ErrorsFound = true;
    1985         1519 :             } else if (state.dataMixedAir->OAMixer(OutAirNum).MixNode == state.dataMixedAir->OAMixer(OutAirNum).RelNode) {
    1986            0 :                 ShowSevereError(state,
    1987            0 :                                 format("{} = {} {} = {} duplicates the {}.",
    1988              :                                        CurrentModuleObject,
    1989            0 :                                        state.dataMixedAir->OAMixer(OutAirNum).Name,
    1990              :                                        cAlphaFields(4),
    1991            0 :                                        state.dataLoopNodes->NodeID(state.dataMixedAir->OAMixer(OutAirNum).RelNode),
    1992              :                                        cAlphaFields(2)));
    1993            0 :                 ErrorsFound = true;
    1994         1519 :             } else if (state.dataMixedAir->OAMixer(OutAirNum).MixNode == state.dataMixedAir->OAMixer(OutAirNum).RetNode) {
    1995            0 :                 ShowSevereError(state,
    1996            0 :                                 format("{} = {} {} = {} duplicates the {}.",
    1997              :                                        CurrentModuleObject,
    1998            0 :                                        state.dataMixedAir->OAMixer(OutAirNum).Name,
    1999              :                                        cAlphaFields(5),
    2000            0 :                                        state.dataLoopNodes->NodeID(state.dataMixedAir->OAMixer(OutAirNum).RetNode),
    2001              :                                        cAlphaFields(2)));
    2002            0 :                 ErrorsFound = true;
    2003              :             }
    2004              : 
    2005         1519 :             if (state.dataMixedAir->OAMixer(OutAirNum).InletNode == state.dataMixedAir->OAMixer(OutAirNum).RelNode) {
    2006            0 :                 ShowSevereError(state,
    2007            0 :                                 format("{} = {} {} = {} duplicates the {}.",
    2008              :                                        CurrentModuleObject,
    2009            0 :                                        state.dataMixedAir->OAMixer(OutAirNum).Name,
    2010              :                                        cAlphaFields(4),
    2011            0 :                                        state.dataLoopNodes->NodeID(state.dataMixedAir->OAMixer(OutAirNum).RelNode),
    2012              :                                        cAlphaFields(3)));
    2013            0 :                 ErrorsFound = true;
    2014         1519 :             } else if (state.dataMixedAir->OAMixer(OutAirNum).InletNode == state.dataMixedAir->OAMixer(OutAirNum).RetNode) {
    2015            0 :                 ShowSevereError(state,
    2016            0 :                                 format("{} = {} {} = {} duplicates the {}.",
    2017              :                                        CurrentModuleObject,
    2018            0 :                                        state.dataMixedAir->OAMixer(OutAirNum).Name,
    2019              :                                        cAlphaFields(5),
    2020            0 :                                        state.dataLoopNodes->NodeID(state.dataMixedAir->OAMixer(OutAirNum).RetNode),
    2021              :                                        cAlphaFields(3)));
    2022            0 :                 ErrorsFound = true;
    2023              :             }
    2024              : 
    2025         1519 :             if (state.dataMixedAir->OAMixer(OutAirNum).RelNode == state.dataMixedAir->OAMixer(OutAirNum).RetNode) {
    2026            0 :                 ShowSevereError(state,
    2027            0 :                                 format("{} = {} {} = {} duplicates the {}.",
    2028              :                                        CurrentModuleObject,
    2029            0 :                                        state.dataMixedAir->OAMixer(OutAirNum).Name,
    2030              :                                        cAlphaFields(5),
    2031            0 :                                        state.dataLoopNodes->NodeID(state.dataMixedAir->OAMixer(OutAirNum).RetNode),
    2032              :                                        cAlphaFields(4)));
    2033            0 :                 ErrorsFound = true;
    2034              :             }
    2035         4557 :             BranchNodeConnections::TestCompSet(
    2036         1519 :                 state, CurrentModuleObject, state.dataMixedAir->OAMixer(OutAirNum).Name, AlphArray(3), AlphArray(2), "Air Nodes");
    2037              :         }
    2038              :     }
    2039              : 
    2040          456 :     if (ErrorsFound) {
    2041            0 :         ShowFatalError(state, format("{}Errors found in getting {}", RoutineName, CurrentModuleObject));
    2042              :     }
    2043              : 
    2044          456 :     state.dataMixedAir->GetOAMixerInputFlag = false;
    2045          456 : }
    2046              : 
    2047         1067 : void ProcessOAControllerInputs(EnergyPlusData &state,
    2048              :                                std::string_view const CurrentModuleObject,
    2049              :                                int const OutAirNum,
    2050              :                                Array1D_string const &AlphArray,
    2051              :                                int const NumAlphas,
    2052              :                                Array1D<Real64> const &NumArray,
    2053              :                                int const NumNums,
    2054              :                                Array1D_bool const &lNumericBlanks, // Unused
    2055              :                                Array1D_bool const &lAlphaBlanks,
    2056              :                                Array1D_string const &cAlphaFields,
    2057              :                                Array1D_string const &cNumericFields, // Unused
    2058              :                                bool &ErrorsFound                     // If errors found in input
    2059              : )
    2060              : {
    2061              : 
    2062              :     // SUBROUTINE INFORMATION:
    2063              :     //       AUTHOR         Fred Buhl
    2064              :     //       DATE WRITTEN   Oct 1998
    2065              :     //       MODIFIED       Shirey/Raustad FSEC, June 2003, Jan 2004
    2066              :     //                      Mangesh Basarkar, 06/2011: Getting zone OA specifications from Design Specification Object
    2067              :     //                      Tianzhen Hong, 3/2012: getting zone air distribution effectiveness and secondary recirculation
    2068              :     //                       from DesignSpecification:ZoneAirDistribution objects
    2069              :     //       RE-ENGINEERED  MJW: Split out processing controller:outdoorair input to facilitate unit testing, Feb 2015
    2070              : 
    2071              :     // PURPOSE OF THIS SUBROUTINE
    2072              :     // Input the OAController data and store it in the OAController array.
    2073              : 
    2074              :     // SUBROUTINE PARAMETER DEFINITIONS:
    2075              :     static constexpr std::string_view RoutineName("GetOAControllerInputs: "); // include trailing blank space
    2076              :     static constexpr std::string_view routineName = "GetOAControllerInputs";
    2077              : 
    2078         1067 :     ErrorObjectHeader eoh{routineName, CurrentModuleObject, AlphArray(1)};
    2079              : 
    2080         1067 :     state.dataMixedAir->OAController(OutAirNum).Name = AlphArray(1);
    2081         1067 :     state.dataMixedAir->OAController(OutAirNum).ControllerType = MixedAirControllerType::ControllerOutsideAir;
    2082         1067 :     state.dataMixedAir->OAController(OutAirNum).MaxOA = NumArray(2);
    2083         1067 :     state.dataMixedAir->OAController(OutAirNum).MinOA = NumArray(1);
    2084         1067 :     state.dataMixedAir->OAController(OutAirNum).MixNode =
    2085         2134 :         NodeInputManager::GetOnlySingleNode(state,
    2086         1067 :                                             AlphArray(4),
    2087              :                                             ErrorsFound,
    2088              :                                             DataLoopNode::ConnectionObjectType::ControllerOutdoorAir,
    2089         1067 :                                             AlphArray(1),
    2090              :                                             DataLoopNode::NodeFluidType::Air,
    2091              :                                             DataLoopNode::ConnectionType::Sensor,
    2092              :                                             NodeInputManager::CompFluidStream::Primary,
    2093              :                                             ObjectIsNotParent);
    2094         2134 :     state.dataMixedAir->OAController(OutAirNum).OANode = NodeInputManager::GetOnlySingleNode(state,
    2095         1067 :                                                                                              AlphArray(5),
    2096              :                                                                                              ErrorsFound,
    2097              :                                                                                              DataLoopNode::ConnectionObjectType::ControllerOutdoorAir,
    2098         1067 :                                                                                              AlphArray(1),
    2099              :                                                                                              DataLoopNode::NodeFluidType::Air,
    2100              :                                                                                              DataLoopNode::ConnectionType::Actuator,
    2101              :                                                                                              NodeInputManager::CompFluidStream::Primary,
    2102              :                                                                                              ObjectIsNotParent);
    2103         1067 :     if (!OutAirNodeManager::CheckOutAirNodeNumber(state, state.dataMixedAir->OAController(OutAirNum).OANode)) {
    2104            0 :         ShowWarningError(state,
    2105            0 :                          format("{}=\"{}\": {}=\"{}\" is not an OutdoorAir:Node.", CurrentModuleObject, AlphArray(1), cAlphaFields(5), AlphArray(5)));
    2106            0 :         ShowContinueError(state, "Confirm that this is the intended source for the outdoor air stream.");
    2107              :     }
    2108         1067 :     if (Util::SameString(AlphArray(6), "NoEconomizer")) {
    2109          531 :         state.dataMixedAir->OAController(OutAirNum).Econo = EconoOp::NoEconomizer;
    2110          536 :     } else if (Util::SameString(AlphArray(6), "FixedDryBulb")) {
    2111          130 :         state.dataMixedAir->OAController(OutAirNum).Econo = EconoOp::FixedDryBulb;
    2112          406 :     } else if (Util::SameString(AlphArray(6), "FixedEnthalpy")) {
    2113            0 :         state.dataMixedAir->OAController(OutAirNum).Econo = EconoOp::FixedEnthalpy;
    2114          406 :     } else if (Util::SameString(AlphArray(6), "FixedDewPointAndDryBulb")) {
    2115            0 :         state.dataMixedAir->OAController(OutAirNum).Econo = EconoOp::FixedDewPointAndDryBulb;
    2116          406 :     } else if (Util::SameString(AlphArray(6), "DifferentialDryBulb")) {
    2117          374 :         state.dataMixedAir->OAController(OutAirNum).Econo = EconoOp::DifferentialDryBulb;
    2118           32 :     } else if (Util::SameString(AlphArray(6), "DifferentialEnthalpy")) {
    2119           25 :         state.dataMixedAir->OAController(OutAirNum).Econo = EconoOp::DifferentialEnthalpy;
    2120            7 :     } else if (Util::SameString(AlphArray(6), "DifferentialDryBulbAndEnthalpy")) {
    2121            0 :         state.dataMixedAir->OAController(OutAirNum).Econo = EconoOp::DifferentialDryBulbAndEnthalpy;
    2122            7 :     } else if (Util::SameString(AlphArray(6), "ElectronicEnthalpy")) {
    2123            7 :         state.dataMixedAir->OAController(OutAirNum).Econo = EconoOp::ElectronicEnthalpy;
    2124              :     } else {
    2125            0 :         ShowSevereError(state, format("{}=\"{}\" invalid {}=\"{}\" value.", CurrentModuleObject, AlphArray(1), cAlphaFields(6), AlphArray(6)));
    2126            0 :         ErrorsFound = true;
    2127              :     }
    2128              :     // Bypass choice - Added by Amit for new feature implementation
    2129         1067 :     if (Util::SameString(AlphArray(7), "ModulateFlow")) {
    2130         1050 :         state.dataMixedAir->OAController(OutAirNum).EconBypass = false;
    2131           17 :     } else if (Util::SameString(AlphArray(7), "MinimumFlowWithBypass")) {
    2132           17 :         state.dataMixedAir->OAController(OutAirNum).EconBypass = true;
    2133              :     } else {
    2134            0 :         ShowSevereError(state, format("{}=\"{}\" invalid {}=\"{}\" value.", CurrentModuleObject, AlphArray(1), cAlphaFields(7), AlphArray(7)));
    2135            0 :         ErrorsFound = true;
    2136              :     }
    2137              : 
    2138         1067 :     if (Util::SameString(AlphArray(9), "NoLockout")) {
    2139          825 :         state.dataMixedAir->OAController(OutAirNum).Lockout = LockoutType::NoLockoutPossible;
    2140          242 :     } else if (Util::SameString(AlphArray(9), "LockoutWithHeating")) {
    2141          201 :         state.dataMixedAir->OAController(OutAirNum).Lockout = LockoutType::LockoutWithHeatingPossible;
    2142           41 :     } else if (Util::SameString(AlphArray(9), "LockoutWithCompressor")) {
    2143           41 :         state.dataMixedAir->OAController(OutAirNum).Lockout = LockoutType::LockoutWithCompressorPossible;
    2144              :     } else {
    2145            0 :         ShowSevereError(state, format("{}=\"{}\" invalid {}=\"{}\" value.", CurrentModuleObject, AlphArray(1), cAlphaFields(9), AlphArray(9)));
    2146            0 :         ErrorsFound = true;
    2147              :     }
    2148         1067 :     if (Util::SameString(AlphArray(10), "FixedMinimum")) {
    2149         1024 :         state.dataMixedAir->OAController(OutAirNum).FixedMin = true;
    2150              :     } else {
    2151           43 :         state.dataMixedAir->OAController(OutAirNum).FixedMin = false;
    2152              :     }
    2153         1067 :     if (lNumericBlanks(3)) {
    2154          297 :         state.dataMixedAir->OAController(OutAirNum).TempLim = HVAC::BlankNumeric;
    2155              :     } else {
    2156          770 :         state.dataMixedAir->OAController(OutAirNum).TempLim = NumArray(3);
    2157              :     }
    2158              : 
    2159         1067 :     if (lNumericBlanks(4)) {
    2160          651 :         state.dataMixedAir->OAController(OutAirNum).EnthLim = HVAC::BlankNumeric;
    2161              :     } else {
    2162          416 :         state.dataMixedAir->OAController(OutAirNum).EnthLim = NumArray(4);
    2163              :     }
    2164         1067 :     if (lNumericBlanks(5)) {
    2165         1052 :         state.dataMixedAir->OAController(OutAirNum).DPTempLim = HVAC::BlankNumeric;
    2166              :     } else {
    2167           15 :         state.dataMixedAir->OAController(OutAirNum).DPTempLim = NumArray(5);
    2168              :     }
    2169              : 
    2170         1067 :     if (lNumericBlanks(6)) {
    2171          370 :         state.dataMixedAir->OAController(OutAirNum).TempLowLim = HVAC::BlankNumeric;
    2172              :     } else {
    2173          697 :         state.dataMixedAir->OAController(OutAirNum).TempLowLim = NumArray(6);
    2174              :     }
    2175              : 
    2176         1067 :     if (!lAlphaBlanks(8)) {
    2177            7 :         state.dataMixedAir->OAController(OutAirNum).EnthalpyCurvePtr = Curve::GetCurveIndex(state, AlphArray(8)); // convert curve name to number
    2178            7 :         if (state.dataMixedAir->OAController(OutAirNum).EnthalpyCurvePtr == 0) {
    2179            0 :             ShowSevereError(state,
    2180            0 :                             format("{}=\"{}\" invalid {}=\"{}\" not found.", CurrentModuleObject, AlphArray(1), cAlphaFields(8), AlphArray(8)));
    2181            0 :             ErrorsFound = true;
    2182              :         } else {
    2183              :             // Verify Curve Object, only legal types are Quadratic and Cubic
    2184           28 :             ErrorsFound |= Curve::CheckCurveDims(state,
    2185            7 :                                                  state.dataMixedAir->OAController(OutAirNum).EnthalpyCurvePtr, // Curve index
    2186              :                                                  {1},                                                          // Valid dimensions
    2187              :                                                  RoutineName,                                                  // Routine name
    2188              :                                                  CurrentModuleObject,                                          // Object Type
    2189            7 :                                                  state.dataMixedAir->OAController(OutAirNum).Name,             // Object Name
    2190            7 :                                                  cAlphaFields(8));                                             // Field Name
    2191              :         }
    2192              :     }
    2193              : 
    2194         1067 :     state.dataMixedAir->OAController(OutAirNum).RelNode =
    2195         2134 :         NodeInputManager::GetOnlySingleNode(state,
    2196         1067 :                                             AlphArray(2),
    2197              :                                             ErrorsFound,
    2198              :                                             DataLoopNode::ConnectionObjectType::ControllerOutdoorAir,
    2199         1067 :                                             AlphArray(1),
    2200              :                                             DataLoopNode::NodeFluidType::Air,
    2201              :                                             DataLoopNode::ConnectionType::Actuator,
    2202              :                                             NodeInputManager::CompFluidStream::Primary,
    2203              :                                             ObjectIsNotParent);
    2204         1067 :     state.dataMixedAir->OAController(OutAirNum).RetNode =
    2205         2134 :         NodeInputManager::GetOnlySingleNode(state,
    2206         1067 :                                             AlphArray(3),
    2207              :                                             ErrorsFound,
    2208              :                                             DataLoopNode::ConnectionObjectType::ControllerOutdoorAir,
    2209         1067 :                                             AlphArray(1),
    2210              :                                             DataLoopNode::NodeFluidType::Air,
    2211              :                                             DataLoopNode::ConnectionType::Sensor,
    2212              :                                             NodeInputManager::CompFluidStream::Primary,
    2213              :                                             ObjectIsNotParent);
    2214              : 
    2215         1067 :     if (lAlphaBlanks(11)) {
    2216          994 :     } else if ((state.dataMixedAir->OAController(OutAirNum).minOASched = Sched::GetSchedule(state, AlphArray(11))) == nullptr) {
    2217            0 :         ShowSevereItemNotFound(state, eoh, cAlphaFields(11), AlphArray(11));
    2218            0 :         ErrorsFound = true;
    2219              :     }
    2220              : 
    2221              :     // Changed by Amit for new feature implementation
    2222         1067 :     if (lAlphaBlanks(12)) {
    2223           45 :     } else if ((state.dataMixedAir->OAController(OutAirNum).minOAflowSched = Sched::GetSchedule(state, AlphArray(12))) == nullptr) {
    2224            0 :         ShowSevereItemNotFound(state, eoh, cAlphaFields(12), AlphArray(12));
    2225            0 :         ErrorsFound = true;
    2226              :     }
    2227              : 
    2228         1067 :     if (lAlphaBlanks(13)) {
    2229           59 :     } else if ((state.dataMixedAir->OAController(OutAirNum).maxOAflowSched = Sched::GetSchedule(state, AlphArray(13))) == nullptr) {
    2230            0 :         ShowSevereItemNotFound(state, eoh, cAlphaFields(13), AlphArray(13));
    2231            0 :         ErrorsFound = true;
    2232              :     }
    2233         1067 :     state.dataMixedAir->OAController(OutAirNum).VentilationMechanicalName = AlphArray(14);
    2234              : 
    2235              :     //   Check for a time of day economizer control schedule
    2236         1067 :     state.dataMixedAir->OAController(OutAirNum).economizerOASched = Sched::GetSchedule(state, AlphArray(15));
    2237              : 
    2238              :     //   High humidity control option can be used with any economizer flag
    2239         1067 :     if (Util::SameString(AlphArray(16), "Yes")) {
    2240              : 
    2241            6 :         state.dataMixedAir->OAController(OutAirNum).HumidistatZoneNum = Util::FindItemInList(AlphArray(17), state.dataHeatBal->Zone);
    2242              : 
    2243              :         // Get the node number for the zone with the humidistat
    2244            6 :         if (state.dataMixedAir->OAController(OutAirNum).HumidistatZoneNum > 0) {
    2245            6 :             bool AirNodeFound = false;
    2246            6 :             bool AirLoopFound = false;
    2247            6 :             bool OASysFound = false;
    2248           25 :             for (int ControlledZoneNum = 1; ControlledZoneNum <= state.dataGlobal->NumOfZones; ++ControlledZoneNum) {
    2249           19 :                 if (ControlledZoneNum != state.dataMixedAir->OAController(OutAirNum).HumidistatZoneNum) {
    2250           13 :                     continue;
    2251              :                 }
    2252              :                 //           Find the controlled zone number for the specified humidistat location
    2253            6 :                 state.dataMixedAir->OAController(OutAirNum).NodeNumofHumidistatZone =
    2254            6 :                     state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).ZoneNode;
    2255              :                 //           Determine which OA System uses this OA Controller
    2256            6 :                 int OASysIndex = 0;
    2257            6 :                 for (int OASysNum = 1; OASysNum <= state.dataAirLoop->NumOASystems; ++OASysNum) {
    2258            6 :                     for (int OAControllerNum = 1; OAControllerNum <= state.dataAirLoop->OutsideAirSys(OASysNum).NumControllers; ++OAControllerNum) {
    2259           12 :                         if (!Util::SameString(state.dataAirLoop->OutsideAirSys(OASysNum).ControllerType(OAControllerNum), CurrentModuleObject) ||
    2260            6 :                             !Util::SameString(state.dataAirLoop->OutsideAirSys(OASysNum).ControllerName(OAControllerNum),
    2261            6 :                                               state.dataMixedAir->OAController(OutAirNum).Name)) {
    2262            0 :                             continue;
    2263              :                         }
    2264            6 :                         OASysIndex = OASysNum;
    2265            6 :                         OASysFound = true;
    2266            6 :                         break;
    2267              :                     }
    2268            6 :                     if (OASysFound) {
    2269            6 :                         break;
    2270              :                     }
    2271              :                 }
    2272              :                 //           Determine if controller is on air loop served by the humidistat location specified
    2273           12 :                 for (int zoneInNode = 1; zoneInNode <= state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).NumInletNodes; ++zoneInNode) {
    2274            6 :                     int AirLoopNumber = state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).InletNodeAirLoopNum(zoneInNode);
    2275            6 :                     if (AirLoopNumber > 0 && OASysIndex > 0) {
    2276            6 :                         for (int BranchNum = 1; BranchNum <= state.dataAirSystemsData->PrimaryAirSystems(AirLoopNumber).NumBranches; ++BranchNum) {
    2277            6 :                             for (int CompNum = 1;
    2278            6 :                                  CompNum <= state.dataAirSystemsData->PrimaryAirSystems(AirLoopNumber).Branch(BranchNum).TotalComponents;
    2279              :                                  ++CompNum) {
    2280            6 :                                 if (!Util::SameString(state.dataAirSystemsData->PrimaryAirSystems(AirLoopNumber).Branch(BranchNum).Comp(CompNum).Name,
    2281           18 :                                                       state.dataAirLoop->OutsideAirSys(OASysIndex).Name) ||
    2282           18 :                                     !Util::SameString(
    2283            6 :                                         state.dataAirSystemsData->PrimaryAirSystems(AirLoopNumber).Branch(BranchNum).Comp(CompNum).TypeOf,
    2284              :                                         "AirLoopHVAC:OutdoorAirSystem")) {
    2285            0 :                                     continue;
    2286              :                                 }
    2287            6 :                                 AirLoopFound = true;
    2288            6 :                                 break;
    2289              :                             }
    2290            6 :                             if (AirLoopFound) {
    2291            6 :                                 break;
    2292              :                             }
    2293              :                         }
    2294            6 :                         for (int HStatZoneNum = 1; HStatZoneNum <= state.dataZoneCtrls->NumHumidityControlZones; ++HStatZoneNum) {
    2295            6 :                             if (state.dataZoneCtrls->HumidityControlZone(HStatZoneNum).ActualZoneNum !=
    2296            6 :                                 state.dataMixedAir->OAController(OutAirNum).HumidistatZoneNum) {
    2297            0 :                                 continue;
    2298              :                             }
    2299            6 :                             AirNodeFound = true;
    2300            6 :                             break;
    2301              :                         }
    2302            6 :                     } else {
    2303            0 :                         if (OASysIndex == 0) {
    2304            0 :                             ShowSevereError(
    2305              :                                 state,
    2306            0 :                                 format("Did not find an AirLoopHVAC:OutdoorAirSystem for {} = \"{}\"",
    2307            0 :                                        MixedAirControllerTypeNames[static_cast<int>(state.dataMixedAir->OAController(OutAirNum).ControllerType)],
    2308            0 :                                        state.dataMixedAir->OAController(OutAirNum).Name));
    2309            0 :                             ErrorsFound = true;
    2310              :                         }
    2311              :                     }
    2312              :                 }
    2313              :             }
    2314            6 :             if (!AirNodeFound) {
    2315            0 :                 ShowSevereError(state,
    2316            0 :                                 format("Did not find Air Node (Zone with Humidistat), {} = \"{}\"",
    2317            0 :                                        MixedAirControllerTypeNames[static_cast<int>(state.dataMixedAir->OAController(OutAirNum).ControllerType)],
    2318            0 :                                        state.dataMixedAir->OAController(OutAirNum).Name));
    2319            0 :                 ShowContinueError(state, format("Specified {} = {}", cAlphaFields(17), AlphArray(17)));
    2320            0 :                 ShowContinueError(state,
    2321              :                                   "Both a ZoneHVAC:EquipmentConnections object and a ZoneControl:Humidistat object must be specified for this zone.");
    2322            0 :                 ErrorsFound = true;
    2323              :             }
    2324            6 :             if (!AirLoopFound) {
    2325            0 :                 ShowSevereError(state,
    2326            0 :                                 format("Did not find correct Primary Air Loop for {} = \"{}\"",
    2327            0 :                                        MixedAirControllerTypeNames[static_cast<int>(state.dataMixedAir->OAController(OutAirNum).ControllerType)],
    2328            0 :                                        state.dataMixedAir->OAController(OutAirNum).Name));
    2329            0 :                 ShowContinueError(state, format("{} = {} is not served by this Primary Air Loop equipment.", cAlphaFields(17), AlphArray(17)));
    2330            0 :                 ErrorsFound = true;
    2331              :             }
    2332              :         } else {
    2333            0 :             ShowSevereError(state,
    2334            0 :                             format("Did not find Air Node (Zone with Humidistat), {} = \"{}\"",
    2335            0 :                                    MixedAirControllerTypeNames[static_cast<int>(state.dataMixedAir->OAController(OutAirNum).ControllerType)],
    2336            0 :                                    state.dataMixedAir->OAController(OutAirNum).Name));
    2337            0 :             ShowContinueError(state, format("Specified {} = {}", cAlphaFields(17), AlphArray(17)));
    2338            0 :             ShowContinueError(state,
    2339              :                               "Both a ZoneHVAC:EquipmentConnections object and a ZoneControl:Humidistat object must be specified for this zone.");
    2340            0 :             ErrorsFound = true;
    2341              :         }
    2342              : 
    2343            6 :         state.dataMixedAir->OAController(OutAirNum).HighRHOAFlowRatio = NumArray(7);
    2344            6 :         if (state.dataMixedAir->OAController(OutAirNum).HighRHOAFlowRatio <= 0.0 && NumNums > 6) {
    2345            0 :             ShowWarningError(state, format("{} \"{}\"", CurrentModuleObject, state.dataMixedAir->OAController(OutAirNum).Name));
    2346            0 :             ShowContinueError(state, format(" {} must be greater than 0.", cNumericFields(7)));
    2347            0 :             ShowContinueError(state, format(" {} is reset to 1 and the simulation continues.", cNumericFields(7)));
    2348            0 :             state.dataMixedAir->OAController(OutAirNum).HighRHOAFlowRatio = 1.0;
    2349              :         }
    2350              : 
    2351            6 :         if (Util::SameString(AlphArray(16), "Yes") && state.dataMixedAir->OAController(OutAirNum).FixedMin) {
    2352            6 :             if (state.dataMixedAir->OAController(OutAirNum).MaxOA > 0.0 && state.dataMixedAir->OAController(OutAirNum).MinOA != AutoSize) {
    2353            5 :                 Real64 OAFlowRatio = state.dataMixedAir->OAController(OutAirNum).MinOA / state.dataMixedAir->OAController(OutAirNum).MaxOA;
    2354            5 :                 if (state.dataMixedAir->OAController(OutAirNum).HighRHOAFlowRatio < OAFlowRatio) {
    2355            0 :                     ShowWarningError(state, format("{} \"{}\"", CurrentModuleObject, state.dataMixedAir->OAController(OutAirNum).Name));
    2356            0 :                     ShowContinueError(state, "... A fixed minimum outside air flow rate and high humidity control have been specified.");
    2357            0 :                     ShowContinueError(
    2358              :                         state,
    2359            0 :                         format("... The {} is less than the ratio of the outside air controllers minimum to maximum outside air flow rate.",
    2360              :                                cNumericFields(7)));
    2361            0 :                     ShowContinueError(
    2362            0 :                         state, format("... Controller {} = {:.4T} m3/s.", cNumericFields(1), state.dataMixedAir->OAController(OutAirNum).MinOA));
    2363            0 :                     ShowContinueError(
    2364            0 :                         state, format("... Controller {} = {:.4T} m3/s.", cNumericFields(2), state.dataMixedAir->OAController(OutAirNum).MaxOA));
    2365            0 :                     ShowContinueError(state, format("... Controller minimum to maximum flow ratio = {:.4T}.", OAFlowRatio));
    2366            0 :                     ShowContinueError(state,
    2367            0 :                                       format("... {} = {:.4T}.", cNumericFields(7), state.dataMixedAir->OAController(OutAirNum).HighRHOAFlowRatio));
    2368              :                 }
    2369              :             }
    2370              :         }
    2371              : 
    2372            6 :         if (NumAlphas >= 18) {
    2373            6 :             if (Util::SameString(AlphArray(18), "Yes")) {
    2374            6 :                 state.dataMixedAir->OAController(OutAirNum).ModifyDuringHighOAMoisture = false;
    2375            0 :             } else if (Util::SameString(AlphArray(18), "No")) {
    2376            0 :                 state.dataMixedAir->OAController(OutAirNum).ModifyDuringHighOAMoisture = true;
    2377              :             } else {
    2378            0 :                 ShowSevereError(state,
    2379            0 :                                 format("{} \"{}\", invalid field value", CurrentModuleObject, state.dataMixedAir->OAController(OutAirNum).Name));
    2380            0 :                 ShowContinueError(state, format("...{}=\"{}\" - valid values are \"Yes\" or \"No\".", cAlphaFields(18), AlphArray(18)));
    2381            0 :                 ErrorsFound = true;
    2382              :             }
    2383              :         } else {
    2384            0 :             if (state.dataMixedAir->OAController(OutAirNum).Econo == EconoOp::NoEconomizer) {
    2385            0 :                 state.dataMixedAir->OAController(OutAirNum).ModifyDuringHighOAMoisture = true;
    2386              :             } else {
    2387            0 :                 state.dataMixedAir->OAController(OutAirNum).ModifyDuringHighOAMoisture = false;
    2388            0 :                 ShowWarningError(state,
    2389            0 :                                  format("{} \"{}\", missing field value", CurrentModuleObject, state.dataMixedAir->OAController(OutAirNum).Name));
    2390            0 :                 ShowContinueError(state, format("...{} will default to Yes when {}= \"Yes\"", cAlphaFields(18), cAlphaFields(16)));
    2391              :             }
    2392              :         }
    2393              : 
    2394         1061 :     } else if (Util::SameString(AlphArray(16), "No") || lAlphaBlanks(16)) {
    2395         1061 :         if (NumAlphas >= 18) {
    2396          132 :             if (!Util::SameString(AlphArray(18), "Yes") && !Util::SameString(AlphArray(18), "No")) {
    2397            0 :                 ShowSevereError(state,
    2398            0 :                                 format("{} \"{}\", invalid field value", CurrentModuleObject, state.dataMixedAir->OAController(OutAirNum).Name));
    2399            0 :                 ShowContinueError(state, format("...{}=\"{}\" - valid values are \"Yes\" or \"No\".", cAlphaFields(18), AlphArray(18)));
    2400            0 :                 ErrorsFound = true;
    2401              :             }
    2402              :         }
    2403              :     } else { // Invalid field 16
    2404            0 :         ShowSevereError(state, format("{} \"{}\", invalid field value", CurrentModuleObject, state.dataMixedAir->OAController(OutAirNum).Name));
    2405            0 :         ShowContinueError(state, format("...{}=\"{}\" - valid values are \"Yes\" or \"No\".", cAlphaFields(16), AlphArray(16)));
    2406            0 :         ErrorsFound = true;
    2407            0 :         if (NumAlphas >= 18) {
    2408            0 :             if (!Util::SameString(AlphArray(18), "Yes") && !Util::SameString(AlphArray(18), "No")) {
    2409            0 :                 ShowSevereError(state,
    2410            0 :                                 format("{} \"{}\", invalid field value", CurrentModuleObject, state.dataMixedAir->OAController(OutAirNum).Name));
    2411            0 :                 ShowContinueError(state, format("...{}=\"{}\" - valid values are \"Yes\" or \"No\".", cAlphaFields(18), AlphArray(18)));
    2412            0 :                 ErrorsFound = true;
    2413              :             }
    2414              :         }
    2415              :     }
    2416              : 
    2417         1067 :     if (NumAlphas > 18) {
    2418          131 :         if (!lAlphaBlanks(19)) {
    2419          127 :             if (Util::SameString(AlphArray(19), "BypassWhenWithinEconomizerLimits")) {
    2420          104 :                 state.dataMixedAir->OAController(OutAirNum).HeatRecoveryBypassControlType = HVAC::BypassWhenWithinEconomizerLimits;
    2421           23 :             } else if (Util::SameString(AlphArray(19), "BypassWhenOAFlowGreaterThanMinimum")) {
    2422           23 :                 state.dataMixedAir->OAController(OutAirNum).HeatRecoveryBypassControlType = HVAC::BypassWhenOAFlowGreaterThanMinimum;
    2423              :             } else {
    2424            0 :                 ShowWarningError(state, format("{}=\"{}\" invalid {}=\"{}\".", CurrentModuleObject, AlphArray(1), cAlphaFields(19), AlphArray(19)));
    2425            0 :                 ShowContinueError(state, "...assuming \"BypassWhenWithinEconomizerLimits\" and the simulation continues.");
    2426            0 :                 state.dataMixedAir->OAController(OutAirNum).HeatRecoveryBypassControlType = HVAC::BypassWhenWithinEconomizerLimits;
    2427              :             }
    2428              :         }
    2429              :     }
    2430              : 
    2431         1067 :     if (NumAlphas > 19) {
    2432            4 :         if (!lAlphaBlanks(20)) {
    2433            4 :             if (Util::SameString(AlphArray(20), "EconomizerFirst")) {
    2434            4 :                 state.dataMixedAir->OAController(OutAirNum).EconomizerStagingType = HVAC::EconomizerStagingType::EconomizerFirst;
    2435              :             } else {
    2436            0 :                 state.dataMixedAir->OAController(OutAirNum).EconomizerStagingType = HVAC::EconomizerStagingType::InterlockedWithMechanicalCooling;
    2437              :             }
    2438              :         }
    2439              :     }
    2440              : 
    2441         1067 :     if (Util::SameString(AlphArray(16), "Yes") && state.dataMixedAir->OAController(OutAirNum).Econo == EconoOp::NoEconomizer) {
    2442            0 :         ShowWarningError(state,
    2443            0 :                          format("{} \"{}\"",
    2444            0 :                                 MixedAirControllerTypeNames[static_cast<int>(state.dataMixedAir->OAController(OutAirNum).ControllerType)],
    2445            0 :                                 state.dataMixedAir->OAController(OutAirNum).Name));
    2446            0 :         ShowContinueError(state, format("...Economizer operation must be enabled when {} is set to YES.", cAlphaFields(16)));
    2447            0 :         ShowContinueError(state, "...The high humidity control option will be disabled and the simulation continues.");
    2448              :     }
    2449              : 
    2450         1067 :     state.dataMixedAir->OAController(OutAirNum).MixedAirSPMNum =
    2451         1067 :         SetPointManager::GetMixedAirNumWithCoilFreezingCheck(state, state.dataMixedAir->OAController(OutAirNum).MixNode);
    2452         1067 : }
    2453              : 
    2454              : // End of Get Input subroutines for the Module
    2455              : //******************************************************************************
    2456              : 
    2457              : // Beginning Initialization Section of the Module
    2458              : //******************************************************************************
    2459              : 
    2460     27043260 : void InitOutsideAirSys(EnergyPlusData &state, int const(OASysNum), int const AirLoopNum)
    2461              : {
    2462              : 
    2463              :     // SUBROUTINE INFORMATION:
    2464              :     //       AUTHOR         Fred Buhl
    2465              :     //       DATE WRITTEN   Oct 1998
    2466              : 
    2467              :     // PURPOSE OF THIS SUBROUTINE
    2468              :     // Initialize the OutsideAirSys data structure
    2469              : 
    2470     27043260 :     if (state.dataAirLoop->OutsideAirSys(OASysNum).AirLoopDOASNum > -1) {
    2471        10882 :         return;
    2472              :     }
    2473              : 
    2474     27032378 :     if (state.dataMixedAir->initOASysFlag(OASysNum)) {
    2475         1067 :         state.dataAirLoop->AirLoopControlInfo(AirLoopNum).OASysNum = OASysNum;
    2476         1067 :         state.dataMixedAir->initOASysFlag(OASysNum) = false;
    2477              :     }
    2478              : }
    2479              : 
    2480     27596359 : void InitOAController(EnergyPlusData &state, int const OAControllerNum, bool const FirstHVACIteration, int const AirLoopNum)
    2481              : {
    2482              : 
    2483              :     // SUBROUTINE INFORMATION:
    2484              :     //       AUTHOR         Fred Buhl
    2485              :     //       DATE WRITTEN   Oct 1998
    2486              :     //       MODIFIED       Shirey/Raustad FSEC, June/Aug 2003, Feb 2004
    2487              :     //                      Tianzhen Hong, Feb 2009 for DCV
    2488              :     //                      Tianzhen Hong, Aug 2013 for economizer faults
    2489              : 
    2490              :     // PURPOSE OF THIS SUBROUTINE
    2491              :     // Initialize the OAController data structure with input node data
    2492              : 
    2493     27596359 :     bool ErrorsFound = false;
    2494              : 
    2495     27596359 :     auto &thisOAController(state.dataMixedAir->OAController(OAControllerNum));
    2496              : 
    2497     27596359 :     if (state.dataMixedAir->InitOAControllerOneTimeFlag) {
    2498          414 :         state.dataMixedAir->OAControllerMyOneTimeFlag.dimension(state.dataMixedAir->NumOAControllers, true);
    2499          414 :         state.dataMixedAir->OAControllerMyEnvrnFlag.dimension(state.dataMixedAir->NumOAControllers, true);
    2500          414 :         state.dataMixedAir->OAControllerMySizeFlag.dimension(state.dataMixedAir->NumOAControllers, true);
    2501          414 :         state.dataMixedAir->MechVentCheckFlag.dimension(state.dataMixedAir->NumOAControllers, true);
    2502          414 :         state.dataMixedAir->InitOAControllerSetPointCheckFlag.dimension(state.dataMixedAir->NumOAControllers, true);
    2503          414 :         state.dataMixedAir->InitOAControllerOneTimeFlag = false;
    2504              :     }
    2505     27596359 :     if (state.dataMixedAir->OAControllerMyOneTimeFlag(OAControllerNum)) {
    2506              :         // Determine Inlet node index for OAController, not a user input for controller, but is obtained from OutsideAirSys and OAMixer
    2507         1171 :         switch (thisOAController.ControllerType) {
    2508         1067 :         case MixedAirControllerType::ControllerOutsideAir: {
    2509         1067 :             int thisOASys = 0;
    2510         6389 :             for (int OASysNum = 1; OASysNum <= state.dataAirLoop->NumOASystems; ++OASysNum) {
    2511              :                 // find which OAsys has this controller
    2512         6389 :                 int found = Util::FindItemInList(thisOAController.Name,
    2513         6389 :                                                  state.dataAirLoop->OutsideAirSys(OASysNum).ControllerName,
    2514         6389 :                                                  isize(state.dataAirLoop->OutsideAirSys(OASysNum).ControllerName));
    2515         6389 :                 if (found != 0) {
    2516         1067 :                     thisOASys = OASysNum;
    2517         1067 :                     state.dataAirLoop->OutsideAirSys(thisOASys).OAControllerIndex = GetOAController(state, thisOAController.Name);
    2518         1067 :                     break; // we found it
    2519              :                 }
    2520              :             }
    2521         1067 :             if (thisOASys == 0) {
    2522            0 :                 ShowSevereError(state, format("InitOAController: Did not find OAController=\"{}\".", thisOAController.Name));
    2523            0 :                 ShowContinueError(state, "in list of valid OA Controllers.");
    2524            0 :                 ErrorsFound = true;
    2525              :             }
    2526         1067 :             int thisNumForMixer = Util::FindItem(CurrentModuleObjects[static_cast<int>(CMO::OAMixer)],
    2527         1067 :                                                  state.dataAirLoop->OutsideAirSys(thisOASys).ComponentType,
    2528         1067 :                                                  isize(state.dataAirLoop->OutsideAirSys(thisOASys).ComponentType));
    2529         1067 :             if (thisNumForMixer != 0) {
    2530         1067 :                 std::string_view const equipName = state.dataAirLoop->OutsideAirSys(thisOASys).ComponentName(thisNumForMixer);
    2531         1067 :                 int thisMixerIndex = Util::FindItemInList(equipName, state.dataMixedAir->OAMixer);
    2532         1067 :                 if (thisMixerIndex != 0) {
    2533         1067 :                     thisOAController.InletNode = state.dataMixedAir->OAMixer(thisMixerIndex).InletNode;
    2534              :                 } else {
    2535            0 :                     ShowSevereError(state, format("InitOAController: Did not find OAMixer=\"{}\".", equipName));
    2536            0 :                     ShowContinueError(state, "in list of valid OA Mixers.");
    2537            0 :                     ErrorsFound = true;
    2538              :                 }
    2539              :             } else {
    2540            0 :                 ShowSevereError(state, "InitOAController: Did not find OutdoorAir:Mixer Component=\"OutdoorAir:Mixer\".");
    2541            0 :                 ShowContinueError(state, "in list of valid OA Components.");
    2542            0 :                 ErrorsFound = true;
    2543              :             }
    2544              : 
    2545         1067 :             if (thisOAController.InletNode == 0) { // throw an error
    2546            0 :                 ShowSevereError(
    2547              :                     state,
    2548            0 :                     format("InitOAController: Failed to find proper inlet node for OutdoorAir:Mixer and Controller = {}", thisOAController.Name));
    2549            0 :                 ErrorsFound = true;
    2550              :             }
    2551         1067 :         } break;
    2552          104 :         case MixedAirControllerType::ControllerStandAloneERV: {
    2553              :             // set the inlet node to also equal the OA node because this is a special controller for economizing stand alone ERV
    2554              :             // with the assumption that equipment is bypassed....
    2555          104 :             thisOAController.InletNode = thisOAController.OANode;
    2556          104 :         } break;
    2557            0 :         default: {
    2558            0 :             ShowSevereError(state,
    2559            0 :                             format("InitOAController: Failed to find ControllerType: {}",
    2560            0 :                                    MixedAirControllerTypeNames[static_cast<int>(thisOAController.ControllerType)]));
    2561            0 :             ErrorsFound = true;
    2562            0 :         } break;
    2563              :         }
    2564              : 
    2565         1171 :         state.dataMixedAir->OAControllerMyOneTimeFlag(OAControllerNum) = false;
    2566              :     }
    2567              : 
    2568     55192616 :     if (!state.dataGlobal->SysSizingCalc && state.dataMixedAir->InitOAControllerSetPointCheckFlag(OAControllerNum) &&
    2569     55192616 :         state.dataHVACGlobal->DoSetPointTest && !FirstHVACIteration) {
    2570         1171 :         int MixedAirNode = thisOAController.MixNode;
    2571         1171 :         if (MixedAirNode > 0) {
    2572              :             //      IF (OAController(OAControllerNum)%Econo == 1 .AND. .NOT. AirLoopControlInfo(AirLoopNum)%CyclingFan) THEN
    2573         1067 :             if (thisOAController.Econo > EconoOp::NoEconomizer && state.dataAirLoop->AirLoopControlInfo(AirLoopNum).AnyContFan) {
    2574          501 :                 if (state.dataLoopNodes->Node(MixedAirNode).TempSetPoint == SensedNodeFlagValue) {
    2575           16 :                     if (!state.dataGlobal->AnyEnergyManagementSystemInModel) {
    2576            0 :                         ShowSevereError(state, format("MixedAir: Missing temperature setpoint for economizer controller {}", thisOAController.Name));
    2577            0 :                         ShowContinueError(state, format("Node Referenced (by Controller)={}", state.dataLoopNodes->NodeID(MixedAirNode)));
    2578            0 :                         ShowContinueError(
    2579              :                             state, "  use a Setpoint Manager with Control Variable = \"Temperature\" to establish a setpoint at the mixed air node.");
    2580            0 :                         state.dataHVACGlobal->SetPointErrorFlag = true;
    2581              :                     } else {
    2582              :                         // add call to check node in EMS
    2583           16 :                         EMSManager::CheckIfNodeSetPointManagedByEMS(
    2584           16 :                             state, MixedAirNode, HVAC::CtrlVarType::Temp, state.dataHVACGlobal->SetPointErrorFlag);
    2585           16 :                         if (state.dataHVACGlobal->SetPointErrorFlag) {
    2586            0 :                             ShowSevereError(state,
    2587            0 :                                             format("MixedAir: Missing temperature setpoint for economizer controller {}", thisOAController.Name));
    2588            0 :                             ShowContinueError(state, format("Node Referenced (by Controller)={}", state.dataLoopNodes->NodeID(MixedAirNode)));
    2589            0 :                             ShowContinueError(state,
    2590              :                                               "  use a Setpoint Manager with Control Variable = \"Temperature\" to establish a setpoint at the "
    2591              :                                               "mixed air node.");
    2592            0 :                             ShowContinueError(state, "Or add EMS Actuator to provide temperature setpoint at this node");
    2593              :                         }
    2594              :                     }
    2595              :                 }
    2596              :             }
    2597              :         }
    2598              : 
    2599         1171 :         state.dataMixedAir->InitOAControllerSetPointCheckFlag(OAControllerNum) = false;
    2600              :     }
    2601              : 
    2602     27596359 :     if (!state.dataGlobal->SysSizingCalc && state.dataMixedAir->OAControllerMySizeFlag(OAControllerNum)) {
    2603         1171 :         thisOAController.SizeOAController(state);
    2604         1171 :         if (AirLoopNum > 0) {
    2605         1067 :             state.dataAirLoop->AirLoopControlInfo(AirLoopNum).OACtrlNum = OAControllerNum;
    2606         1067 :             state.dataAirLoop->AirLoopControlInfo(AirLoopNum).OACtrlName = thisOAController.Name;
    2607         1067 :             if (thisOAController.Lockout == LockoutType::LockoutWithHeatingPossible) {
    2608          201 :                 state.dataAirLoop->AirLoopControlInfo(AirLoopNum).CanLockoutEconoWithHeating = true;
    2609          201 :                 state.dataAirLoop->AirLoopControlInfo(AirLoopNum).CanLockoutEconoWithCompressor = false;
    2610          201 :                 state.dataAirLoop->AirLoopControlInfo(AirLoopNum).CanNotLockoutEcono = false;
    2611          866 :             } else if (thisOAController.Lockout == LockoutType::LockoutWithCompressorPossible) {
    2612           41 :                 state.dataAirLoop->AirLoopControlInfo(AirLoopNum).CanLockoutEconoWithHeating = false;
    2613           41 :                 state.dataAirLoop->AirLoopControlInfo(AirLoopNum).CanLockoutEconoWithCompressor = true;
    2614           41 :                 state.dataAirLoop->AirLoopControlInfo(AirLoopNum).CanNotLockoutEcono = false;
    2615              :             } else {
    2616          825 :                 state.dataAirLoop->AirLoopControlInfo(AirLoopNum).CanLockoutEconoWithHeating = false;
    2617          825 :                 state.dataAirLoop->AirLoopControlInfo(AirLoopNum).CanLockoutEconoWithCompressor = false;
    2618          825 :                 state.dataAirLoop->AirLoopControlInfo(AirLoopNum).CanNotLockoutEcono = true;
    2619              :             }
    2620              :         }
    2621         1171 :         if ((thisOAController.MaxOA - thisOAController.MinOA) < -HVAC::SmallAirVolFlow) {
    2622            0 :             ShowSevereError(state, format("For Controller:OutdoorAir: {}", thisOAController.Name));
    2623            0 :             ShowContinueError(state,
    2624            0 :                               format("  maximum outdoor air flow rate ({:.4R}) < minimum outdoor air flow rate ({:.4R})",
    2625            0 :                                      thisOAController.MaxOA,
    2626            0 :                                      thisOAController.MinOA));
    2627            0 :             ShowContinueError(state,
    2628              :                               "  To set the minimum outside air flow rate use the \"Design (minimum) outdoor air flow rate\" field in the "
    2629              :                               "Sizing:System object");
    2630            0 :             ErrorsFound = true;
    2631              :         }
    2632              : 
    2633         1171 :         if (AirLoopNum > 0) {
    2634         1067 :             Real64 DesSupplyVolFlowRate = state.dataAirLoop->AirLoopFlow(AirLoopNum).DesSupply / state.dataEnvrn->StdRhoAir;
    2635         1067 :             if ((thisOAController.MinOA - DesSupplyVolFlowRate) > 0.0001) {
    2636            0 :                 ShowWarningError(state,
    2637            0 :                                  format("InitOAController: Minimum Outdoor Air Flow Rate for Controller:OutdoorAir={} is greater than Design Supply "
    2638              :                                         "Air Flow Rate for AirLoopHVAC={}.",
    2639            0 :                                         thisOAController.Name,
    2640            0 :                                         state.dataAirSystemsData->PrimaryAirSystems(AirLoopNum).Name));
    2641            0 :                 ShowContinueError(state,
    2642            0 :                                   format("...Minimum Outdoor Air Flow Rate={:.6R} will be reset to loop Design Supply Air Flow Rate={:.6R}",
    2643            0 :                                          thisOAController.MinOA,
    2644              :                                          DesSupplyVolFlowRate));
    2645            0 :                 thisOAController.MinOA = DesSupplyVolFlowRate;
    2646         1067 :             } else if ((thisOAController.MinOA - DesSupplyVolFlowRate) > 0.0) {
    2647              :                 // If difference is tiny, reset silently
    2648            0 :                 thisOAController.MinOA = DesSupplyVolFlowRate;
    2649              :             }
    2650         1067 :             if ((thisOAController.MaxOA - DesSupplyVolFlowRate) > 0.0001) {
    2651            0 :                 ShowWarningError(state,
    2652            0 :                                  format("InitOAController: Maximum Outdoor Air Flow Rate for Controller:OutdoorAir={} is greater than Design Supply "
    2653              :                                         "Air Flow Rate for AirLoopHVAC={}.",
    2654            0 :                                         thisOAController.Name,
    2655            0 :                                         state.dataAirSystemsData->PrimaryAirSystems(AirLoopNum).Name));
    2656            0 :                 ShowContinueError(state,
    2657            0 :                                   format("...Maximum Outdoor Air Flow Rate={:.6R} will be reset to loop Design Supply Air Flow Rate={:.6R}",
    2658            0 :                                          thisOAController.MaxOA,
    2659              :                                          DesSupplyVolFlowRate));
    2660            0 :                 thisOAController.MaxOA = DesSupplyVolFlowRate;
    2661         1067 :             } else if ((thisOAController.MaxOA - DesSupplyVolFlowRate) > 0.0) {
    2662              :                 // If difference is tiny, reset silently
    2663           23 :                 thisOAController.MaxOA = DesSupplyVolFlowRate;
    2664              :             }
    2665              : 
    2666              :             // Check if system has a Sizing:System object and a sizing run has been done
    2667         1067 :             bool SizingDesRunThisAirSys = false;
    2668         1067 :             CheckThisAirSystemForSizing(state, AirLoopNum, SizingDesRunThisAirSys);
    2669              : 
    2670              :             // Get design outdoor air flow rate
    2671         1067 :             if (SizingDesRunThisAirSys && thisOAController.VentMechObjectNum > 0) {
    2672           47 :                 state.dataMixedAir->VentilationMechanical(thisOAController.VentMechObjectNum).SysDesOA =
    2673           47 :                     state.dataSize->FinalSysSizing(AirLoopNum).DesOutAirVolFlow;
    2674              :             }
    2675              :         }
    2676              : 
    2677         1171 :         state.dataMixedAir->OAControllerMySizeFlag(OAControllerNum) = false;
    2678              :     }
    2679              : 
    2680     27596359 :     if (state.dataGlobal->BeginEnvrnFlag && state.dataMixedAir->OAControllerMyEnvrnFlag(OAControllerNum)) {
    2681         7451 :         Real64 RhoAirStdInit = state.dataEnvrn->StdRhoAir;
    2682         7451 :         thisOAController.MinOAMassFlowRate = thisOAController.MinOA * RhoAirStdInit;
    2683         7451 :         thisOAController.MaxOAMassFlowRate = thisOAController.MaxOA * RhoAirStdInit;
    2684         7451 :         state.dataMixedAir->OAControllerMyEnvrnFlag(OAControllerNum) = false;
    2685         7451 :         state.dataLoopNodes->Node(thisOAController.OANode).MassFlowRateMax = thisOAController.MaxOAMassFlowRate;
    2686              : 
    2687              :         // predefined reporting
    2688         7451 :         if (thisOAController.Econo > EconoOp::NoEconomizer) {
    2689         3637 :             std::string_view const equipName = thisOAController.Name;
    2690              :             // 90.1 descriptor for economizer controls. Changed by Amit for New Feature implementation
    2691         3637 :             if (thisOAController.Econo == EconoOp::DifferentialEnthalpy) {
    2692          166 :                 OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchEcoKind, equipName, "DifferentialEnthalpy");
    2693         3471 :             } else if (thisOAController.Econo == EconoOp::DifferentialDryBulb) {
    2694         2653 :                 OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchEcoKind, equipName, "DifferentialDryBulb");
    2695          818 :             } else if (thisOAController.Econo == EconoOp::FixedEnthalpy) {
    2696            0 :                 OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchEcoKind, equipName, "FixedEnthalpy");
    2697          818 :             } else if (thisOAController.Econo == EconoOp::FixedDryBulb) {
    2698          771 :                 OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchEcoKind, equipName, "FixedDryBulb");
    2699              :             } else {
    2700           47 :                 OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchEcoKind, equipName, "Other");
    2701              :             }
    2702              : 
    2703         3637 :             OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchEcoMinOA, equipName, thisOAController.MinOA);
    2704         3637 :             OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchEcoMaxOA, equipName, thisOAController.MaxOA);
    2705              :             // EnergyPlus input echos for economizer controls. Changed by Amit for new feature implementation
    2706         3637 :             if (thisOAController.Econo == EconoOp::DifferentialDryBulb) {
    2707         2653 :                 OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchEcoRetTemp, equipName, "Yes");
    2708              :             } else {
    2709          984 :                 OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchEcoRetTemp, equipName, "No");
    2710              :             }
    2711         3637 :             if (thisOAController.Econo == EconoOp::DifferentialEnthalpy) {
    2712          166 :                 OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchEcoRetTemp, equipName, "Yes");
    2713              :             } else {
    2714         3471 :                 OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchEcoRetTemp, equipName, "No");
    2715              :             }
    2716         3637 :             if (thisOAController.Econo == EconoOp::FixedDryBulb) {
    2717          771 :                 OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchEcoRetTemp, equipName, thisOAController.TempLim);
    2718              :             } else {
    2719         2866 :                 OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchEcoRetTemp, equipName, "-");
    2720              :             }
    2721         3637 :             if (thisOAController.Econo == EconoOp::FixedEnthalpy) {
    2722            0 :                 OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchEcoRetTemp, equipName, thisOAController.EnthLim);
    2723              :             } else {
    2724         3637 :                 OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchEcoRetTemp, equipName, "-");
    2725              :             }
    2726              :         }
    2727              :     }
    2728              : 
    2729     27596359 :     if (!state.dataGlobal->BeginEnvrnFlag) {
    2730     27507092 :         state.dataMixedAir->OAControllerMyEnvrnFlag(OAControllerNum) = true;
    2731              :     }
    2732              : 
    2733     27596359 :     if (state.dataMixedAir->MechVentCheckFlag(OAControllerNum)) {
    2734              :         // Make these checks only once at the beginning of the simulation
    2735              : 
    2736              :         // Make sure all air loop zones and air loop zones with people objects are covered by mechanical ventilation
    2737              :         // Issue a warning only if the zone is not accounted for in the associated mechanical ventilation object
    2738         1171 :         if (thisOAController.VentMechObjectNum > 0) {
    2739           54 :             auto &vent_mech(state.dataMixedAir->VentilationMechanical(thisOAController.VentMechObjectNum));
    2740              : 
    2741              :             // Make sure all zones with mechanical ventilation are on the correct air loop
    2742           54 :             int TempMechVentArrayCounter = 0;
    2743          459 :             for (int NumMechVentZone = 1; NumMechVentZone <= vent_mech.NumofVentMechZones; ++NumMechVentZone) {
    2744          405 :                 auto &thisMechVentZone = vent_mech.VentMechZone(NumMechVentZone);
    2745          405 :                 int ZoneNum = thisMechVentZone.zoneNum;
    2746          405 :                 auto const &zone(state.dataHeatBal->Zone(ZoneNum));
    2747          405 :                 bool FoundZone = false;
    2748              : 
    2749         4746 :                 for (int AirLoopZoneInfoZoneNum = 1; AirLoopZoneInfoZoneNum <= state.dataAirLoop->AirLoopZoneInfo(AirLoopNum).NumZones;
    2750              :                      ++AirLoopZoneInfoZoneNum) {
    2751         4746 :                     int NumZone = state.dataAirLoop->AirLoopZoneInfo(AirLoopNum).ActualZoneNumber(AirLoopZoneInfoZoneNum);
    2752         4746 :                     if (ZoneNum == NumZone) {
    2753          405 :                         FoundZone = true;
    2754          405 :                         ++TempMechVentArrayCounter;
    2755          405 :                         if (TempMechVentArrayCounter < NumMechVentZone) { // Copy to lower index
    2756            0 :                             auto &tempMechVentZone = vent_mech.VentMechZone(TempMechVentArrayCounter);
    2757            0 :                             tempMechVentZone.zoneNum = thisMechVentZone.zoneNum;
    2758            0 :                             tempMechVentZone.ZoneOAAreaRate = thisMechVentZone.ZoneOAAreaRate;
    2759            0 :                             tempMechVentZone.ZoneOAPeopleRate = thisMechVentZone.ZoneOAPeopleRate;
    2760            0 :                             tempMechVentZone.ZoneOAFlowRate = thisMechVentZone.ZoneOAFlowRate;
    2761            0 :                             tempMechVentZone.ZoneOAACHRate = thisMechVentZone.ZoneOAACHRate;
    2762            0 :                             tempMechVentZone.ZoneOAFlowMethod = thisMechVentZone.ZoneOAFlowMethod;
    2763            0 :                             tempMechVentZone.zoneOASched = thisMechVentZone.zoneOASched;
    2764            0 :                             tempMechVentZone.ZoneDesignSpecOAObjIndex = thisMechVentZone.ZoneDesignSpecOAObjIndex;
    2765            0 :                             tempMechVentZone.ZoneDesignSpecOAObjName = thisMechVentZone.ZoneDesignSpecOAObjName;
    2766              : 
    2767              :                             // new DCV
    2768            0 :                             tempMechVentZone.ZoneADEffCooling = thisMechVentZone.ZoneADEffCooling;
    2769            0 :                             tempMechVentZone.ZoneADEffHeating = thisMechVentZone.ZoneADEffHeating;
    2770            0 :                             tempMechVentZone.zoneADEffSched = thisMechVentZone.zoneADEffSched;
    2771              :                         }
    2772              : 
    2773              :                         // Sum outside air per unit floor area for each mechanical ventilation object only once per simulation
    2774          405 :                         vent_mech.TotAreaOAFlow += zone.FloorArea * zone.Multiplier * zone.ListMultiplier * thisMechVentZone.ZoneOAAreaRate;
    2775          405 :                         vent_mech.TotZoneOAFlow += zone.Multiplier * zone.ListMultiplier * thisMechVentZone.ZoneOAFlowRate;
    2776          405 :                         vent_mech.TotZoneOAACH += zone.Multiplier * zone.ListMultiplier * (thisMechVentZone.ZoneOAACHRate * zone.Volume / 3600.0);
    2777          405 :                         break;
    2778              :                     }
    2779              :                 }
    2780          405 :                 if (!FoundZone) {
    2781            0 :                     ShowWarningError(state,
    2782            0 :                                      format("Zone name = {} in {} object name = {} is not on the same air loop as Controller:OutdoorAir = {}",
    2783            0 :                                             zone.Name,
    2784            0 :                                             CurrentModuleObjects[static_cast<int>(CMO::MechVentilation)],
    2785            0 :                                             thisOAController.VentilationMechanicalName,
    2786            0 :                                             thisOAController.Name));
    2787            0 :                     ShowContinueError(state, "This zone will not be used and the simulation will continue...");
    2788              :                 }
    2789              :             }
    2790              : 
    2791              :             // Shrink final arrays to conserve environment space
    2792           54 :             if (TempMechVentArrayCounter < vent_mech.NumofVentMechZones) {
    2793            0 :                 vent_mech.VentMechZone.resize(TempMechVentArrayCounter);
    2794            0 :                 vent_mech.NumofVentMechZones = TempMechVentArrayCounter;
    2795              :             }
    2796              : 
    2797              :             // predefined report
    2798          459 :             for (int jZone = 1; jZone <= vent_mech.NumofVentMechZones; ++jZone) {
    2799          405 :                 auto &thisMechVentZone = vent_mech.VentMechZone(jZone);
    2800          405 :                 std::string_view const zoneName = state.dataHeatBal->Zone(thisMechVentZone.zoneNum).Name;
    2801          405 :                 OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchDCVventMechName, zoneName, vent_mech.Name);
    2802          405 :                 OutputReportPredefined::PreDefTableEntry(
    2803          405 :                     state, state.dataOutRptPredefined->pdchDCVperPerson, zoneName, thisMechVentZone.ZoneOAPeopleRate, 6);
    2804          405 :                 OutputReportPredefined::PreDefTableEntry(
    2805          405 :                     state, state.dataOutRptPredefined->pdchDCVperArea, zoneName, thisMechVentZone.ZoneOAAreaRate, 6);
    2806          405 :                 OutputReportPredefined::PreDefTableEntry(
    2807          405 :                     state, state.dataOutRptPredefined->pdchDCVperZone, zoneName, thisMechVentZone.ZoneOAFlowRate, 6);
    2808          405 :                 OutputReportPredefined::PreDefTableEntry(
    2809          405 :                     state, state.dataOutRptPredefined->pdchDCVperACH, zoneName, thisMechVentZone.ZoneOAACHRate, 6);
    2810          405 :                 OutputReportPredefined::PreDefTableEntry(state,
    2811          405 :                                                          state.dataOutRptPredefined->pdchDCVMethod,
    2812              :                                                          zoneName,
    2813          405 :                                                          OAFlowCalcMethodNames[static_cast<int>(thisMechVentZone.ZoneOAFlowMethod)]);
    2814          405 :                 OutputReportPredefined::PreDefTableEntry(
    2815          405 :                     state, state.dataOutRptPredefined->pdchDCVType, zoneName, SysOAMethodNames[static_cast<int>(vent_mech.SystemOAMethod)]);
    2816          405 :                 if (thisMechVentZone.zoneOASched != nullptr) {
    2817          405 :                     OutputReportPredefined::PreDefTableEntry(
    2818          405 :                         state, state.dataOutRptPredefined->pdchDCVOASchName, zoneName, thisMechVentZone.zoneOASched->Name);
    2819              :                 } else {
    2820            0 :                     OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchDCVOASchName, zoneName, "");
    2821              :                 }
    2822              : 
    2823              :                 // added for new DCV inputs
    2824          405 :                 if (thisMechVentZone.zoneADEffSched != nullptr) {
    2825            6 :                     OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchDCVZoneADEffCooling, zoneName, "");
    2826            6 :                     OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchDCVZoneADEffHeating, zoneName, "");
    2827            6 :                     OutputReportPredefined::PreDefTableEntry(
    2828            6 :                         state, state.dataOutRptPredefined->pdchDCVZoneADEffSchName, zoneName, thisMechVentZone.zoneADEffSched->Name);
    2829              :                 } else {
    2830          399 :                     OutputReportPredefined::PreDefTableEntry(
    2831          399 :                         state, state.dataOutRptPredefined->pdchDCVZoneADEffCooling, zoneName, thisMechVentZone.ZoneADEffCooling, 2);
    2832          399 :                     OutputReportPredefined::PreDefTableEntry(
    2833          399 :                         state, state.dataOutRptPredefined->pdchDCVZoneADEffHeating, zoneName, thisMechVentZone.ZoneADEffHeating, 2);
    2834          399 :                     OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchDCVZoneADEffSchName, zoneName, "");
    2835              :                 }
    2836              :             }
    2837              : 
    2838              :             // Fill People index lists if needed
    2839           54 :             if (vent_mech.SystemOAMethod == DataSizing::SysOAMethod::ProportionalControlDesOcc) {
    2840            4 :                 for (int peopleNum = 1; peopleNum <= state.dataHeatBal->TotPeople; ++peopleNum) {
    2841            6 :                     for (auto &thisMechVentZone : vent_mech.VentMechZone) {
    2842            6 :                         if (state.dataHeatBal->People(peopleNum).ZonePtr == thisMechVentZone.zoneNum) {
    2843            3 :                             thisMechVentZone.peopleIndexes.push_back(peopleNum);
    2844            3 :                             break;
    2845              :                         }
    2846            3 :                     }
    2847              :                 }
    2848              :             }
    2849              : 
    2850              :             // Check to see if any zones on an air loop are not accounted for by a mechanical ventilation object
    2851          459 :             for (int AirLoopZoneInfoZoneNum = 1; AirLoopZoneInfoZoneNum <= state.dataAirLoop->AirLoopZoneInfo(AirLoopNum).NumZones;
    2852              :                  ++AirLoopZoneInfoZoneNum) {
    2853          405 :                 int NumZone = state.dataAirLoop->AirLoopZoneInfo(AirLoopNum).ActualZoneNumber(AirLoopZoneInfoZoneNum);
    2854          405 :                 bool FoundAreaZone = false;
    2855          405 :                 bool FoundPeopleZone = false;
    2856         4746 :                 for (int NumMechVentZone = 1; NumMechVentZone <= vent_mech.NumofVentMechZones; ++NumMechVentZone) {
    2857         4746 :                     auto const &thisMechVentZone = vent_mech.VentMechZone(NumMechVentZone);
    2858         4746 :                     int ZoneNum = thisMechVentZone.zoneNum;
    2859         4746 :                     if (ZoneNum == NumZone) {
    2860          405 :                         FoundAreaZone = true;
    2861          405 :                         if (thisMechVentZone.ZoneOAPeopleRate > 0.0) {
    2862          339 :                             FoundPeopleZone = true;
    2863              :                         }
    2864          405 :                         break;
    2865              :                     }
    2866              :                 }
    2867          405 :                 if (!FoundAreaZone) {
    2868            0 :                     ShowWarningError(state,
    2869            0 :                                      format("Zone name = {} is not accounted for by {} object name = {}",
    2870            0 :                                             state.dataHeatBal->Zone(NumZone).Name,
    2871            0 :                                             CurrentModuleObjects[static_cast<int>(CMO::MechVentilation)],
    2872            0 :                                             thisOAController.VentilationMechanicalName));
    2873            0 :                     ShowContinueError(state, "Ventilation per unit floor area has not been specified for this zone, which is connected to");
    2874            0 :                     ShowContinueError(
    2875            0 :                         state, format("the air loop served by Controller:OutdoorAir = {}. Simulation will continue...", thisOAController.Name));
    2876              :                 }
    2877          405 :                 if (!FoundPeopleZone) {
    2878              :                     // Loop through people objects to see if this zone has a people object and only then show a warning
    2879         3337 :                     for (int PeopleNum = 1; PeopleNum <= state.dataHeatBal->TotPeople; ++PeopleNum) {
    2880         3271 :                         if (state.dataHeatBal->People(PeopleNum).ZonePtr == NumZone) {
    2881           62 :                             if (!FoundAreaZone) {
    2882            0 :                                 ShowWarningError(state,
    2883            0 :                                                  format("PEOPLE object for zone = {} is not accounted for by {} object name = {}",
    2884            0 :                                                         state.dataHeatBal->Zone(NumZone).Name,
    2885            0 :                                                         CurrentModuleObjects[static_cast<int>(CMO::MechVentilation)],
    2886            0 :                                                         thisOAController.VentilationMechanicalName));
    2887            0 :                                 ShowContinueError(
    2888              :                                     state,
    2889            0 :                                     format(
    2890              :                                         "A \"PEOPLE\" object has been specified in the idf for this zone, but it is not included in this {} Object.",
    2891            0 :                                         CurrentModuleObjects[static_cast<int>(CMO::MechVentilation)]));
    2892            0 :                                 ShowContinueError(state,
    2893            0 :                                                   format("Check {} object. Simulation will continue.",
    2894            0 :                                                          CurrentModuleObjects[static_cast<int>(CMO::MechVentilation)]));
    2895              :                             }
    2896              :                         }
    2897              :                     }
    2898              :                 } else { // People > 0, check to make sure there is a people statement in the zone
    2899          339 :                     FoundAreaZone = false;
    2900         7253 :                     for (int PeopleNum = 1; PeopleNum <= state.dataHeatBal->TotPeople; ++PeopleNum) {
    2901         7209 :                         if (state.dataHeatBal->People(PeopleNum).ZonePtr != NumZone) {
    2902         6914 :                             continue;
    2903              :                         }
    2904          295 :                         FoundAreaZone = true;
    2905          295 :                         break;
    2906              :                     }
    2907          339 :                     if (!FoundAreaZone) {
    2908           88 :                         ShowWarningError(state,
    2909           88 :                                          format("{} = \"{}\", Zone=\"{}\".",
    2910           44 :                                                 CurrentModuleObjects[static_cast<int>(CMO::MechVentilation)],
    2911           44 :                                                 thisOAController.VentilationMechanicalName,
    2912           44 :                                                 state.dataHeatBal->Zone(NumZone).Name));
    2913           88 :                         ShowContinueError(state,
    2914              :                                           "No \"PEOPLE\" object has been specified in the idf for this zone, but the ventilation rate is > 0 in "
    2915              :                                           "this Controller:MechanicalVentilation Object.");
    2916          132 :                         ShowContinueError(state, "Check ventilation rate in Controller:MechanicalVentilation object.  Simulation will continue.");
    2917              :                     }
    2918              :                 }
    2919              :             }
    2920              :         }
    2921              : 
    2922         1171 :         state.dataMixedAir->MechVentCheckFlag(OAControllerNum) = false;
    2923              :     }
    2924              :     //****
    2925              : 
    2926              :     // Perform a one time initialization of AirloopHVAC OA System report variables
    2927              :     // If AirloopHVAC objects are used, NumPrimaryAirSys > 0 and the initialization proceeds and then sets
    2928              :     // SetUpAirLoopHVACVariables to .FALSE. so this is never done again and only the first IF is checked
    2929              :     // each time through Init. If for some reason the primary air system have not yet been read in, this
    2930              :     // code waits for the air loop data to be available before performing the report variable initialization.
    2931              :     // If AirloopHVAC objects are not used, NumPrimaryAirSys is always equal to 0 and only these
    2932              :     // two IF statements are checked each time through Init (e.g., if StandAloneERV controllers are used
    2933              :     // without AirloopHVAC objects).
    2934     27596359 :     if (state.dataMixedAir->InitOAControllerSetUpAirLoopHVACVariables) {
    2935         7787 :         if (AirLoopNum > 0) {
    2936              :             // Added code to report (TH, 10/20/2008):
    2937              :             //   air economizer status (1 = on, 0 = off or does not exist), and actual and minimum outside air fraction (0 to 1)
    2938          413 :             std::string airloopName; // Temporary equipment name
    2939         1582 :             for (int OAControllerLoop = 1; OAControllerLoop <= state.dataMixedAir->NumOAControllers; ++OAControllerLoop) {
    2940         1169 :                 auto &loopOAController(state.dataMixedAir->OAController(OAControllerLoop));
    2941              : 
    2942              :                 // Find the outside air system that has the OA controller
    2943         1169 :                 if (loopOAController.ControllerType == MixedAirControllerType::ControllerStandAloneERV) {
    2944          102 :                     continue; // ERV controller not on airloop
    2945              :                 }
    2946         1067 :                 bool OASysFound = false;
    2947         1067 :                 int thisOASys = 0;
    2948         6389 :                 for (int OASysNum = 1; OASysNum <= state.dataAirLoop->NumOASystems; ++OASysNum) {
    2949        11713 :                     for (int OAControllerLoop2 = 1; OAControllerLoop2 <= state.dataAirLoop->OutsideAirSys(OASysNum).NumControllers;
    2950              :                          ++OAControllerLoop2) {
    2951         6391 :                         if (Util::SameString(state.dataAirLoop->OutsideAirSys(OASysNum).ControllerName(OAControllerLoop2), loopOAController.Name)) {
    2952         1067 :                             thisOASys = OASysNum;
    2953         1067 :                             OASysFound = true;
    2954         1067 :                             break;
    2955              :                         }
    2956              :                     }
    2957         6389 :                     if (OASysFound) {
    2958         1067 :                         break;
    2959              :                     }
    2960              :                 }
    2961              : 
    2962         1067 :                 int airLoopNum = 0;
    2963         1067 :                 bool AirLoopFound = false;
    2964         1067 :                 if (thisOASys <= 0) {
    2965              :                     // Check outside air system name
    2966            0 :                     ShowWarningError(state, format("Cannot find the AirLoopHVAC:OutdoorAirSystem for the OA Controller: {}", loopOAController.Name));
    2967              :                 } else {
    2968              :                     // Find the primary air loop that has the outside air system
    2969         6389 :                     for (int thisAirLoop = 1; thisAirLoop <= state.dataHVACGlobal->NumPrimaryAirSys; ++thisAirLoop) {
    2970        11714 :                         for (int BranchNum = 1; BranchNum <= state.dataAirSystemsData->PrimaryAirSystems(thisAirLoop).NumBranches; ++BranchNum) {
    2971        19505 :                             for (int CompNum = 1;
    2972        19505 :                                  CompNum <= state.dataAirSystemsData->PrimaryAirSystems(thisAirLoop).Branch(BranchNum).TotalComponents;
    2973              :                                  ++CompNum) {
    2974        14180 :                                 if (!Util::SameString(state.dataAirSystemsData->PrimaryAirSystems(thisAirLoop).Branch(BranchNum).Comp(CompNum).Name,
    2975        29427 :                                                       state.dataAirLoop->OutsideAirSys(thisOASys).Name) ||
    2976        15247 :                                     !Util::SameString(state.dataAirSystemsData->PrimaryAirSystems(thisAirLoop).Branch(BranchNum).Comp(CompNum).TypeOf,
    2977              :                                                       "AirLoopHVAC:OutdoorAirSystem")) {
    2978        13113 :                                     continue;
    2979              :                                 }
    2980         1067 :                                 AirLoopFound = true;
    2981         1067 :                                 airLoopNum = thisAirLoop;
    2982         1067 :                                 break;
    2983              :                             }
    2984         6392 :                             if (AirLoopFound) {
    2985         1067 :                                 break;
    2986              :                             }
    2987              :                         }
    2988         6389 :                         if (AirLoopFound) {
    2989         1067 :                             break;
    2990              :                         }
    2991              :                     }
    2992              :                 }
    2993              :                 // Check primary air loop name
    2994         1067 :                 if (AirLoopFound && airLoopNum > 0) {
    2995         1067 :                     airloopName = state.dataAirSystemsData->PrimaryAirSystems(airLoopNum).Name; // OutsideAirSys(OASysIndex)%Name
    2996              :                 } else {
    2997            0 :                     ShowWarningError(state, format("Cannot find the primary air loop for the OA Controller: {}", loopOAController.Name));
    2998            0 :                     airloopName = "AirLoop not found";
    2999              :                 }
    3000              : 
    3001              :                 //    Note use of OAControllerLoop here to keep DO Loop index separate from InitOAController local variable
    3002              :                 // CurrentModuleObject='AirLoopHVAC'
    3003         1067 :                 SetupOutputVariable(state,
    3004              :                                     "Air System Outdoor Air Economizer Status",
    3005              :                                     Constant::Units::None,
    3006         1067 :                                     loopOAController.EconomizerStatus,
    3007              :                                     OutputProcessor::TimeStepType::System,
    3008              :                                     OutputProcessor::StoreType::Average,
    3009              :                                     airloopName);
    3010              : 
    3011         1067 :                 SetupOutputVariable(state,
    3012              :                                     "Air System Outdoor Air Heat Recovery Bypass Status",
    3013              :                                     Constant::Units::None,
    3014         1067 :                                     loopOAController.HeatRecoveryBypassStatus,
    3015              :                                     OutputProcessor::TimeStepType::System,
    3016              :                                     OutputProcessor::StoreType::Average,
    3017              :                                     airloopName);
    3018              : 
    3019         1067 :                 SetupOutputVariable(state,
    3020              :                                     "Air System Outdoor Air Heat Recovery Bypass Heating Coil Activity Status",
    3021              :                                     Constant::Units::None,
    3022         1067 :                                     loopOAController.HRHeatingCoilActive,
    3023              :                                     OutputProcessor::TimeStepType::System,
    3024              :                                     OutputProcessor::StoreType::Average,
    3025              :                                     airloopName);
    3026         2134 :                 SetupOutputVariable(state,
    3027              :                                     "Air System Outdoor Air Heat Recovery Bypass Minimum Outdoor Air Mixed Air Temperature",
    3028              :                                     Constant::Units::C,
    3029         1067 :                                     loopOAController.MixedAirTempAtMinOAFlow,
    3030              :                                     OutputProcessor::TimeStepType::System,
    3031              :                                     OutputProcessor::StoreType::Average,
    3032              :                                     airloopName);
    3033              : 
    3034         1067 :                 SetupOutputVariable(state,
    3035              :                                     "Air System Outdoor Air High Humidity Control Status",
    3036              :                                     Constant::Units::None,
    3037         1067 :                                     loopOAController.HighHumCtrlStatus,
    3038              :                                     OutputProcessor::TimeStepType::System,
    3039              :                                     OutputProcessor::StoreType::Average,
    3040              :                                     airloopName);
    3041              : 
    3042         1067 :                 SetupOutputVariable(state,
    3043              :                                     "Air System Outdoor Air Limiting Factor",
    3044              :                                     Constant::Units::None,
    3045         1067 :                                     loopOAController.OALimitingFactorReport,
    3046              :                                     OutputProcessor::TimeStepType::System,
    3047              :                                     OutputProcessor::StoreType::Average,
    3048              :                                     airloopName);
    3049              : 
    3050         2134 :                 SetupOutputVariable(state,
    3051              :                                     "Air System Outdoor Air Flow Fraction",
    3052              :                                     Constant::Units::None,
    3053         1067 :                                     loopOAController.OAFractionRpt,
    3054              :                                     OutputProcessor::TimeStepType::System,
    3055              :                                     OutputProcessor::StoreType::Average,
    3056              :                                     airloopName);
    3057              : 
    3058         2134 :                 SetupOutputVariable(state,
    3059              :                                     "Air System Outdoor Air Minimum Flow Fraction",
    3060              :                                     Constant::Units::None,
    3061         1067 :                                     loopOAController.MinOAFracLimit,
    3062              :                                     OutputProcessor::TimeStepType::System,
    3063              :                                     OutputProcessor::StoreType::Average,
    3064              :                                     airloopName);
    3065              : 
    3066         2134 :                 SetupOutputVariable(state,
    3067              :                                     "Air System Outdoor Air Mass Flow Rate",
    3068              :                                     Constant::Units::kg_s,
    3069         1067 :                                     loopOAController.OAMassFlow,
    3070              :                                     OutputProcessor::TimeStepType::System,
    3071              :                                     OutputProcessor::StoreType::Average,
    3072              :                                     airloopName);
    3073              : 
    3074         2134 :                 SetupOutputVariable(state,
    3075              :                                     "Air System Mixed Air Mass Flow Rate",
    3076              :                                     Constant::Units::kg_s,
    3077         1067 :                                     loopOAController.MixMassFlow,
    3078              :                                     OutputProcessor::TimeStepType::System,
    3079              :                                     OutputProcessor::StoreType::Average,
    3080              :                                     airloopName);
    3081              : 
    3082         2134 :                 SetupOutputVariable(state,
    3083              :                                     "Air System Relief Air Heat Transfer Rate",
    3084              :                                     Constant::Units::W,
    3085         1067 :                                     loopOAController.RelTotalLossRate,
    3086              :                                     OutputProcessor::TimeStepType::System,
    3087              :                                     OutputProcessor::StoreType::Average,
    3088              :                                     airloopName);
    3089              : 
    3090         2134 :                 SetupOutputVariable(state,
    3091              :                                     "Air System Relief Air Sensible Heat Transfer Rate",
    3092              :                                     Constant::Units::W,
    3093         1067 :                                     loopOAController.RelSensiLossRate,
    3094              :                                     OutputProcessor::TimeStepType::System,
    3095              :                                     OutputProcessor::StoreType::Average,
    3096              :                                     airloopName);
    3097              : 
    3098         2134 :                 SetupOutputVariable(state,
    3099              :                                     "Air System Relief Air Latent Heat Transfer Rate",
    3100              :                                     Constant::Units::W,
    3101         1067 :                                     loopOAController.RelLatentLossRate,
    3102              :                                     OutputProcessor::TimeStepType::System,
    3103              :                                     OutputProcessor::StoreType::Average,
    3104              :                                     airloopName);
    3105              : 
    3106         1067 :                 if (loopOAController.MixedAirSPMNum > 0) {
    3107            2 :                     SetupOutputVariable(state,
    3108              :                                         "Air System Outdoor Air Maximum Flow Fraction",
    3109              :                                         Constant::Units::None,
    3110            1 :                                         loopOAController.MaxOAFracBySetPoint,
    3111              :                                         OutputProcessor::TimeStepType::System,
    3112              :                                         OutputProcessor::StoreType::Average,
    3113              :                                         airloopName);
    3114              :                 }
    3115              : 
    3116         1067 :                 if (state.dataGlobal->AnyEnergyManagementSystemInModel) {
    3117          335 :                     SetupEMSInternalVariable(
    3118          335 :                         state, "Outdoor Air Controller Maximum Mass Flow Rate", loopOAController.Name, "[kg/s]", loopOAController.MaxOAMassFlowRate);
    3119          335 :                     SetupEMSInternalVariable(
    3120          335 :                         state, "Outdoor Air Controller Minimum Mass Flow Rate", loopOAController.Name, "[kg/s]", loopOAController.MinOAMassFlowRate);
    3121          335 :                     SetupEMSActuator(state,
    3122              :                                      "Outdoor Air Controller",
    3123              :                                      loopOAController.Name,
    3124              :                                      "Air Mass Flow Rate",
    3125              :                                      "[kg/s]",
    3126          335 :                                      loopOAController.EMSOverrideOARate,
    3127          335 :                                      loopOAController.EMSOARateValue);
    3128              :                 }
    3129              : 
    3130         1067 :                 if (loopOAController.VentMechObjectNum > 0 && airLoopNum > 0) {
    3131          108 :                     SetupOutputVariable(state,
    3132              :                                         "Air System Outdoor Air Mechanical Ventilation Requested Mass Flow Rate",
    3133              :                                         Constant::Units::kg_s,
    3134           54 :                                         loopOAController.MechVentOAMassFlowRequest,
    3135              :                                         OutputProcessor::TimeStepType::System,
    3136              :                                         OutputProcessor::StoreType::Average,
    3137              :                                         airloopName);
    3138           54 :                     if (!state.dataMixedAir->VentilationMechanical(loopOAController.VentMechObjectNum).DCVFlag) {
    3139            3 :                         state.dataAirLoop->AirLoopControlInfo(airLoopNum).AirLoopDCVFlag = false;
    3140              :                     }
    3141              :                 }
    3142              :             }
    3143              : 
    3144          413 :             state.dataMixedAir->InitOAControllerSetUpAirLoopHVACVariables = false;
    3145          413 :         }
    3146              :     }
    3147              : 
    3148              :     // Each time step
    3149     27596359 :     if (FirstHVACIteration) {
    3150              :         // Mixed air setpoint. Set by a setpoint manager.
    3151      9547982 :         if (thisOAController.ControllerType == MixedAirControllerType::ControllerOutsideAir) {
    3152      9402032 :             if (state.dataLoopNodes->Node(thisOAController.MixNode).TempSetPoint > SensedNodeFlagValue) {
    3153      8614788 :                 thisOAController.MixSetTemp = state.dataLoopNodes->Node(thisOAController.MixNode).TempSetPoint;
    3154              :             } else {
    3155       787244 :                 thisOAController.MixSetTemp = thisOAController.TempLowLim;
    3156              :             }
    3157              : 
    3158      9402032 :             Real64 TotalPeopleOAFlow = 0.0;
    3159      9402032 :             if (thisOAController.VentMechObjectNum != 0) {
    3160       350046 :                 auto &vent_mech(state.dataMixedAir->VentilationMechanical(thisOAController.VentMechObjectNum));
    3161      3536980 :                 for (int ZoneIndex = 1; ZoneIndex <= vent_mech.NumofVentMechZones; ++ZoneIndex) {
    3162      3186934 :                     auto &thisVentMechZone = vent_mech.VentMechZone(ZoneIndex);
    3163      3186934 :                     int ZoneNum = thisVentMechZone.zoneNum;
    3164              : 
    3165              :                     // ZoneIntGain(ZoneNum)%NOFOCC is the number of occupants of a zone at each time step, already counting the occupant schedule
    3166      3186934 :                     OAFlowCalcMethod OAFlowMethod = thisVentMechZone.ZoneOAFlowMethod;
    3167      3186934 :                     if (OAFlowMethod == OAFlowCalcMethod::PerPerson || OAFlowMethod == OAFlowCalcMethod::Sum ||
    3168              :                         OAFlowMethod == OAFlowCalcMethod::Max) {
    3169      3186934 :                         TotalPeopleOAFlow += state.dataHeatBal->ZoneIntGain(ZoneNum).NOFOCC * state.dataHeatBal->Zone(ZoneNum).Multiplier *
    3170      6373868 :                                              state.dataHeatBal->Zone(ZoneNum).ListMultiplier * thisVentMechZone.ZoneOAPeopleRate *
    3171      3186934 :                                              thisVentMechZone.zoneOASched->getCurrentVal();
    3172              :                     }
    3173              :                 }
    3174       350046 :                 vent_mech.TotPeopleOAFlow = TotalPeopleOAFlow;
    3175              :             }
    3176              :         } else {
    3177              :             // Stand Alone ERV does not require a temperature setpoint schedule, make setpoint equal to lower economizer limit
    3178       145950 :             thisOAController.MixSetTemp = thisOAController.TempLowLim;
    3179              :         }
    3180              :     }
    3181              : 
    3182              :     // Each iteration
    3183              : 
    3184     27596359 :     if (thisOAController.ControllerType == MixedAirControllerType::ControllerOutsideAir) {
    3185              :         // zone exhaust mass flow is saved in AirLoopFlow%ZoneExhaust
    3186              :         // the zone exhaust mass flow that is said to be balanced by simple air flows is saved in AirLoopFlow%ZoneExhaustBalanced
    3187     27032378 :         if (AirLoopNum > 0) {
    3188     27032378 :             thisOAController.ExhMassFlow =
    3189     27032378 :                 max(0.0, state.dataAirLoop->AirLoopFlow(AirLoopNum).SupFlow - state.dataAirLoop->AirLoopFlow(AirLoopNum).SysRetFlow);
    3190     27032378 :             state.dataAirLoop->AirLoopControlInfo(AirLoopNum).ZoneExhMassFlow = thisOAController.ExhMassFlow;
    3191     27032378 :             if (state.dataAirLoop->AirLoopControlInfo(AirLoopNum).LoopFlowRateSet && !FirstHVACIteration) {
    3192              :                 // if flow rate has been specified by a manager, set it to the specified value
    3193       300983 :                 thisOAController.MixMassFlow =
    3194       300983 :                     state.dataAirLoop->AirLoopFlow(AirLoopNum).ReqSupplyFrac * state.dataAirLoop->AirLoopFlow(AirLoopNum).DesSupply;
    3195              :                 // state.dataLoopNodes->Node(thisOAController.RetNode).MassFlowRate = thisOAController.MixMassFlow - thisOAController.ExhMassFlow;
    3196              :             } else {
    3197     26731395 :                 thisOAController.MixMassFlow = state.dataLoopNodes->Node(thisOAController.RetNode).MassFlowRate + thisOAController.ExhMassFlow;
    3198              : 
    3199              :                 // The following was commented out after discussion on PR 7382, it can be reopened for discussion anytime
    3200              :                 // found this equation results in flow that exceeds the design flow rate when there is exhaust flow rate is greater than
    3201              :                 // the design supply air flow rate. Capped the mixed air flow rate at design supply air flow rate, issue #77379
    3202              :                 // thisOAController.MixMassFlow = Node(thisOAController.RetNode).MassFlowRate + thisOAController.ExhMassFlow;
    3203              :                 // thisOAController.MixMassFlow =
    3204              :                 //     min(Node(thisOAController.RetNode).MassFlowRate + thisOAController.ExhMassFlow, AirLoopFlow(AirLoopNum).DesSupply);
    3205              :             }
    3206              :         } else {
    3207            0 :             thisOAController.ExhMassFlow = 0.0;
    3208            0 :             thisOAController.MixMassFlow = state.dataLoopNodes->Node(thisOAController.RetNode).MassFlowRate;
    3209              :         }
    3210     27032378 :         if (state.dataLoopNodes->Node(thisOAController.MixNode).MassFlowRateMaxAvail <= 0.0) {
    3211      1804558 :             thisOAController.MixMassFlow = 0.0;
    3212              :         }
    3213              :     } else {
    3214              :         // Mixed and exhaust flow rates are passed through to model CONTROLLER:STAND ALONE ERV in SimOAController
    3215       563981 :         thisOAController.OAMassFlow = thisOAController.MaxOAMassFlowRate;
    3216       563981 :         thisOAController.MixMassFlow = thisOAController.MaxOAMassFlowRate;
    3217       563981 :         thisOAController.ExhMassFlow = state.dataLoopNodes->Node(thisOAController.RetNode).MassFlowRate;
    3218              :     }
    3219     27596359 :     thisOAController.ExhMassFlow = max(thisOAController.ExhMassFlow, 0.0);
    3220              : 
    3221              :     // Outside air values
    3222     27596359 :     thisOAController.OATemp = state.dataLoopNodes->Node(thisOAController.OANode).Temp;
    3223     27596359 :     thisOAController.OAEnth = state.dataLoopNodes->Node(thisOAController.OANode).Enthalpy;
    3224     27596359 :     thisOAController.OAPress = state.dataLoopNodes->Node(thisOAController.OANode).Press;
    3225     27596359 :     thisOAController.OAHumRat = state.dataLoopNodes->Node(thisOAController.OANode).HumRat;
    3226              : 
    3227              :     // Inlet air values (on OA input side)
    3228     27596359 :     thisOAController.InletTemp = state.dataLoopNodes->Node(thisOAController.InletNode).Temp;
    3229     27596359 :     thisOAController.InletEnth = state.dataLoopNodes->Node(thisOAController.InletNode).Enthalpy;
    3230     27596359 :     thisOAController.InletPress = state.dataLoopNodes->Node(thisOAController.InletNode).Press;
    3231     27596359 :     thisOAController.InletHumRat = state.dataLoopNodes->Node(thisOAController.InletNode).HumRat;
    3232              : 
    3233              :     // Return air values
    3234     27596359 :     thisOAController.RetTemp = state.dataLoopNodes->Node(thisOAController.RetNode).Temp;
    3235     27596359 :     thisOAController.RetEnth = state.dataLoopNodes->Node(thisOAController.RetNode).Enthalpy;
    3236              : 
    3237              :     // Check sensors faults for the air economizer
    3238     27596359 :     EconoOp iEco = thisOAController.Econo;
    3239     27596359 :     if (state.dataFaultsMgr->AnyFaultsInModel && (iEco != EconoOp::NoEconomizer)) {
    3240      1745265 :         for (int i = 1; i <= thisOAController.NumFaultyEconomizer; ++i) {
    3241       241121 :             int j = thisOAController.EconmizerFaultNum(i);
    3242       241121 :             Real64 rSchVal = 0.0;
    3243       241121 :             if (state.dataFaultsMgr->FaultsEconomizer(j).availSched->getCurrentVal() > 0.0) {
    3244       241121 :                 rSchVal = 1.0;
    3245       241121 :                 if (state.dataFaultsMgr->FaultsEconomizer(j).severitySched != nullptr) {
    3246       241121 :                     rSchVal = state.dataFaultsMgr->FaultsEconomizer(j).severitySched->getCurrentVal();
    3247              :                 }
    3248              :             } else {
    3249            0 :                 continue; // no fault
    3250              :             }
    3251              : 
    3252       241121 :             Real64 rOffset = rSchVal * state.dataFaultsMgr->FaultsEconomizer(j).Offset;
    3253              : 
    3254       241121 :             if (std::abs(rOffset) < 0.000000001) {
    3255         8360 :                 continue;
    3256              :             }
    3257              : 
    3258              :             // ECONOMIZER - outdoor air dry-bulb temperature sensor offset
    3259       232761 :             switch (iEco) {
    3260       232761 :             case EconoOp::FixedDryBulb:
    3261              :             case EconoOp::DifferentialDryBulb:
    3262              :             case EconoOp::FixedDewPointAndDryBulb:
    3263              :             case EconoOp::ElectronicEnthalpy:
    3264              :             case EconoOp::DifferentialDryBulbAndEnthalpy: {
    3265       232761 :                 if (state.dataFaultsMgr->FaultsEconomizer(j).type == FaultType::TemperatureSensorOffset_OutdoorAir) {
    3266              :                     // FaultModel:TemperatureSensorOffset:OutdoorAir
    3267        38685 :                     thisOAController.OATemp += rOffset;
    3268        38685 :                     thisOAController.InletTemp += rOffset;
    3269              :                 }
    3270       232761 :             } break;
    3271            0 :             default:
    3272            0 :                 break;
    3273              :             }
    3274              : 
    3275              :             // ECONOMIZER - outdoor air humidity ratio sensor offset. really needed ???
    3276       232761 :             switch (iEco) {
    3277            0 :             case EconoOp::FixedDewPointAndDryBulb:
    3278              :             case EconoOp::ElectronicEnthalpy: {
    3279            0 :                 if (state.dataFaultsMgr->FaultsEconomizer(j).type == FaultType::HumiditySensorOffset_OutdoorAir) {
    3280              :                     // FaultModel:HumiditySensorOffset:OutdoorAir
    3281            0 :                     thisOAController.OAHumRat += rOffset;
    3282            0 :                     thisOAController.InletHumRat += rOffset;
    3283              :                 }
    3284            0 :             } break;
    3285       232761 :             default:
    3286       232761 :                 break;
    3287              :             }
    3288              : 
    3289              :             // ECONOMIZER - outdoor air enthalpy sensor offset
    3290       232761 :             switch (iEco) {
    3291            0 :             case EconoOp::FixedEnthalpy:
    3292              :             case EconoOp::ElectronicEnthalpy:
    3293              :             case EconoOp::DifferentialDryBulbAndEnthalpy: {
    3294            0 :                 if (state.dataFaultsMgr->FaultsEconomizer(j).type == FaultType::EnthalpySensorOffset_OutdoorAir) {
    3295              :                     // FaultModel:EnthalpySensorOffset:OutdoorAir
    3296            0 :                     thisOAController.OAEnth += rOffset;
    3297            0 :                     thisOAController.InletEnth += rOffset;
    3298              :                 }
    3299            0 :             } break;
    3300       232761 :             default:
    3301       232761 :                 break;
    3302              :             }
    3303              : 
    3304              :             // ECONOMIZER - return air dry-bulb temperature sensor offset
    3305       232761 :             switch (iEco) {
    3306       232761 :             case EconoOp::DifferentialDryBulb:
    3307              :             case EconoOp::DifferentialDryBulbAndEnthalpy: {
    3308       232761 :                 if (state.dataFaultsMgr->FaultsEconomizer(j).type == FaultType::TemperatureSensorOffset_ReturnAir) {
    3309              :                     // FaultModel:TemperatureSensorOffset:ReturnAir
    3310        49993 :                     thisOAController.RetTemp += rOffset;
    3311              :                 }
    3312       232761 :             } break;
    3313            0 :             default:
    3314            0 :                 break;
    3315              :             }
    3316              : 
    3317              :             // ECONOMIZER - return air enthalpy sensor offset
    3318       232761 :             switch (iEco) {
    3319            0 :             case EconoOp::ElectronicEnthalpy:
    3320              :             case EconoOp::DifferentialDryBulbAndEnthalpy: {
    3321            0 :                 if (state.dataFaultsMgr->FaultsEconomizer(j).type == FaultType::EnthalpySensorOffset_ReturnAir) {
    3322              :                     // FaultModel:EnthalpySensorOffset:ReturnAir
    3323            0 :                     thisOAController.RetEnth += rOffset;
    3324              :                 }
    3325            0 :             } break;
    3326       232761 :             default:
    3327       232761 :                 break;
    3328              :             }
    3329              :         }
    3330              :     }
    3331              : 
    3332     27596359 :     if (ErrorsFound) {
    3333            0 :         ShowFatalError(state, format("Error in {}; program terminated", CurrentModuleObjects[static_cast<int>(CMO::OAController)]));
    3334              :     }
    3335     27596359 : } // namespace MixedAir
    3336              : 
    3337     60004604 : void OAMixerProps::InitOAMixer(EnergyPlusData &state)
    3338              : {
    3339              :     // SUBROUTINE INFORMATION:
    3340              :     //       AUTHOR         Fred Buhl
    3341              :     //       DATE WRITTEN   Oct 1998
    3342              : 
    3343              :     // PURPOSE OF THIS SUBROUTINE
    3344              :     // Initialize the OAMixer data structure with input node data
    3345              : 
    3346     60004604 :     int RetNode = this->RetNode;
    3347     60004604 :     int InletNode = this->InletNode;
    3348     60004604 :     int RelNode = this->RelNode;
    3349              : 
    3350              :     // Return air stream data
    3351     60004604 :     this->RetTemp = state.dataLoopNodes->Node(RetNode).Temp;
    3352     60004604 :     this->RetHumRat = state.dataLoopNodes->Node(RetNode).HumRat;
    3353     60004604 :     this->RetEnthalpy = state.dataLoopNodes->Node(RetNode).Enthalpy;
    3354     60004604 :     this->RetPressure = state.dataLoopNodes->Node(RetNode).Press;
    3355     60004604 :     this->RetMassFlowRate = state.dataLoopNodes->Node(RetNode).MassFlowRate;
    3356              :     // Outside air stream data
    3357     60004604 :     this->OATemp = state.dataLoopNodes->Node(InletNode).Temp;
    3358     60004604 :     this->OAHumRat = state.dataLoopNodes->Node(InletNode).HumRat;
    3359     60004604 :     this->OAEnthalpy = state.dataLoopNodes->Node(InletNode).Enthalpy;
    3360     60004604 :     this->OAPressure = state.dataLoopNodes->Node(InletNode).Press;
    3361     60004604 :     this->OAMassFlowRate = state.dataLoopNodes->Node(InletNode).MassFlowRate;
    3362              :     // Relief air data
    3363     60004604 :     this->RelMassFlowRate = state.dataLoopNodes->Node(RelNode).MassFlowRate;
    3364     60004604 : }
    3365              : 
    3366     27596359 : void OAControllerProps::CalcOAController(EnergyPlusData &state, int const AirLoopNum, bool const FirstHVACIteration)
    3367              : {
    3368              : 
    3369              :     // SUBROUTINE INFORMATION:
    3370              :     //       AUTHOR         Fred Buhl
    3371              :     //       DATE WRITTEN   Oct 1998
    3372              :     //       MODIFIED       Shirey/Raustad FSEC, June 2003
    3373              :     //                      Tianzhen Hong, Feb 2009 for new DCV
    3374              :     //                      Brent Griffith ,EMS override of OA rate
    3375              :     //                      Mangesh Basarkar, 06/2011: Modifying outside air calculation based on DCV flag
    3376              :     //                      Chandan Sharma, FSEC, 25Aug 2011 - Added ProportionalControl
    3377              :     //                           to enhance CO2 based DCV control
    3378              :     //                      Tianzhen Hong, March 2012, zone maximum OA fraction - a TRACE feature
    3379              :     //                      Tianzhen Hong, March 2012, multi-path VRP based on ASHRAE 62.1-2010
    3380              : 
    3381              :     // PURPOSE OF THIS SUBROUTINE
    3382              :     // Determine the outside air flow
    3383              : 
    3384              :     // REFERENCES:
    3385              :     // DOE-2.1E Supplement pages 3.97 - 3.100
    3386              :     // BLAST User Reference pages 183 - 186
    3387              :     // ASHRAE Standard 62.1-2010
    3388              : 
    3389              :     // SUBROUTINE PARAMETER DEFINITIONS:
    3390              :     static constexpr std::string_view RoutineName("CalcOAController: ");
    3391              : 
    3392              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    3393     27596359 :     Real64 OASignal = 0.0;                  // Outside air flow rate fraction (0.0 to 1.0)
    3394     27596359 :     bool AirLoopCyclingFan = false;         // Type of air loop fan (TRUE if Fan:OnOff)
    3395     27596359 :     bool HighHumidityOperationFlag = false; // TRUE if zone humidistat senses a high humidity condition
    3396              : 
    3397     27596359 :     if (AirLoopNum > 0) {
    3398     27032378 :         AirLoopCyclingFan = (state.dataAirLoop->AirLoopControlInfo(AirLoopNum).fanOp == HVAC::FanOp::Cycling);
    3399              :     } else {
    3400       563981 :         AirLoopCyclingFan = false;
    3401              :     }
    3402              : 
    3403     27596359 :     this->OALimitingFactor = OALimitFactor::None; // oa controller limiting factor
    3404              : 
    3405              :     // Check for no flow
    3406     27596359 :     if (this->MixMassFlow <= HVAC::SmallMassFlow) {
    3407              : 
    3408      1993256 :         this->OAMassFlow = 0.0;     // outside air mass flow rate
    3409      1993256 :         this->RelMassFlow = 0.0;    // relief air mass flow rate
    3410      1993256 :         this->MixMassFlow = 0.0;    // mixed air mass flow rate
    3411      1993256 :         this->MinOAFracLimit = 0.0; // minimum OA fraction limit
    3412              : 
    3413      1993256 :         this->EconomizerStatus = 0;                                                    // economizer status for reporting
    3414      1993256 :         this->HeatRecoveryBypassStatus = 0;                                            // HR bypass status for reporting
    3415      1993256 :         this->HRHeatingCoilActive = 0;                                                 // resets report variable
    3416      1993256 :         this->MixedAirTempAtMinOAFlow = state.dataLoopNodes->Node(this->RetNode).Temp; // track return T
    3417      1993256 :         this->HighHumCtrlStatus = 0;                                                   // high humidity control status for reporting
    3418      1993256 :         this->OAFractionRpt = 0.0;                                                     // actual OA fraction for reporting
    3419              : 
    3420      1993256 :         this->EconoActive = false;       // DataAirLoop variable (OA Controllers)
    3421      1993256 :         this->HighHumCtrlActive = false; // DataAirLoop variable (OA Controllers)
    3422              : 
    3423              :         // also reset air loop data for use by other routines
    3424      1993256 :         if (AirLoopNum > 0) {
    3425      1993154 :             auto &curAirLoopControlInfo(state.dataAirLoop->AirLoopControlInfo(AirLoopNum));
    3426      1993154 :             auto &curAirLoopFlow(state.dataAirLoop->AirLoopFlow(AirLoopNum));
    3427              : 
    3428      1993154 :             curAirLoopControlInfo.EconoActive = false;        // DataAirLoop variable (AirloopHVAC)
    3429      1993154 :             curAirLoopControlInfo.HeatRecoveryBypass = false; // DataAirLoop variable (AirloopHVAC)
    3430      1993154 :             curAirLoopControlInfo.HighHumCtrlActive = false;  // DataAirLoop variable (AirloopHVAC)
    3431      1993154 :             curAirLoopControlInfo.ResimAirLoopFlag = false;   // DataAirLoop variable (AirloopHVAC)
    3432      1993154 :             curAirLoopFlow.OAFrac = 0.0;                      // DataAirLoop variable (AirloopHVAC)
    3433      1993154 :             curAirLoopFlow.OAMinFrac = 0.0;                   // DataAirLoop variable (AirloopHVAC)
    3434      1993154 :             curAirLoopFlow.MinOutAir = 0.0;
    3435      1993154 :             curAirLoopFlow.OAFlow = 0.0;
    3436              :         }
    3437      1993256 :         return;
    3438              :     }
    3439              : 
    3440     25603103 :     Real64 OutAirMinFrac = 0.0; // Local variable used to calculate min OA fraction
    3441     25603103 :     if (AirLoopNum > 0) {
    3442     25039224 :         auto const &curAirLoopFlow(state.dataAirLoop->AirLoopFlow(AirLoopNum));
    3443     25039224 :         if (curAirLoopFlow.DesSupply >= HVAC::SmallAirVolFlow) {
    3444     25039224 :             OutAirMinFrac = this->MinOAMassFlowRate / curAirLoopFlow.DesSupply;
    3445              :         }
    3446              :     } else {
    3447       563879 :         if (this->MaxOA >= HVAC::SmallAirVolFlow) {
    3448       563879 :             OutAirMinFrac = this->MinOA / this->MaxOA;
    3449              :         }
    3450              :     }
    3451     25603103 :     Real64 MinOASchedVal = 1.0; // value of the minimum outside air schedule
    3452     25603103 :     if (this->minOASched != nullptr) {
    3453     24345318 :         MinOASchedVal = this->minOASched->getCurrentVal();
    3454     24345318 :         MinOASchedVal = min(max(MinOASchedVal, 0.0), 1.0);
    3455     24345318 :         OutAirMinFrac *= MinOASchedVal;
    3456     24345318 :         this->OALimitingFactor = OALimitFactor::Limits;
    3457              :     }
    3458              : 
    3459              :     // Get outside air mass flow rate calculated by mechanical ventilation object [kg/s]
    3460     25603103 :     Real64 MechVentOutsideAirMinFrac = 0.0; // fraction of OA specified by mechanical ventilation object
    3461     25603103 :     if (AirLoopNum > 0 && this->VentMechObjectNum != 0) {
    3462      1261261 :         auto const &curAirLoopControlInfo(state.dataAirLoop->AirLoopControlInfo(AirLoopNum));
    3463      1261261 :         auto const &curAirLoopFlow(state.dataAirLoop->AirLoopFlow(AirLoopNum));
    3464              : 
    3465              :         // Get system supply air flow rate
    3466      1261261 :         Real64 SysSA = 0.0; // System supply air mass flow rate [kg/s]
    3467      1261261 :         if (curAirLoopControlInfo.LoopFlowRateSet) {
    3468              :             // if flow rate has been specified by a manager, set it to the specified value
    3469              :             // DesSupply and SupFlow are mass flow rate in kg/s
    3470            0 :             SysSA = curAirLoopFlow.ReqSupplyFrac * curAirLoopFlow.DesSupply;
    3471              :         } else {
    3472      1261261 :             SysSA = curAirLoopFlow.SupFlow;
    3473              :         }
    3474              : 
    3475      1261261 :         this->MechVentOAMassFlowRequest = state.dataMixedAir->VentilationMechanical(this->VentMechObjectNum).CalcMechVentController(state, SysSA);
    3476      1261261 :         MechVentOutsideAirMinFrac = this->MechVentOAMassFlowRequest / curAirLoopFlow.DesSupply;
    3477      1261261 :         if (curAirLoopFlow.FanPLR > 0.0) {
    3478      1260276 :             MechVentOutsideAirMinFrac *= curAirLoopFlow.FanPLR;
    3479      1260276 :             this->MechVentOAMassFlowRequest *= curAirLoopFlow.FanPLR;
    3480              :         }
    3481      1261261 :     } else {
    3482     24341842 :         this->MechVentOAMassFlowRequest = 0.0;
    3483              :     }
    3484              :     //****** use greater of Mechanical Ventilation Outside Air fraction and OutAirMinFrac
    3485     25603103 :     if ((MechVentOutsideAirMinFrac > 0.0) && (OutAirMinFrac > MechVentOutsideAirMinFrac)) {
    3486            0 :         if (!state.dataGlobal->WarmupFlag) {
    3487            0 :             if (this->CountMechVentFrac == 0) {
    3488            0 :                 ++this->CountMechVentFrac;
    3489            0 :                 ShowWarningError(
    3490              :                     state,
    3491            0 :                     format("{}Minimum OA fraction > Mechanical Ventilation Controller request for Controller:OutdoorAir={}, Min OA fraction is used.",
    3492              :                            RoutineName,
    3493            0 :                            this->Name));
    3494            0 :                 ShowContinueError(state,
    3495              :                                   "This may be overriding desired ventilation controls. Check inputs for Minimum Outdoor Air Flow Rate, Minimum "
    3496              :                                   "Outdoor Air Schedule Name and Controller:MechanicalVentilation");
    3497            0 :                 ShowContinueErrorTimeStamp(
    3498            0 :                     state, format("Minimum OA fraction = {:.4R}, Mech Vent OA fraction = {:.4R}", OutAirMinFrac, MechVentOutsideAirMinFrac));
    3499              :             } else {
    3500            0 :                 ShowRecurringWarningErrorAtEnd(state,
    3501            0 :                                                "Controller:OutdoorAir=\"" + this->Name +
    3502              :                                                    "\": Min OA fraction > Mechanical ventilation OA fraction, continues...",
    3503            0 :                                                this->IndexMechVentFrac,
    3504              :                                                OutAirMinFrac,
    3505              :                                                OutAirMinFrac);
    3506              :             }
    3507              :         }
    3508              :     }
    3509     25603103 :     if (MechVentOutsideAirMinFrac > OutAirMinFrac) {
    3510       859913 :         OutAirMinFrac = MechVentOutsideAirMinFrac;
    3511       859913 :         this->OALimitingFactor = OALimitFactor::DCV;
    3512              :     }
    3513              : 
    3514     25603103 :     OutAirMinFrac = min(max(OutAirMinFrac, 0.0), 1.0);
    3515              : 
    3516              :     // At this point, OutAirMinFrac is still based on AirLoopFlow.DesSupply
    3517     25603103 :     if (AirLoopNum > 0) {
    3518     25039224 :         auto &curAirLoopFlow(state.dataAirLoop->AirLoopFlow(AirLoopNum));
    3519              : 
    3520     25039224 :         curAirLoopFlow.MinOutAir = OutAirMinFrac * curAirLoopFlow.DesSupply;
    3521              : 
    3522              :         // calculate mixed air temp at min OA flow rate
    3523     25039224 :         Real64 ReliefMassFlowAtMinOA = max(curAirLoopFlow.MinOutAir - this->ExhMassFlow, 0.0);
    3524     25039224 :         Real64 RecircMassFlowRateAtMinOAFlow = max(state.dataLoopNodes->Node(this->RetNode).MassFlowRate - ReliefMassFlowAtMinOA, 0.0);
    3525     25039224 :         if ((RecircMassFlowRateAtMinOAFlow + curAirLoopFlow.MinOutAir) > 0.0) {
    3526     25027595 :             Real64 RecircTemp = state.dataLoopNodes->Node(this->RetNode).Temp; // return air temp used for custom economizer control calculation
    3527     25027595 :             this->MixedAirTempAtMinOAFlow =
    3528     25027595 :                 (RecircMassFlowRateAtMinOAFlow * RecircTemp + curAirLoopFlow.MinOutAir * state.dataLoopNodes->Node(this->OANode).Temp) /
    3529     25027595 :                 (RecircMassFlowRateAtMinOAFlow + curAirLoopFlow.MinOutAir);
    3530              :         } else {
    3531        11629 :             this->MixedAirTempAtMinOAFlow = state.dataLoopNodes->Node(this->RetNode).Temp;
    3532              :         }
    3533              :     }
    3534              : 
    3535              :     // Economizer
    3536     25603103 :     this->CalcOAEconomizer(state, AirLoopNum, OutAirMinFrac, OASignal, HighHumidityOperationFlag, FirstHVACIteration);
    3537              : 
    3538     25603103 :     this->OAMassFlow = OASignal * this->MixMassFlow;
    3539              : 
    3540              :     // Do not allow OA to be below Ventilation:Mechanical flow rate or above mixed mass flow rate
    3541     25603103 :     if (AirLoopNum > 0 && VentMechObjectNum != 0) {
    3542      1261261 :         if (this->MechVentOAMassFlowRequest > this->OAMassFlow) {
    3543       582317 :             this->OAMassFlow = min(this->MechVentOAMassFlowRequest, this->MixMassFlow);
    3544              :         }
    3545              :     }
    3546              : 
    3547              :     // Do not allow OA to be below Exh for controller:outside air
    3548     25603103 :     if (this->ControllerType == MixedAirControllerType::ControllerOutsideAir) {
    3549     25039224 :         if (this->ExhMassFlow > this->OAMassFlow) {
    3550       985548 :             this->OAMassFlow = this->ExhMassFlow;
    3551       985548 :             this->OALimitingFactor = OALimitFactor::Exhaust;
    3552              :         }
    3553              :     }
    3554              : 
    3555              :     // if fixed minimum, don't let go below min OA
    3556     25603103 :     if (this->FixedMin) {
    3557              :         // cycling fans allow "average" min OA to be below minimum
    3558     24683294 :         if (!AirLoopCyclingFan) {
    3559     21910918 :             Real64 minOASchedMassFlowRate = this->MinOAMassFlowRate * MinOASchedVal;
    3560     21910918 :             if (minOASchedMassFlowRate > this->OAMassFlow) {
    3561      8031938 :                 this->OAMassFlow = minOASchedMassFlowRate;
    3562      8031938 :                 this->OALimitingFactor = OALimitFactor::Limits;
    3563              :             }
    3564              :         }
    3565              :     }
    3566              : 
    3567              :     // Apply Minimum Fraction of Outdoor Air Schedule
    3568     25603103 :     if (this->minOAflowSched != nullptr) {
    3569      2220879 :         Real64 MinOAflowfracVal = this->minOAflowSched->getCurrentVal();
    3570      2220879 :         MinOAflowfracVal = min(max(MinOAflowfracVal, 0.0), 1.0);
    3571      2220879 :         OutAirMinFrac = max(MinOAflowfracVal, OutAirMinFrac);
    3572      2220879 :         Real64 minOAFracMassFlowRate = this->MixMassFlow * MinOAflowfracVal;
    3573      2220879 :         if (minOAFracMassFlowRate > this->OAMassFlow) {
    3574      1473302 :             this->OAMassFlow = minOAFracMassFlowRate;
    3575      1473302 :             this->OALimitingFactor = OALimitFactor::Limits;
    3576              :         }
    3577              :     }
    3578              : 
    3579              :     // Apply Maximum Fraction of Outdoor Air Schedule
    3580     25603103 :     Real64 currentMaxOAMassFlowRate = this->MaxOAMassFlowRate;
    3581     25603103 :     if (this->maxOAflowSched != nullptr) {
    3582      1162493 :         Real64 MaxOAflowfracVal = this->maxOAflowSched->getCurrentVal();
    3583      1162493 :         MaxOAflowfracVal = min(max(MaxOAflowfracVal, 0.0), 1.0);
    3584      1162493 :         currentMaxOAMassFlowRate = min(this->MaxOAMassFlowRate, this->MixMassFlow * MaxOAflowfracVal);
    3585      1162493 :         OutAirMinFrac = min(MaxOAflowfracVal, OutAirMinFrac);
    3586      1162493 :         if (currentMaxOAMassFlowRate < this->OAMassFlow) {
    3587        39969 :             this->OAMassFlow = currentMaxOAMassFlowRate;
    3588        39969 :             this->OALimitingFactor = OALimitFactor::Limits;
    3589              :         }
    3590              :     }
    3591              : 
    3592              :     // Don't let the OA flow be > than the max OA limit. OA for high humidity control is allowed to be greater than max OA.
    3593              :     // Night Ventilation has priority and may override an OASignal > 1 high humidity condition with OASignal = 1
    3594     25603103 :     if (HighHumidityOperationFlag) {
    3595          394 :         Real64 maxOAMassFlow = this->MaxOAMassFlowRate * max(1.0, OASignal);
    3596          394 :         if (maxOAMassFlow < this->OAMassFlow) {
    3597            0 :             this->OAMassFlow = maxOAMassFlow;
    3598            0 :             this->OALimitingFactor = OALimitFactor::Limits;
    3599              :         }
    3600              :     } else {
    3601     25602709 :         if (this->MaxOAMassFlowRate < this->OAMassFlow) {
    3602       511318 :             this->OAMassFlow = this->MaxOAMassFlowRate;
    3603       511318 :             this->OALimitingFactor = OALimitFactor::Limits;
    3604              :         }
    3605              :     }
    3606              : 
    3607     25603103 :     if (!state.dataGlobal->WarmupFlag && !state.dataGlobal->DoingSizing && (this->ManageDemand) && (this->OAMassFlow > this->DemandLimitFlowRate)) {
    3608         3972 :         this->OAMassFlow = this->DemandLimitFlowRate;
    3609         3972 :         this->OALimitingFactor = OALimitFactor::DemandLimit;
    3610              :     }
    3611     25603103 :     if (this->EMSOverrideOARate) {
    3612            0 :         this->OAMassFlow = this->EMSOARateValue;
    3613            0 :         this->OALimitingFactor = OALimitFactor::EMS;
    3614              :     }
    3615              : 
    3616              :     // Don't let OA flow be > mixed air flow.
    3617              :     // Seems if RAB (return air bypass) that this should be don't let OA flow be > design supply flow but that causes other issues
    3618     25603103 :     if (this->MixMassFlow < this->OAMassFlow) {
    3619       436954 :         this->OAMassFlow = this->MixMassFlow;
    3620       436954 :         this->OALimitingFactor = OALimitFactor::MixedAir;
    3621              :     }
    3622              : 
    3623              :     // save the min outside air flow fraction and max outside air mass flow rate
    3624     25603103 :     if (AirLoopNum > 0) {
    3625     25039224 :         auto &curAirLoopControlInfo(state.dataAirLoop->AirLoopControlInfo(AirLoopNum));
    3626     25039224 :         auto &curAirLoopFlow(state.dataAirLoop->AirLoopFlow(AirLoopNum));
    3627              : 
    3628     25039224 :         curAirLoopFlow.OAMinFrac = OutAirMinFrac;
    3629     25039224 :         if (this->FixedMin) {
    3630     24683294 :             curAirLoopFlow.MinOutAir = min(OutAirMinFrac * curAirLoopFlow.DesSupply, this->MixMassFlow);
    3631              :         } else {
    3632       355930 :             curAirLoopFlow.MinOutAir = OutAirMinFrac * this->MixMassFlow;
    3633              :         }
    3634     25039224 :         if (this->MixMassFlow > 0.0) {
    3635     25039224 :             curAirLoopFlow.OAFrac = this->OAMassFlow / this->MixMassFlow;
    3636     25039224 :             curAirLoopFlow.OAFlow = this->OAMassFlow;
    3637              :         } else {
    3638            0 :             curAirLoopFlow.OAFrac = 0.0;
    3639            0 :             curAirLoopFlow.OAFlow = 0.0;
    3640              :         }
    3641     25039224 :         this->MinOAFracLimit = OutAirMinFrac;
    3642     25039224 :         if (HighHumidityOperationFlag && OASignal > 1.0) {
    3643           62 :             curAirLoopFlow.MaxOutAir = this->MaxOAMassFlowRate * OASignal;
    3644              :         } else {
    3645     25039162 :             curAirLoopFlow.MaxOutAir = currentMaxOAMassFlowRate;
    3646              :         }
    3647              : 
    3648              :         // MJW - Not sure if this is necessary but keeping it for now
    3649     25039224 :         if (curAirLoopControlInfo.HeatingActiveFlag && curAirLoopControlInfo.EconomizerFlowLocked) {
    3650              :             // The airloop needs to be simulated again so that the heating coil & HX can be resimulated
    3651       838844 :             if (curAirLoopControlInfo.HeatRecoveryResimFlag && curAirLoopControlInfo.OASysComponentsSimulated) {
    3652       103516 :                 curAirLoopControlInfo.ResimAirLoopFlag = true;
    3653       103516 :                 curAirLoopControlInfo.HeatRecoveryResimFlag = false;
    3654       103516 :                 curAirLoopControlInfo.HeatRecoveryResimFlag2 = true;
    3655              :                 // on the first iteration, air loop heating coils have not be simulated so HeatingCoilActive=FALSE
    3656              :                 // on the second iteration, the heating coils could have been on, but logic tests here could deactivate heating coil
    3657              :                 // reset heating coil active status and HX since logic tests may turn off heating coil
    3658              :                 // the ResimAirLoopFlag will force another iteration and things should line up on subsequent iterations
    3659       103516 :                 curAirLoopControlInfo.HeatingActiveFlag = false;
    3660       103516 :                 this->HRHeatingCoilActive = 0;
    3661       103516 :                 curAirLoopControlInfo.HeatRecoveryBypass = true;
    3662       103516 :                 this->HeatRecoveryBypassStatus = 1;
    3663       735328 :             } else if (curAirLoopControlInfo.HeatRecoveryResimFlag2) {
    3664       103456 :                 curAirLoopControlInfo.ResimAirLoopFlag = true;
    3665       103456 :                 curAirLoopControlInfo.HeatRecoveryResimFlag2 = false;
    3666              :             } else {
    3667       631872 :                 curAirLoopControlInfo.ResimAirLoopFlag = false;
    3668              :             }
    3669     24200380 :         } else if (curAirLoopControlInfo.HeatingActiveFlag) {
    3670      3042675 :             this->HRHeatingCoilActive = 1;
    3671              :         } else {
    3672     21157705 :             this->HRHeatingCoilActive = 0;
    3673              :         }
    3674              : 
    3675              :     } // if (AirLoopNum > 0)
    3676              : 
    3677              :     // Set the relief air flow rate (must be done last to account for changes in OAMassFlow
    3678     25603103 :     this->RelMassFlow = max(this->OAMassFlow - this->ExhMassFlow, 0.0);
    3679              : 
    3680              :     // Save OA fraction for reporting
    3681     25603103 :     if (this->MixMassFlow > 0) {
    3682     25603103 :         this->OAFractionRpt = this->OAMassFlow / this->MixMassFlow;
    3683              :     } else {
    3684            0 :         if (this->OAMassFlow > 0) {
    3685            0 :             this->OAFractionRpt = OASignal;
    3686              :         } else {
    3687            0 :             this->OAFractionRpt = 0.0;
    3688              :         }
    3689              :     }
    3690     25603103 :     this->RelTemp = this->RetTemp;
    3691     25603103 :     this->RelEnth = this->RetEnth;
    3692     25603103 :     this->RelSensiLossRate =
    3693     25603103 :         this->RelMassFlow * Psychrometrics::PsyCpAirFnW(state.dataEnvrn->OutHumRat) * (this->RelTemp - state.dataEnvrn->OutDryBulbTemp);
    3694     25603103 :     this->RelTotalLossRate = this->RelMassFlow * (this->RelEnth - state.dataEnvrn->OutEnthalpy);
    3695     25603103 :     this->RelLatentLossRate = this->RelTotalLossRate - this->RelSensiLossRate;
    3696     25603103 :     this->OALimitingFactorReport = static_cast<int>(OALimitingFactor);
    3697              : }
    3698              : 
    3699      1261261 : Real64 VentilationMechanicalProps::CalcMechVentController(EnergyPlusData &state,
    3700              :                                                           Real64 SysSA // System supply air mass flow rate [kg/s]
    3701              : )
    3702              : {
    3703              :     static constexpr std::string_view RoutineName("CalcMechVentController: ");
    3704              :     static std::string_view const &CurrentModuleObject(CurrentModuleObjects[static_cast<int>(CMO::MechVentilation)]);
    3705              : 
    3706              :     // new local variables for DCV
    3707              :     // Zone OA flow rate based on each calculation method [m3/s]
    3708      1261261 :     std::array<Real64, static_cast<int>(DataSizing::OAFlowCalcMethod::Num)> ZoneOACalc{0.0};
    3709              :     Real64 ZoneOABZ;         // Zone breathing-zone OA flow rate [m3/s]
    3710              :     Real64 ZoneOA;           // Zone OA flow rate [m3/s]
    3711              :     Real64 ZoneOAFrac;       // Zone OA fraction (as a fraction of actual supply air flow rate)
    3712              :     Real64 SysOAuc;          // System uncorrected OA flow rate
    3713              :     Real64 SysOA;            // System supply OA volume flow rate [m3/s]
    3714              :     Real64 SysEv;            // System ventilation efficiency
    3715              :     Real64 NodeTemp;         // node temperature
    3716              :     Real64 NodeHumRat;       // node humidity ratio
    3717      1261261 :     Real64 ZoneMaxCO2 = 0.0; // Breathing-zone CO2 concentration
    3718      1261261 :     Real64 ZoneMinCO2 = 0.0; // Minimum CO2 concentration in zone
    3719      1261261 :     Real64 ZoneOAMin = 0.0;  // Minimum Zone OA flow rate when the zone is unoccupied (i.e. ZoneOAPeople = 0)
    3720      1261261 :     Real64 ZoneOAMax = 0.0;  // Maximum Zone OA flow rate (ZoneOAPeople + ZoneOACalc[static_cast<int>(DataSizing::OAFlowCalcMethod::PerArea)])
    3721      1261261 :     Real64 MechVentOAMassFlow = 0.0;
    3722              : 
    3723              :     // Apply mechanical ventilation only when it is available/allowed
    3724      1261261 :     if (this->availSched->getCurrentVal() > 0) {
    3725       968939 :         Real64 SysOAMassFlow = 0.0; // System supply OA mass flow rate [kg/s]
    3726       968939 :         if (this->SystemOAMethod == DataSizing::SysOAMethod::IAQP) {
    3727              :             // IAQP for CO2 control
    3728        24528 :             for (int ZoneIndex = 1; ZoneIndex <= this->NumofVentMechZones; ++ZoneIndex) {
    3729        18396 :                 auto &thisMechVentZone = this->VentMechZone(ZoneIndex);
    3730        18396 :                 int ZoneNum = thisMechVentZone.zoneNum;
    3731        18396 :                 SysOAMassFlow +=
    3732        18396 :                     state.dataContaminantBalance->ZoneSysContDemand(ZoneNum).OutputRequiredToCO2SP * thisMechVentZone.zoneOASched->getCurrentVal();
    3733              :             }
    3734         6132 :             MechVentOAMassFlow = SysOAMassFlow;
    3735       962807 :         } else if (this->SystemOAMethod == DataSizing::SysOAMethod::IAQPGC) {
    3736              :             // IAQP for generic contaminant control
    3737        28720 :             for (int ZoneIndex = 1; ZoneIndex <= this->NumofVentMechZones; ++ZoneIndex) {
    3738        21540 :                 auto &thisMechVentZone = this->VentMechZone(ZoneIndex);
    3739        21540 :                 int ZoneNum = thisMechVentZone.zoneNum;
    3740        21540 :                 SysOAMassFlow +=
    3741        21540 :                     state.dataContaminantBalance->ZoneSysContDemand(ZoneNum).OutputRequiredToGCSP * thisMechVentZone.zoneOASched->getCurrentVal();
    3742              :             }
    3743         7180 :             MechVentOAMassFlow = SysOAMassFlow;
    3744       955627 :         } else if (this->SystemOAMethod == DataSizing::SysOAMethod::IAQPCOM) {
    3745              :             // IAQP for both CO2 and generic contaminant control
    3746            0 :             SysOAMassFlow = 0.0;
    3747            0 :             for (int ZoneIndex = 1; ZoneIndex <= this->NumofVentMechZones; ++ZoneIndex) {
    3748            0 :                 auto &thisMechVentZone = this->VentMechZone(ZoneIndex);
    3749            0 :                 int ZoneNum = thisMechVentZone.zoneNum;
    3750            0 :                 SysOAMassFlow +=
    3751            0 :                     state.dataContaminantBalance->ZoneSysContDemand(ZoneNum).OutputRequiredToCO2SP * thisMechVentZone.zoneOASched->getCurrentVal();
    3752              :             }
    3753            0 :             MechVentOAMassFlow = SysOAMassFlow;
    3754            0 :             SysOAMassFlow = 0.0;
    3755            0 :             for (int ZoneIndex = 1; ZoneIndex <= this->NumofVentMechZones; ++ZoneIndex) {
    3756            0 :                 auto &thisMechVentZone = this->VentMechZone(ZoneIndex);
    3757            0 :                 int ZoneNum = thisMechVentZone.zoneNum;
    3758            0 :                 SysOAMassFlow +=
    3759            0 :                     state.dataContaminantBalance->ZoneSysContDemand(ZoneNum).OutputRequiredToGCSP * thisMechVentZone.zoneOASched->getCurrentVal();
    3760              :             }
    3761            0 :             MechVentOAMassFlow = max(SysOAMassFlow, MechVentOAMassFlow);
    3762              :         } else {
    3763              :             // for system OA methods: Zone_Sum, VRP, CO2 methods
    3764              :             // new code for DCV method complying with the VRP defined in ASHRAE Standard 62.1-2010
    3765              : 
    3766              :             // Loop through each zone first to calc uncorrected system OA flow rate
    3767       955627 :             SysOAuc = 0.0;
    3768       955627 :             SysOA = 0.0;
    3769      9276965 :             for (int ZoneIndex = 1; ZoneIndex <= this->NumofVentMechZones; ++ZoneIndex) {
    3770      8321338 :                 auto &thisMechVentZone = this->VentMechZone(ZoneIndex);
    3771      8321338 :                 int ZoneNum = thisMechVentZone.zoneNum;
    3772      8321338 :                 auto const &curZone(state.dataHeatBal->Zone(ZoneNum));
    3773      8321338 :                 Real64 multiplier = curZone.Multiplier * curZone.ListMultiplier * thisMechVentZone.zoneOASched->getCurrentVal();
    3774              : 
    3775              :                 // Calc the zone OA flow rate based on the people component
    3776              :                 // ZoneIntGain(ZoneNum)%NOFOCC is the number of occupants of a zone at each time step, already counting the occupant schedule
    3777              :                 //  Checking DCV flag before calculating zone OA per person
    3778      8321338 :                 if (this->DCVFlag && this->SystemOAMethod != DataSizing::SysOAMethod::ProportionalControlDesOcc) {
    3779      6008678 :                     ZoneOACalc[static_cast<int>(DataSizing::OAFlowCalcMethod::PerPerson)] =
    3780      6008678 :                         state.dataHeatBal->ZoneIntGain(ZoneNum).NOFOCC * thisMechVentZone.ZoneOAPeopleRate;
    3781              :                 } else {
    3782      2312660 :                     ZoneOACalc[static_cast<int>(DataSizing::OAFlowCalcMethod::PerPerson)] = curZone.TotOccupants * thisMechVentZone.ZoneOAPeopleRate;
    3783              :                 }
    3784              : 
    3785              :                 // Calc the zone OA flow rate based on the floor area component
    3786      8321338 :                 ZoneOACalc[static_cast<int>(DataSizing::OAFlowCalcMethod::PerArea)] = curZone.FloorArea * thisMechVentZone.ZoneOAAreaRate;
    3787      8321338 :                 ZoneOACalc[static_cast<int>(DataSizing::OAFlowCalcMethod::PerZone)] = thisMechVentZone.ZoneOAFlowRate;
    3788      8321338 :                 ZoneOACalc[static_cast<int>(DataSizing::OAFlowCalcMethod::ACH)] = (thisMechVentZone.ZoneOAACHRate * curZone.Volume) / 3600.0;
    3789              : 
    3790              :                 // Calc the breathing-zone OA flow rate
    3791      8321338 :                 int OAIndex = thisMechVentZone.ZoneDesignSpecOAObjIndex; // index to design specification outdoor air objects
    3792      8321338 :                 if (OAIndex > 0) {
    3793      8321338 :                     switch (state.dataSize->OARequirements(OAIndex).OAFlowMethod) {
    3794      8163158 :                     case DataSizing::OAFlowCalcMethod::Sum: {
    3795      8163158 :                         ZoneOABZ = multiplier * (ZoneOACalc[static_cast<int>(DataSizing::OAFlowCalcMethod::PerPerson)] +
    3796      8163158 :                                                  ZoneOACalc[static_cast<int>(DataSizing::OAFlowCalcMethod::PerArea)] +
    3797      8163158 :                                                  ZoneOACalc[static_cast<int>(DataSizing::OAFlowCalcMethod::PerZone)] +
    3798      8163158 :                                                  ZoneOACalc[static_cast<int>(DataSizing::OAFlowCalcMethod::ACH)]);
    3799      8163158 :                     } break;
    3800            0 :                     case DataSizing::OAFlowCalcMethod::Max: {
    3801            0 :                         ZoneOABZ = multiplier * max(ZoneOACalc[static_cast<int>(DataSizing::OAFlowCalcMethod::PerPerson)],
    3802            0 :                                                     ZoneOACalc[static_cast<int>(DataSizing::OAFlowCalcMethod::PerArea)],
    3803            0 :                                                     ZoneOACalc[static_cast<int>(DataSizing::OAFlowCalcMethod::PerZone)],
    3804            0 :                                                     ZoneOACalc[static_cast<int>(DataSizing::OAFlowCalcMethod::ACH)]);
    3805              : 
    3806            0 :                     } break;
    3807       158180 :                     default: {
    3808       158180 :                         ZoneOABZ = multiplier * ZoneOACalc[static_cast<int>(state.dataSize->OARequirements(OAIndex).OAFlowMethod)];
    3809       158180 :                         break;
    3810              :                     }
    3811              :                     }
    3812              :                 } else {
    3813            0 :                     ZoneOABZ = multiplier * ZoneOACalc[static_cast<int>(DataSizing::OAFlowCalcMethod::PerPerson)];
    3814              :                 }
    3815              : 
    3816      8321338 :                 if (this->SystemOAMethod == DataSizing::SysOAMethod::ZoneSum) {
    3817              :                     // Sum the zone OA flow rates and done
    3818      1769412 :                     SysOA += ZoneOABZ;
    3819              :                 } else {
    3820              :                     // Calc the uncorrected system OA flow rate - VRP and ProportionalControl
    3821      6551926 :                     SysOAuc += ZoneOABZ;
    3822              :                 }
    3823              :             }
    3824              : 
    3825              :             // get system supply air flow rate
    3826       955627 :             if (this->SystemOAMethod == DataSizing::SysOAMethod::VRP || this->SystemOAMethod == DataSizing::SysOAMethod::ProportionalControlSchOcc ||
    3827       845644 :                 this->SystemOAMethod == DataSizing::SysOAMethod::ProportionalControlDesOcc ||
    3828       839508 :                 this->SystemOAMethod == DataSizing::SysOAMethod::ProportionalControlDesOARate ||
    3829       833368 :                 this->SystemOAMethod == DataSizing::SysOAMethod::VRPL) {
    3830              : 
    3831              :                 // System supply air flow rate is always greater than or equal the system outdoor air flow rate
    3832       787505 :                 if ((SysSA > 0.0) && (SysSA < (SysOAuc * state.dataEnvrn->StdRhoAir))) {
    3833        40065 :                     SysSA = SysOAuc * state.dataEnvrn->StdRhoAir;
    3834              :                 }
    3835              : 
    3836              :                 // calc Xs - average outdoor air fraction
    3837       787505 :                 if (SysSA > 0.0) {
    3838       776993 :                     Xs = (SysOAuc * state.dataEnvrn->StdRhoAir) / SysSA;
    3839              :                 } else {
    3840        10512 :                     Xs = 0.0;
    3841              :                 }
    3842              : 
    3843              :                 // Loop through each zone again
    3844       787505 :                 SysEv = 2.0; // starting with a big fraction
    3845      7339431 :                 for (int ZoneIndex = 1; ZoneIndex <= this->NumofVentMechZones; ++ZoneIndex) {
    3846      6551926 :                     auto &thisMechVentZone = this->VentMechZone(ZoneIndex);
    3847      6551926 :                     int ZoneNum = thisMechVentZone.zoneNum;
    3848      6551926 :                     int ZoneEquipConfigNum = ZoneNum; // correspondence - 1:1 of ZoneEquipConfig to Zone index
    3849      6551926 :                     Real64 ZoneEz = 0.0;              // Zone air distribution effectiveness
    3850              : 
    3851              :                     // Assign references
    3852      6551926 :                     auto &curZone(state.dataHeatBal->Zone(ZoneNum));
    3853      6551926 :                     auto &curZoneSysEnergyDemand(state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ZoneEquipConfigNum));
    3854      6551926 :                     Real64 multiplier = curZone.Multiplier * curZone.ListMultiplier * thisMechVentZone.zoneOASched->getCurrentVal();
    3855              : 
    3856              :                     // Calc the zone OA flow rate based on the people component
    3857              :                     // ZoneIntGain(ZoneNum)%NOFOCC is the number of occupants of a zone at each time step, already counting the occupant schedule
    3858              :                     //  Checking DCV flag before calculating zone OA per person
    3859      6551926 :                     if (this->DCVFlag && this->SystemOAMethod != DataSizing::SysOAMethod::ProportionalControlDesOcc) {
    3860      5598571 :                         ZoneOACalc[static_cast<int>(DataSizing::OAFlowCalcMethod::PerPerson)] =
    3861      5598571 :                             state.dataHeatBal->ZoneIntGain(ZoneNum).NOFOCC * multiplier * thisMechVentZone.ZoneOAPeopleRate;
    3862              :                     } else {
    3863       953355 :                         ZoneOACalc[static_cast<int>(DataSizing::OAFlowCalcMethod::PerPerson)] =
    3864       953355 :                             curZone.TotOccupants * multiplier * thisMechVentZone.ZoneOAPeopleRate;
    3865              :                     }
    3866              : 
    3867              :                     // Calc the zone OA flow rate based on the floor area component
    3868     13103852 :                     ZoneOACalc[static_cast<int>(DataSizing::OAFlowCalcMethod::PerArea)] =
    3869      6551926 :                         curZone.FloorArea * multiplier * thisMechVentZone.ZoneOAAreaRate;
    3870      6551926 :                     ZoneOACalc[static_cast<int>(DataSizing::OAFlowCalcMethod::PerZone)] = multiplier * thisMechVentZone.ZoneOAFlowRate;
    3871     13103852 :                     ZoneOACalc[static_cast<int>(DataSizing::OAFlowCalcMethod::ACH)] =
    3872      6551926 :                         multiplier * (thisMechVentZone.ZoneOAACHRate * curZone.Volume) / 3600.0;
    3873              : 
    3874              :                     // Calc the breathing-zone OA flow rate
    3875      6551926 :                     int OAIndex = thisMechVentZone.ZoneDesignSpecOAObjIndex;
    3876      6551926 :                     if (OAIndex > 0) {
    3877      6551926 :                         switch (state.dataSize->OARequirements(OAIndex).OAFlowMethod) {
    3878      6393746 :                         case DataSizing::OAFlowCalcMethod::Sum: {
    3879      6393746 :                             ZoneOABZ = ZoneOACalc[static_cast<int>(DataSizing::OAFlowCalcMethod::PerPerson)] +
    3880      6393746 :                                        ZoneOACalc[static_cast<int>(DataSizing::OAFlowCalcMethod::PerArea)] +
    3881      6393746 :                                        ZoneOACalc[static_cast<int>(DataSizing::OAFlowCalcMethod::PerZone)] +
    3882      6393746 :                                        ZoneOACalc[static_cast<int>(DataSizing::OAFlowCalcMethod::ACH)];
    3883      6393746 :                         } break;
    3884            0 :                         case DataSizing::OAFlowCalcMethod::Max: {
    3885            0 :                             ZoneOABZ = max(ZoneOACalc[static_cast<int>(DataSizing::OAFlowCalcMethod::PerPerson)],
    3886            0 :                                            ZoneOACalc[static_cast<int>(DataSizing::OAFlowCalcMethod::PerArea)],
    3887            0 :                                            ZoneOACalc[static_cast<int>(DataSizing::OAFlowCalcMethod::PerZone)],
    3888            0 :                                            ZoneOACalc[static_cast<int>(DataSizing::OAFlowCalcMethod::ACH)]);
    3889              : 
    3890            0 :                         } break;
    3891       158180 :                         default: {
    3892       158180 :                             ZoneOABZ = ZoneOACalc[static_cast<int>(state.dataSize->OARequirements(OAIndex).OAFlowMethod)];
    3893       158180 :                             break;
    3894              :                         }
    3895              :                         }
    3896              :                     }
    3897              : 
    3898              :                     // use the ventilation rate procedure in ASHRAE Standard 62.1-2007
    3899              :                     // Calc the zone supplied OA flow rate counting the zone air distribution effectiveness
    3900              :                     //  First check whether the zone air distribution effectiveness schedule exists, if yes uses it;
    3901              :                     //   otherwise uses the inputs of zone distribution effectiveness in cooling mode or heating mode
    3902      6551926 :                     if (thisMechVentZone.zoneADEffSched != nullptr) {
    3903              :                         // Get schedule value for the zone air distribution effectiveness
    3904        24556 :                         ZoneEz = thisMechVentZone.zoneADEffSched->getCurrentVal();
    3905              :                     } else {
    3906      6527370 :                         Real64 ZoneLoad = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ZoneNum).TotalOutputRequired;
    3907              : 
    3908              :                         // Zone in cooling mode
    3909      6527370 :                         if (ZoneLoad < 0.0) {
    3910      3173457 :                             ZoneEz = thisMechVentZone.ZoneADEffCooling;
    3911              :                         }
    3912              : 
    3913              :                         // Zone in heating mode
    3914      6527370 :                         if (ZoneLoad > 0.0) {
    3915      2706597 :                             ZoneEz = thisMechVentZone.ZoneADEffHeating;
    3916              :                         }
    3917              :                     }
    3918      6551926 :                     if (ZoneEz <= 0.0) {
    3919              :                         // Enforce defaults
    3920       647316 :                         ZoneEz = 1.0;
    3921              :                     }
    3922              : 
    3923              :                     // Calc zone supply OA flow rate
    3924      6551926 :                     if (this->SystemOAMethod == DataSizing::SysOAMethod::VRP || this->SystemOAMethod == DataSizing::SysOAMethod::VRPL) {
    3925              :                         // the VRP case
    3926      6496678 :                         ZoneOA = ZoneOABZ / ZoneEz;
    3927              : 
    3928        55248 :                     } else if (this->SystemOAMethod == DataSizing::SysOAMethod::ProportionalControlSchOcc ||
    3929        36828 :                                this->SystemOAMethod == DataSizing::SysOAMethod::ProportionalControlDesOcc ||
    3930        18420 :                                this->SystemOAMethod == DataSizing::SysOAMethod::ProportionalControlDesOARate) {
    3931              :                         // Check whether "Carbon Dioxide Control Availability Schedule" for ZoneControl:ContaminantController is specified
    3932        55248 :                         if (curZone.zoneContamControllerSched != nullptr) {
    3933              :                             // Check the availability schedule value for ZoneControl:ContaminantController
    3934        30688 :                             Real64 ZoneContamControllerSchedVal = curZone.zoneContamControllerSched->getCurrentVal();
    3935        30688 :                             if (ZoneContamControllerSchedVal > 0.0) {
    3936        30688 :                                 ZoneOAMin = ZoneOACalc[static_cast<int>(DataSizing::OAFlowCalcMethod::PerArea)] / ZoneEz;
    3937        30688 :                                 ZoneOAMax = (ZoneOACalc[static_cast<int>(DataSizing::OAFlowCalcMethod::PerArea)] +
    3938        30688 :                                              ZoneOACalc[static_cast<int>(DataSizing::OAFlowCalcMethod::PerPerson)]) /
    3939              :                                             ZoneEz;
    3940        30688 :                                 if (this->SystemOAMethod == DataSizing::SysOAMethod::ProportionalControlDesOARate) {
    3941         6140 :                                     ZoneOAMax = ZoneOABZ / ZoneEz;
    3942         6140 :                                     if (thisMechVentZone.oaPropCtlMinRateSched != nullptr) {
    3943            0 :                                         ZoneOAMin = ZoneOAMax * thisMechVentZone.oaPropCtlMinRateSched->getCurrentVal();
    3944              :                                     } else {
    3945         6140 :                                         ZoneOAMin = ZoneOAMax;
    3946              :                                     }
    3947         6140 :                                     if (ZoneOAMax < ZoneOAMin) {
    3948            0 :                                         ZoneOAMin = ZoneOAMax;
    3949            0 :                                         ++this->OAMaxMinLimitErrorCount;
    3950            0 :                                         if (this->OAMaxMinLimitErrorCount < 2) {
    3951            0 :                                             ShowSevereError(state, format("{}{} = \"{}\".", RoutineName, CurrentModuleObject, this->Name));
    3952            0 :                                             ShowContinueError(
    3953              :                                                 state,
    3954            0 :                                                 format("For System Outdoor Air Method = ProportionalControlBasedOnDesignOARate, maximum zone "
    3955              :                                                        "outdoor air rate ({:.4R}), is not greater than minimum zone outdoor air rate ({:.4R}).",
    3956              :                                                        ZoneOAMax,
    3957              :                                                        ZoneOAMin));
    3958            0 :                                             ShowContinueError(state,
    3959              :                                                               " The minimum zone outdoor air rate is set to the maximum zone outdoor air rate. "
    3960              :                                                               "Simulation continues...");
    3961            0 :                                             ShowContinueErrorTimeStamp(state, "");
    3962              :                                         } else {
    3963            0 :                                             ShowRecurringWarningErrorAtEnd(
    3964              :                                                 state,
    3965            0 :                                                 format("{} = \"{}\", For System Outdoor Air Method = ProportionalControlBasedOnDesignOARate, maximum "
    3966              :                                                        "zone outdoor air rate is not greater than minimum zone outdoor air rate. Error continues...",
    3967              :                                                        CurrentModuleObject,
    3968            0 :                                                        this->Name),
    3969            0 :                                                 this->OAMaxMinLimitErrorIndex);
    3970              :                                         }
    3971              :                                     }
    3972              :                                 }
    3973              : 
    3974        30688 :                                 if (ZoneOACalc[static_cast<int>(DataSizing::OAFlowCalcMethod::PerPerson)] > 0.0) {
    3975        24136 :                                     if (state.dataContaminantBalance->ZoneCO2GainFromPeople(ZoneNum) > 0.0) {
    3976        14320 :                                         if (curZone.zoneMinCO2Sched != nullptr) {
    3977              :                                             // Take the schedule value of "Minimum Carbon Dioxide Concentration Schedule Name"
    3978              :                                             // in the ZoneControl:ContaminantController
    3979        11456 :                                             ZoneMinCO2 = curZone.zoneMinCO2Sched->getCurrentVal();
    3980              :                                         } else {
    3981         2864 :                                             ZoneMinCO2 = state.dataContaminantBalance->OutdoorCO2;
    3982              :                                         }
    3983              : 
    3984              :                                         // Calculate zone maximum target CO2 concentration in PPM
    3985        14320 :                                         if (this->SystemOAMethod == DataSizing::SysOAMethod::ProportionalControlDesOcc) {
    3986              :                                             // Accumulate CO2 generation from people at design occupancy and current activity level
    3987         8592 :                                             Real64 CO2PeopleGeneration = 0.0;
    3988        17184 :                                             for (int const PeopleNum : thisMechVentZone.peopleIndexes) {
    3989         8592 :                                                 CO2PeopleGeneration += state.dataHeatBal->People(PeopleNum).NumberOfPeople *
    3990        17184 :                                                                        state.dataHeatBal->People(PeopleNum).CO2RateFactor *
    3991         8592 :                                                                        state.dataHeatBal->People(PeopleNum).activityLevelSched->getCurrentVal();
    3992         8592 :                                             }
    3993         8592 :                                             ZoneMaxCO2 = state.dataContaminantBalance->OutdoorCO2 +
    3994         8592 :                                                          (CO2PeopleGeneration * curZone.Multiplier * curZone.ListMultiplier * 1.0e6) / ZoneOAMax;
    3995         5728 :                                         } else if (curZone.zoneMaxCO2Sched != nullptr) {
    3996         2864 :                                             ZoneMaxCO2 = curZone.zoneMaxCO2Sched->getCurrentVal();
    3997              :                                         } else {
    3998         2864 :                                             ZoneMaxCO2 = state.dataContaminantBalance->OutdoorCO2 +
    3999         2864 :                                                          (state.dataContaminantBalance->ZoneCO2GainFromPeople(ZoneNum) * curZone.Multiplier *
    4000         2864 :                                                           curZone.ListMultiplier * 1.0e6) /
    4001              :                                                              ZoneOAMax;
    4002              :                                         }
    4003              : 
    4004        14320 :                                         if (ZoneMaxCO2 <= ZoneMinCO2) {
    4005            0 :                                             ++this->CO2MaxMinLimitErrorCount;
    4006            0 :                                             if (this->SystemOAMethod == DataSizing::SysOAMethod::ProportionalControlSchOcc) {
    4007            0 :                                                 if (this->CO2MaxMinLimitErrorCount < 2) {
    4008            0 :                                                     ShowSevereError(state, format("{}{} = \"{}\".", RoutineName, CurrentModuleObject, this->Name));
    4009            0 :                                                     ShowContinueError(
    4010              :                                                         state,
    4011            0 :                                                         format("For System Outdoor Air Method = ProportionalControlBasedOnOccupancySchedule, "
    4012              :                                                                "maximum target CO2 concentration ({:.2R}), is not greater than minimum target "
    4013              :                                                                "CO2 concentration ({:.2R}).",
    4014              :                                                                ZoneMaxCO2,
    4015              :                                                                ZoneMinCO2));
    4016            0 :                                                     ShowContinueError(state,
    4017              :                                                                       "\"ProportionalControlBasedOnOccupancySchedule\" will not be modeled. "
    4018              :                                                                       "Default \"Standard62.1VentilationRateProcedure\" will be modeled. Simulation "
    4019              :                                                                       "continues...");
    4020            0 :                                                     ShowContinueErrorTimeStamp(state, "");
    4021              :                                                 } else {
    4022            0 :                                                     ShowRecurringWarningErrorAtEnd(state,
    4023            0 :                                                                                    format("{} = \"{}\", For System Outdoor Air Method = "
    4024              :                                                                                           "ProportionalControlBasedOnOccupancySchedule, maximum "
    4025              :                                                                                           "target CO2 concentration is not greater than minimum "
    4026              :                                                                                           "target CO2 concentration. Error continues...",
    4027              :                                                                                           CurrentModuleObject,
    4028            0 :                                                                                           this->Name),
    4029            0 :                                                                                    this->CO2MaxMinLimitErrorIndex);
    4030              :                                                 }
    4031              :                                             }
    4032            0 :                                             if (this->SystemOAMethod == DataSizing::SysOAMethod::ProportionalControlDesOcc) {
    4033            0 :                                                 if (this->CO2MaxMinLimitErrorCount < 2) {
    4034            0 :                                                     ShowSevereError(state, format("{}{} = \"{}\".", RoutineName, CurrentModuleObject, this->Name));
    4035            0 :                                                     ShowContinueError(
    4036              :                                                         state,
    4037            0 :                                                         format("For System Outdoor Air Method = ProportionalControlBasedOnDesignOccupancy, "
    4038              :                                                                "maximum target CO2 concentration ({:.2R}), is not greater than minimum target "
    4039              :                                                                "CO2 concentration ({:.2R}).",
    4040              :                                                                ZoneMaxCO2,
    4041              :                                                                ZoneMinCO2));
    4042            0 :                                                     ShowContinueError(state,
    4043              :                                                                       "\"ProportionalControlBasedOnDesignOccupancy\" will not be modeled. "
    4044              :                                                                       "Default \"Standard62.1VentilationRateProcedure\" will be modeled. Simulation "
    4045              :                                                                       "continues...");
    4046            0 :                                                     ShowContinueErrorTimeStamp(state, "");
    4047              :                                                 } else {
    4048            0 :                                                     ShowRecurringWarningErrorAtEnd(state,
    4049            0 :                                                                                    format("{} = \"{}\", For System Outdoor Air Method = "
    4050              :                                                                                           "ProportionalControlBasedOnDesignOccupancy, maximum "
    4051              :                                                                                           "target CO2 concentration is not greater than minimum "
    4052              :                                                                                           "target CO2 concentration. Error continues...",
    4053              :                                                                                           CurrentModuleObject,
    4054            0 :                                                                                           this->Name),
    4055            0 :                                                                                    this->CO2MaxMinLimitErrorIndex);
    4056              :                                                 }
    4057              :                                             }
    4058            0 :                                             if (this->SystemOAMethod == DataSizing::SysOAMethod::ProportionalControlDesOARate) {
    4059            0 :                                                 if (this->CO2MaxMinLimitErrorCount < 2) {
    4060            0 :                                                     ShowSevereError(state, format("{}{} = \"{}\".", RoutineName, CurrentModuleObject, this->Name));
    4061            0 :                                                     ShowContinueError(
    4062              :                                                         state,
    4063            0 :                                                         format("For System Outdoor Air Method = ProportionalControlBasedOnDesignOARate, maximum "
    4064              :                                                                "target CO2 concentration ({:.2R}), is not greater than minimum target CO2 "
    4065              :                                                                "concentration ({:.2R}).",
    4066              :                                                                ZoneMaxCO2,
    4067              :                                                                ZoneMinCO2));
    4068            0 :                                                     ShowContinueError(
    4069              :                                                         state,
    4070              :                                                         "\"ProportionalControlBasedOnDesignOARate\" will not be modeled. Default "
    4071              :                                                         "\"Standard62.1VentilationRateProcedure\" will be modeled. Simulation continues...");
    4072            0 :                                                     ShowContinueErrorTimeStamp(state, "");
    4073              :                                                 } else {
    4074            0 :                                                     ShowRecurringWarningErrorAtEnd(state,
    4075            0 :                                                                                    format("{} = \"{}\", For System Outdoor Air Method = "
    4076              :                                                                                           "ProportionalControlBasedOnDesignOARate, maximum target "
    4077              :                                                                                           "CO2 concentration is not greater than minimum target CO2 "
    4078              :                                                                                           "concentration. Error continues...",
    4079              :                                                                                           CurrentModuleObject,
    4080            0 :                                                                                           this->Name),
    4081            0 :                                                                                    this->CO2MaxMinLimitErrorIndex);
    4082              :                                                 }
    4083              :                                             }
    4084              : 
    4085            0 :                                             ZoneOA = ZoneOABZ / ZoneEz;
    4086              :                                         } else {
    4087              : 
    4088        14320 :                                             if (state.dataContaminantBalance->ZoneAirCO2(ZoneNum) <= ZoneMinCO2) {
    4089              :                                                 // Zone air CO2 concentration is less than minimum zone CO2 concentration, set the Zone OA flow
    4090              :                                                 // rate to minimum Zone OA flow rate when the zone is unoccupied
    4091            0 :                                                 ZoneOA = ZoneOAMin;
    4092        14320 :                                             } else if (state.dataContaminantBalance->ZoneAirCO2(ZoneNum) >= ZoneMaxCO2) {
    4093              :                                                 // Zone air CO2 concentration is greater than maximum zone CO2 concentration, set the Zone OA flow
    4094              :                                                 // rate to maximum Zone OA flow rate (i.e.
    4095              :                                                 // ZoneOACalc[static_cast<int>(DataSizing::OAFlowCalcMethod::PerArea)] + ZoneOAPeople)
    4096         1108 :                                                 ZoneOA = ZoneOAMax;
    4097              :                                             } else {
    4098              :                                                 // Zone air CO2 concentration is between maximum and minimum limits of zone CO2 concentration,
    4099              :                                                 // set Zone OA flow rate by proportionally adjusting between ZoneOAMin and ZoneOAMax
    4100        13212 :                                                 ZoneOA = ZoneOAMin +
    4101        13212 :                                                          (ZoneOAMax - ZoneOAMin) * ((state.dataContaminantBalance->ZoneAirCO2(ZoneNum) - ZoneMinCO2) /
    4102        13212 :                                                                                     (ZoneMaxCO2 - ZoneMinCO2));
    4103              :                                             }
    4104              :                                         }
    4105              :                                     } else {
    4106         9816 :                                         if (state.dataGlobal->DisplayExtraWarnings) {
    4107            0 :                                             ++this->CO2GainErrorCount;
    4108            0 :                                             if (this->SystemOAMethod == DataSizing::SysOAMethod::ProportionalControlSchOcc) {
    4109            0 :                                                 if (this->CO2GainErrorCount < 2) {
    4110            0 :                                                     ShowSevereError(state, format("{}{} = \"{}\".", RoutineName, CurrentModuleObject, this->Name));
    4111            0 :                                                     ShowContinueError(
    4112              :                                                         state,
    4113            0 :                                                         format("For System Outdoor Air Method = ProportionalControlBasedOnOccupancySchedule, CO2 "
    4114              :                                                                "generation from people is not greater than zero. Occurs in Zone =\"{}\". ",
    4115            0 :                                                                curZone.Name));
    4116            0 :                                                     ShowContinueError(state,
    4117              :                                                                       "\"ProportionalControlBasedOnOccupancySchedule\" will not be modeled. "
    4118              :                                                                       "Default \"Standard62.1VentilationRateProcedure\" will be modeled. Simulation "
    4119              :                                                                       "continues...");
    4120            0 :                                                     ShowContinueErrorTimeStamp(state, "");
    4121              :                                                 } else {
    4122            0 :                                                     ShowRecurringWarningErrorAtEnd(
    4123              :                                                         state,
    4124            0 :                                                         format("{} = \"{}\", For System Outdoor Air Method = "
    4125              :                                                                "ProportionalControlBasedOnOccupancySchedule, "
    4126              :                                                                "CO2 generation from people is not greater than zero. Error continues...",
    4127              :                                                                CurrentModuleObject,
    4128            0 :                                                                this->Name),
    4129            0 :                                                         this->CO2GainErrorIndex);
    4130              :                                                 }
    4131              :                                             }
    4132            0 :                                             if (this->SystemOAMethod == DataSizing::SysOAMethod::ProportionalControlDesOcc) {
    4133            0 :                                                 if (this->CO2GainErrorCount < 2) {
    4134            0 :                                                     ShowSevereError(state, format("{}{} = \"{}\".", RoutineName, CurrentModuleObject, this->Name));
    4135            0 :                                                     ShowContinueError(
    4136              :                                                         state,
    4137            0 :                                                         format("For System Outdoor Air Method = ProportionalControlBasedOnDesignOccupancy, CO2 "
    4138              :                                                                "generation from people is not greater than zero. Occurs in Zone =\"{}\". ",
    4139            0 :                                                                curZone.Name));
    4140            0 :                                                     ShowContinueError(state,
    4141              :                                                                       "\"ProportionalControlBasedOnDesignOccupancy\" will not be modeled. "
    4142              :                                                                       "Default \"Standard62.1VentilationRateProcedure\" will be modeled. Simulation "
    4143              :                                                                       "continues...");
    4144            0 :                                                     ShowContinueErrorTimeStamp(state, "");
    4145              :                                                 } else {
    4146            0 :                                                     ShowRecurringWarningErrorAtEnd(
    4147              :                                                         state,
    4148            0 :                                                         format(
    4149              :                                                             "{} = \"{}\", For System Outdoor Air Method = ProportionalControlBasedOnDesignOccupancy, "
    4150              :                                                             "CO2 generation from people is not greater than zero. Error continues...",
    4151              :                                                             CurrentModuleObject,
    4152            0 :                                                             this->Name),
    4153            0 :                                                         this->CO2GainErrorIndex);
    4154              :                                                 }
    4155              :                                             }
    4156              :                                         }
    4157         9816 :                                         ZoneOA = ZoneOABZ / ZoneEz;
    4158              :                                     }
    4159              :                                 } else {
    4160              :                                     // ZoneOACalc[static_cast<int>(DataSizing::OAFlowCalcMethod::PerPerson)] is less than or equal to zero
    4161         6552 :                                     ZoneOA = ZoneOABZ / ZoneEz;
    4162              :                                 }
    4163              :                             } else {
    4164              :                                 // ZoneControl:ContaminantController is scheduled off (not available)
    4165            0 :                                 ZoneOA = ZoneOABZ / ZoneEz;
    4166              :                             }
    4167              :                         } else {
    4168              :                             // "Carbon Dioxide Control Availability Schedule" for ZoneControl:ContaminantController not found
    4169        24560 :                             ZoneOA = ZoneOABZ / ZoneEz;
    4170              :                         }
    4171        55248 :                         SysOA = SysOA + ZoneOA;
    4172              :                     }
    4173              : 
    4174              :                     // Get the zone supply air flow rate
    4175      6551926 :                     Real64 ZoneSA = 0.0; // Zone supply air flow rate
    4176      6551926 :                     Real64 ZonePA = 0.0; // Zone primary air flow rate
    4177      6551926 :                     Ep = 1.0;
    4178      6551926 :                     if (ZoneEquipConfigNum > 0) {
    4179      6551926 :                         auto &curZoneEquipConfig = state.dataZoneEquip->ZoneEquipConfig(ZoneEquipConfigNum);
    4180     13103852 :                         for (int InNodeIndex = 1; InNodeIndex <= curZoneEquipConfig.NumInletNodes; ++InNodeIndex) {
    4181              :                             // Assume primary air is always stored at the AirDistUnitCool (cooling deck if dual duct)
    4182      6551926 :                             int PriNode = curZoneEquipConfig.AirDistUnitCool(InNodeIndex).InNode; // primary node of zone terminal unit
    4183      6551926 :                             Real64 MassFlowRate = 0.0;
    4184      6551926 :                             if (PriNode > 0) {
    4185      6551926 :                                 NodeTemp = state.dataLoopNodes->Node(PriNode).Temp;
    4186      6551926 :                                 NodeHumRat = state.dataLoopNodes->Node(PriNode).HumRat;
    4187      6551926 :                                 MassFlowRate = state.dataLoopNodes->Node(PriNode).MassFlowRate;
    4188              :                             }
    4189              :                             // total primary air to terminal units of the zone
    4190      6551926 :                             if (MassFlowRate > 0.0) {
    4191      6499334 :                                 ZonePA +=
    4192      6499334 :                                     MassFlowRate / Psychrometrics::PsyRhoAirFnPbTdbW(state, state.dataEnvrn->OutBaroPress, NodeTemp, NodeHumRat);
    4193              :                             }
    4194              : 
    4195              :                             // or InletNode = ZoneEquipConfig(ZoneEquipConfigNum)%AirDistUnitCool(InNodeIndex)%OutNode
    4196      6551926 :                             int InletNode = curZoneEquipConfig.InletNode(InNodeIndex); // outlet node of zone terminal unit
    4197      6551926 :                             MassFlowRate = 0.0;
    4198      6551926 :                             if (InletNode > 0) {
    4199      6551926 :                                 NodeTemp = state.dataLoopNodes->Node(InletNode).Temp;
    4200      6551926 :                                 NodeHumRat = state.dataLoopNodes->Node(InletNode).HumRat; // ZoneAirHumRat(ZoneNum)
    4201      6551926 :                                 MassFlowRate = state.dataLoopNodes->Node(InletNode).MassFlowRate;
    4202              :                             }
    4203              :                             // total supply air to the zone
    4204      6551926 :                             if (MassFlowRate > 0.0) {
    4205      6502874 :                                 ZoneSA +=
    4206      6502874 :                                     MassFlowRate / Psychrometrics::PsyRhoAirFnPbTdbW(state, state.dataEnvrn->OutBaroPress, NodeTemp, NodeHumRat);
    4207              :                             }
    4208              :                         }
    4209              : 
    4210              :                         // calc zone primary air fraction
    4211      6551926 :                         if (ZoneSA > 0.0) {
    4212      6502874 :                             Ep = ZonePA / ZoneSA;
    4213              :                         }
    4214      6551926 :                         if (Ep > 1.0) {
    4215            0 :                             Ep = 1.0;
    4216              :                         }
    4217              :                     }
    4218              : 
    4219              :                     // Calc the zone OA fraction = Zone OA flow rate / Zone supply air flow rate
    4220      6551926 :                     if (ZoneSA > 0.0) {
    4221      6502874 :                         ZoneOAFrac = ZoneOA / ZoneSA;
    4222              :                         // Zone OA fraction cannot be more than 1
    4223      6502874 :                         if (ZoneOAFrac > 1.0) {
    4224       216765 :                             ZoneOAFrac = 1.0;
    4225              :                         }
    4226              :                     } else {
    4227        49052 :                         ZoneOAFrac = 0.0;
    4228              :                     }
    4229              : 
    4230              :                     // added for TRACE - zone maximum OA fraction - calculate the adjustment factor for the TU/zone supply air flow
    4231              :                     // only for VRP system OA method
    4232      6551926 :                     curZoneSysEnergyDemand.SupplyAirAdjustFactor = 1.0;
    4233              : 
    4234      6551926 :                     if (this->SystemOAMethod == DataSizing::SysOAMethod::VRP || this->SystemOAMethod == DataSizing::SysOAMethod::VRPL) {
    4235      6496678 :                         if (ZoneOAFrac > this->ZoneMaxOAFraction) {
    4236            0 :                             if (this->ZoneMaxOAFraction > 0.0) {
    4237            0 :                                 curZoneSysEnergyDemand.SupplyAirAdjustFactor = ZoneOAFrac / this->ZoneMaxOAFraction;
    4238              :                             } else {
    4239            0 :                                 curZoneSysEnergyDemand.SupplyAirAdjustFactor = 1.0;
    4240              :                             }
    4241              : 
    4242              :                             // cap zone OA fraction at the maximum specified
    4243            0 :                             ZoneOAFrac = this->ZoneMaxOAFraction;
    4244              :                         }
    4245              :                     }
    4246              : 
    4247              :                     // Zone air secondary recirculation fraction
    4248      6551926 :                     Er = thisMechVentZone.ZoneSecondaryRecirculation;
    4249      6551926 :                     if (Er > 0.0) {
    4250              :                         // multi-path ventilation system using VRP
    4251        18354 :                         Fa = Ep + (1.0 - Ep) * Er;
    4252        18354 :                         Fb = Ep;
    4253        18354 :                         Fc = 1.0 - (1.0 - ZoneEz) * (1.0 - Er) * (1.0 - Ep);
    4254              : 
    4255              :                         // Calc zone ventilation efficiency
    4256        18354 :                         if (Fa > 0.0) {
    4257        18354 :                             Evz = 1.0 + Xs * Fb / Fa - ZoneOAFrac * Ep * Fc / Fa;
    4258              :                         } else {
    4259            0 :                             Evz = 1.0;
    4260              :                         }
    4261              :                     } else {
    4262              :                         // single-path ventilation system
    4263      6533572 :                         Evz = 1.0 + Xs - ZoneOAFrac;
    4264              :                     }
    4265              : 
    4266              :                     // calc system ventilation efficiency = Minimum of zone ventilation efficiency
    4267      6551926 :                     if (Evz < 0.0) {
    4268            0 :                         Evz = 0.0;
    4269              :                     }
    4270      6551926 :                     if (Evz < SysEv) {
    4271      1409001 :                         SysEv = Evz;
    4272              :                     }
    4273              : 
    4274              :                 } // zone loop
    4275              : 
    4276              :                 // Calc the system supply OA flow rate counting the system ventilation efficiency
    4277       787505 :                 if (SysEv <= 0.0) {
    4278            0 :                     SysEv = 1.0;
    4279              :                 }
    4280              : 
    4281              :                 // Calc system outdoor air requirement
    4282       787505 :                 if (this->SystemOAMethod == DataSizing::SysOAMethod::ProportionalControlSchOcc ||
    4283       781365 :                     this->SystemOAMethod == DataSizing::SysOAMethod::ProportionalControlDesOcc ||
    4284       775229 :                     this->SystemOAMethod == DataSizing::SysOAMethod::ProportionalControlDesOARate) {
    4285        18416 :                     SysOA = SysOA / SysEv;
    4286       769089 :                 } else if (this->SystemOAMethod == DataSizing::SysOAMethod::VRPL && this->SysDesOA > 0.0) {
    4287              :                     // Limit system OA to design OA minimum flow rate, as per ASHRAE Guideline 36-2018 Section 5.16.3.1
    4288              :                     // If no system sizing run is done (i.e. no Sizing:System) the design outdoor air flow rate is not known
    4289       665246 :                     SysOA = min(SysOAuc / SysEv, this->SysDesOA);
    4290              :                 } else {
    4291       103843 :                     SysOA = SysOAuc / SysEv;
    4292              :                 }
    4293              :             }
    4294              : 
    4295              :             // Finally calc the system supply OA mass flow rate
    4296       955627 :             MechVentOAMassFlow = SysOA * state.dataEnvrn->StdRhoAir;
    4297              :         }
    4298              :     }
    4299      1261261 :     return MechVentOAMassFlow;
    4300              : }
    4301              : 
    4302     25603103 : void OAControllerProps::CalcOAEconomizer(EnergyPlusData &state,
    4303              :                                          int const AirLoopNum,
    4304              :                                          Real64 const OutAirMinFrac,
    4305              :                                          Real64 &OASignal,
    4306              :                                          bool &HighHumidityOperationFlag,
    4307              :                                          bool const FirstHVACIteration)
    4308              : {
    4309     25603103 :     int constexpr MaxIte(500);             // Maximum number of iterations
    4310     25603103 :     Real64 constexpr Acc(0.0001);          // Accuracy of result
    4311              :     bool AirLoopEconoLockout;              // Economizer lockout flag
    4312              :     bool AirLoopNightVent;                 // Night Ventilation flag for air loop
    4313              :     bool EconomizerOperationFlag;          // TRUE if OA economizer is active
    4314              :     Real64 EconomizerAirFlowScheduleValue; // value of economizer operation schedule (push-button type control schedule)
    4315              :     Real64 MaximumOAFracBySetPoint;        // The maximum OA fraction due to freezing cooling coil check
    4316              :     Real64 OutAirSignal;                   // Used to set OA mass flow rate
    4317              :     Real64 minOAFrac;
    4318              : 
    4319     25603103 :     if (AirLoopNum > 0) {
    4320              :         // Check lockout with heating for any airloop - will lockout economizer even on airloops without a unitary system
    4321     25039224 :         if (this->Lockout == LockoutType::LockoutWithHeatingPossible) {
    4322              :             // For all system types (even ones that don't set AirLoopEconoLockout) lock out economizer if unfavorable for heating
    4323      5492561 :             if (state.dataAirLoop->AirLoopControlInfo(AirLoopNum).CheckHeatRecoveryBypassStatus &&
    4324       939567 :                 state.dataAirLoop->AirLoopControlInfo(AirLoopNum).OASysComponentsSimulated) {
    4325              : 
    4326       392420 :                 if (this->MixedAirTempAtMinOAFlow <= state.dataLoopNodes->Node(this->MixNode).TempSetPoint) {
    4327       146774 :                     state.dataAirLoop->AirLoopControlInfo(AirLoopNum).EconomizerFlowLocked = true;
    4328              :                     // this->OAMassFlow = AirLoopFlow( AirLoopNum ).MinOutAir;
    4329              :                     // AirLoopFlow( AirLoopNum ).OAFrac = this->OAMassFlow / this->MixMassFlow;
    4330       146774 :                     state.dataAirLoop->AirLoopControlInfo(AirLoopNum).EconoLockout = true;
    4331              :                 } else {
    4332       245646 :                     state.dataAirLoop->AirLoopControlInfo(AirLoopNum).EconomizerFlowLocked = false;
    4333       245646 :                     this->HRHeatingCoilActive = 0;
    4334              :                 }
    4335       392420 :                 state.dataAirLoop->AirLoopControlInfo(AirLoopNum).CheckHeatRecoveryBypassStatus = false;
    4336              :             }
    4337              :         }
    4338              :     }
    4339              : 
    4340     25603103 :     if (AirLoopNum > 0) {
    4341     25039224 :         AirLoopEconoLockout = state.dataAirLoop->AirLoopControlInfo(AirLoopNum).EconoLockout;
    4342     25039224 :         AirLoopNightVent = state.dataAirLoop->AirLoopControlInfo(AirLoopNum).NightVent;
    4343              :     } else {
    4344       563879 :         AirLoopEconoLockout = false;
    4345       563879 :         AirLoopNightVent = false;
    4346              :     }
    4347              : 
    4348              :     // Define an outside air signal
    4349     25603103 :     if (this->MixedAirSPMNum > 0) {
    4350        10151 :         this->CoolCoilFreezeCheck = SetPointManager::GetCoilFreezingCheckFlag(state, this->MixedAirSPMNum);
    4351              :     } else {
    4352     25592952 :         this->CoolCoilFreezeCheck = false;
    4353              :     }
    4354              : 
    4355     25603103 :     if (std::abs(this->RetTemp - this->InletTemp) > HVAC::SmallTempDiff) {
    4356     25602589 :         OutAirSignal = (this->RetTemp - this->MixSetTemp) / (this->RetTemp - this->InletTemp);
    4357     25602589 :         if (this->CoolCoilFreezeCheck) {
    4358            2 :             this->MaxOAFracBySetPoint = 0.0;
    4359            2 :             MaximumOAFracBySetPoint = OutAirSignal;
    4360              :         }
    4361              :     } else {
    4362          514 :         if (this->RetTemp - this->MixSetTemp < 0.0) {
    4363          189 :             if (this->RetTemp - this->InletTemp >= 0.0) {
    4364          124 :                 OutAirSignal = -1.0;
    4365              :             } else {
    4366           65 :                 OutAirSignal = 1.0;
    4367              :             }
    4368              :         } else {
    4369          325 :             if (this->RetTemp - this->InletTemp >= 0.0) {
    4370          292 :                 OutAirSignal = 1.0;
    4371              :             } else {
    4372           33 :                 OutAirSignal = -1.0;
    4373              :             }
    4374              :         }
    4375              :     }
    4376     25603103 :     OutAirSignal = min(max(OutAirSignal, OutAirMinFrac), 1.0);
    4377              : 
    4378              :     // If no economizer, set to minimum and disable economizer and high humidity control
    4379     25603103 :     if (this->Econo == EconoOp::NoEconomizer) {
    4380      8153113 :         OutAirSignal = OutAirMinFrac;
    4381      8153113 :         EconomizerOperationFlag = false;
    4382      8153113 :         EconomizerAirFlowScheduleValue = 0.0;
    4383      8153113 :         HighHumidityOperationFlag = false;
    4384     17449990 :     } else if (this->MaxOA < HVAC::SmallAirVolFlow) {
    4385            0 :         OutAirSignal = OutAirMinFrac;
    4386            0 :         EconomizerOperationFlag = false;
    4387            0 :         EconomizerAirFlowScheduleValue = 0.0;
    4388            0 :         HighHumidityOperationFlag = false;
    4389     17449990 :     } else if (AirLoopEconoLockout) {
    4390       921405 :         OutAirSignal = OutAirMinFrac;
    4391       921405 :         EconomizerOperationFlag = false;
    4392       921405 :         EconomizerAirFlowScheduleValue = 0.0;
    4393       921405 :         HighHumidityOperationFlag = false;
    4394              :     } else {
    4395              :         // Changed by Amit for new implementation
    4396              :         // Otherwise do the limit checks
    4397     16528585 :         EconomizerOperationFlag = true;
    4398              :         // Outside air temp greater than mix air setpoint
    4399     16528585 :         if (this->InletTemp > this->MixSetTemp) {
    4400     11781801 :             OutAirSignal = 1.0;
    4401              :         }
    4402              :         // Return air temp limit
    4403     16528585 :         if (this->Econo == EconoOp::DifferentialDryBulb) {
    4404     11830167 :             if (this->InletTemp > this->RetTemp) {
    4405      4561305 :                 OutAirSignal = OutAirMinFrac;
    4406      4561305 :                 EconomizerOperationFlag = false;
    4407              :             }
    4408     11830167 :             this->Checksetpoints(state, OutAirMinFrac, OutAirSignal, EconomizerOperationFlag);
    4409              :         }
    4410              :         // Return air enthalpy limit
    4411     16528585 :         if (this->Econo == EconoOp::DifferentialEnthalpy) {
    4412      1346940 :             if (this->InletEnth > this->RetEnth) {
    4413       925178 :                 OutAirSignal = OutAirMinFrac;
    4414       925178 :                 EconomizerOperationFlag = false;
    4415              :             }
    4416      1346940 :             this->Checksetpoints(state, OutAirMinFrac, OutAirSignal, EconomizerOperationFlag);
    4417              :         }
    4418              :         // Outside air temperature limit
    4419     16528585 :         if (this->Econo == EconoOp::FixedDryBulb) {
    4420      3289891 :             this->Checksetpoints(state, OutAirMinFrac, OutAirSignal, EconomizerOperationFlag);
    4421              :         }
    4422              :         // Fixed Enthalpy limit
    4423     16528585 :         if (this->Econo == EconoOp::FixedEnthalpy) {
    4424            0 :             this->Checksetpoints(state, OutAirMinFrac, OutAirSignal, EconomizerOperationFlag);
    4425              :         }
    4426              :         // FIXED DEW POINT AND DRY BULB TEMPERATURE STRATEGY
    4427     16528585 :         if (this->Econo == EconoOp::FixedDewPointAndDryBulb) {
    4428            0 :             this->Checksetpoints(state, OutAirMinFrac, OutAirSignal, EconomizerOperationFlag);
    4429              :         }
    4430              :         // ELECRONIC ENTHALPY, HUMIDITY RATIO CURVE
    4431     16528585 :         if (this->Econo == EconoOp::ElectronicEnthalpy) {
    4432        61587 :             this->Checksetpoints(state, OutAirMinFrac, OutAirSignal, EconomizerOperationFlag);
    4433              :         }
    4434              :         // Differential dry bulb and enthalpy strategy
    4435     16528585 :         if (this->Econo == EconoOp::DifferentialDryBulbAndEnthalpy) {
    4436            0 :             if (this->InletTemp > this->RetTemp) {
    4437            0 :                 OutAirSignal = OutAirMinFrac;
    4438            0 :                 EconomizerOperationFlag = false;
    4439              :             }
    4440            0 :             if (this->InletEnth > this->RetEnth) {
    4441            0 :                 OutAirSignal = OutAirMinFrac;
    4442            0 :                 EconomizerOperationFlag = false;
    4443              :             }
    4444            0 :             this->Checksetpoints(state, OutAirMinFrac, OutAirSignal, EconomizerOperationFlag);
    4445              :         }
    4446              : 
    4447     16528585 :         if (this->TempLowLim != HVAC::BlankNumeric && this->OATemp < this->TempLowLim) {
    4448       959292 :             OutAirSignal = OutAirMinFrac;
    4449       959292 :             EconomizerOperationFlag = false;
    4450              :         }
    4451              :         // Increase air flow for humidity control
    4452              :         // (HumidistatZoneNum is greater than 0 IF High Humidity Control Flag = YES, checked in GetInput)
    4453     16528585 :         if (this->HumidistatZoneNum > 0) {
    4454              :             //   IF humidistat senses a moisture load check to see if modifying air flow is appropriate, otherwise disable modified air flow
    4455        58289 :             if (state.dataZoneEnergyDemand->ZoneSysMoistureDemand(this->HumidistatZoneNum).TotalOutputRequired < 0.0) {
    4456              :                 //     IF OAController is not allowed to modify air flow during high outdoor humrat condition, then disable modified air flow
    4457              :                 //     if indoor humrat is less than or equal to outdoor humrat
    4458        42180 :                 if (!this->ModifyDuringHighOAMoisture &&
    4459        21090 :                     (state.dataLoopNodes->Node(this->NodeNumofHumidistatZone).HumRat - this->OAHumRat) <= HVAC::SmallHumRatDiff) {
    4460        20696 :                     HighHumidityOperationFlag = false;
    4461              :                 } else {
    4462          394 :                     HighHumidityOperationFlag = true;
    4463              :                 }
    4464              :             } else {
    4465        37199 :                 HighHumidityOperationFlag = false;
    4466              :             }
    4467              :         } else {
    4468     16470296 :             HighHumidityOperationFlag = false;
    4469              :         }
    4470              : 
    4471              :         // Check time of day economizer schedule, enable economizer if schedule value > 0
    4472     16528585 :         EconomizerAirFlowScheduleValue = 0.0;
    4473     16528585 :         if (this->economizerOASched != nullptr) {
    4474        61772 :             EconomizerAirFlowScheduleValue = this->economizerOASched->getCurrentVal();
    4475        61772 :             if (EconomizerAirFlowScheduleValue > 0.0) {
    4476          848 :                 EconomizerOperationFlag = true;
    4477          848 :                 OutAirSignal = 1.0;
    4478              :             }
    4479              :         }
    4480              :     }
    4481              : 
    4482              :     // OutAirSignal will not give exactly the correct mixed air temperature (equal to the setpoint) since
    4483              :     // it was calculated using the approximate method of sensible energy balance. Now we have to get the
    4484              :     // accurate result using a full mass, enthalpy and moisture balance and iteration.
    4485     25603103 :     if (OutAirSignal > OutAirMinFrac && OutAirSignal < 1.0 && this->MixMassFlow > HVAC::VerySmallMassFlow &&
    4486      1746299 :         this->ControllerType == MixedAirControllerType::ControllerOutsideAir && !AirLoopNightVent) {
    4487              :         int SolFla; // Flag of solver
    4488              : 
    4489      1746299 :         if (AirLoopNum > 0) {
    4490              : 
    4491      1746299 :             if (state.dataAirLoop->OutsideAirSys(state.dataAirLoop->AirLoopControlInfo(AirLoopNum).OASysNum).NumComponents == 1) {
    4492              :                 // no need to simulate OA System if only a mixer is used in the OutsideAirSystem
    4493              : 
    4494      6582125 :                 auto f = [&state, this](Real64 const OASignal) {
    4495      6582125 :                     Real64 const OAMassFlowRate = OASignal * this->MixMassFlow;
    4496      6582125 :                     Real64 const RecircMassFlowRate = max(this->MixMassFlow - OAMassFlowRate, 0.0);
    4497      6582125 :                     Real64 const RecircEnth = state.dataLoopNodes->Node(this->RetNode).Enthalpy;
    4498      6582125 :                     Real64 const RecircHumRat = state.dataLoopNodes->Node(this->RetNode).HumRat;
    4499              :                     Real64 const MixEnth =
    4500      6582125 :                         (RecircMassFlowRate * RecircEnth + OAMassFlowRate * state.dataLoopNodes->Node(this->OANode).Enthalpy) / this->MixMassFlow;
    4501              :                     Real64 const MixHumRat =
    4502      6582125 :                         (RecircMassFlowRate * RecircHumRat + OAMassFlowRate * state.dataLoopNodes->Node(this->OANode).HumRat) / this->MixMassFlow;
    4503      6582125 :                     Real64 const MixTemp = Psychrometrics::PsyTdbFnHW(MixEnth, MixHumRat);
    4504      6582125 :                     return state.dataLoopNodes->Node(this->MixNode).TempSetPoint - MixTemp;
    4505      1734575 :                 };
    4506              : 
    4507      1734575 :                 General::SolveRoot(state, Acc, MaxIte, SolFla, OASignal, f, OutAirMinFrac, 1.0);
    4508      1734575 :                 if (SolFla < 0) {
    4509          805 :                     OASignal = OutAirSignal;
    4510              :                 }
    4511              : 
    4512              :             } else {
    4513              : 
    4514              :                 // simulate OA System if equipment exists other than the mixer (e.g., heating/cooling coil, HX, etc.)
    4515              : 
    4516              :                 // 1 - check min OA flow result
    4517        11724 :                 if (this->FixedMin) {
    4518        11724 :                     state.dataLoopNodes->Node(this->OANode).MassFlowRate =
    4519        11724 :                         min(max(this->ExhMassFlow, OutAirMinFrac * state.dataAirLoop->AirLoopFlow(AirLoopNum).DesSupply),
    4520        11724 :                             state.dataLoopNodes->Node(this->MixNode).MassFlowRate);
    4521        11724 :                     state.dataLoopNodes->Node(this->RelNode).MassFlowRate =
    4522        11724 :                         max(state.dataLoopNodes->Node(this->OANode).MassFlowRate - this->ExhMassFlow, 0.0);
    4523              :                     // save actual OA flow frac for use as min value for RegulaFalsi call
    4524        11724 :                     minOAFrac = max(OutAirMinFrac, state.dataLoopNodes->Node(this->OANode).MassFlowRate / this->MixMassFlow);
    4525              :                 } else {
    4526            0 :                     state.dataLoopNodes->Node(this->OANode).MassFlowRate =
    4527            0 :                         max(this->ExhMassFlow, OutAirMinFrac * state.dataLoopNodes->Node(this->MixNode).MassFlowRate);
    4528            0 :                     state.dataLoopNodes->Node(this->RelNode).MassFlowRate =
    4529            0 :                         max(state.dataLoopNodes->Node(this->OANode).MassFlowRate - this->ExhMassFlow, 0.0);
    4530              :                     // save actual OA flow frac for use as min value for RegulaFalsi call
    4531            0 :                     minOAFrac = max(OutAirMinFrac, state.dataLoopNodes->Node(this->OANode).MassFlowRate / this->MixMassFlow);
    4532              :                 }
    4533        11724 :                 SimOASysComponents(state, state.dataAirLoop->AirLoopControlInfo(AirLoopNum).OASysNum, FirstHVACIteration, AirLoopNum);
    4534        11724 :                 Real64 lowFlowResiduum = state.dataLoopNodes->Node(this->MixNode).TempSetPoint - state.dataLoopNodes->Node(this->MixNode).Temp;
    4535              : 
    4536              :                 // 2 - check max OA flow result
    4537        11724 :                 state.dataLoopNodes->Node(this->OANode).MassFlowRate = max(this->ExhMassFlow, state.dataLoopNodes->Node(this->MixNode).MassFlowRate);
    4538        11724 :                 state.dataLoopNodes->Node(this->RelNode).MassFlowRate =
    4539        11724 :                     max(state.dataLoopNodes->Node(this->OANode).MassFlowRate - this->ExhMassFlow, 0.0);
    4540        11724 :                 SimOASysComponents(state, state.dataAirLoop->AirLoopControlInfo(AirLoopNum).OASysNum, FirstHVACIteration, AirLoopNum);
    4541        11724 :                 Real64 highFlowResiduum = state.dataLoopNodes->Node(this->MixNode).TempSetPoint - state.dataLoopNodes->Node(this->MixNode).Temp;
    4542              : 
    4543              :                 // 3 - test to ensure RegulaFalsi can find an answer
    4544        11724 :                 if ((sign(lowFlowResiduum) == sign(highFlowResiduum))) {
    4545          645 :                     OASignal = OutAirSignal;
    4546              :                 } else {
    4547              :                     // 4 - find result
    4548              : 
    4549        51304 :                     auto f = [&state, this, FirstHVACIteration, AirLoopNum](Real64 const OASignal) {
    4550        51304 :                         Real64 const MixMassFlowRate = this->MixMassFlow;
    4551        51304 :                         int const OASysNum = state.dataAirLoop->AirLoopControlInfo(AirLoopNum).OASysNum;
    4552        51304 :                         Real64 localExhMassFlow = state.dataAirLoop->AirLoopControlInfo(AirLoopNum).ZoneExhMassFlow;
    4553        51304 :                         Real64 const OAMassFlowRate = max(localExhMassFlow, OASignal * MixMassFlowRate);
    4554        51304 :                         state.dataLoopNodes->Node(this->OANode).MassFlowRate = OAMassFlowRate; // set OA node mass flow rate
    4555        51304 :                         state.dataLoopNodes->Node(this->RelNode).MassFlowRate =
    4556        51304 :                             max(OAMassFlowRate - localExhMassFlow, 0.0); // set relief node mass flow rate to maintain mixer continuity calcs
    4557        51304 :                         SimOASysComponents(state, OASysNum, FirstHVACIteration, AirLoopNum);
    4558        51304 :                         return state.dataLoopNodes->Node(this->MixNode).TempSetPoint - state.dataLoopNodes->Node(this->MixNode).Temp;
    4559        11079 :                     };
    4560              : 
    4561        11079 :                     General::SolveRoot(state, (Acc / 10.0), MaxIte, SolFla, OASignal, f, minOAFrac, 1.0);
    4562        11079 :                     if (SolFla < 0) { // if RegulaFalsi fails to find a solution, returns -1 or -2, set to existing OutAirSignal
    4563          270 :                         OASignal = OutAirSignal;
    4564              :                     }
    4565              :                 }
    4566              :             }
    4567              : 
    4568              :         } else {
    4569              : 
    4570            0 :             auto f = [&state, this](Real64 const OASignal) {
    4571            0 :                 Real64 const MixMassFlowRate = this->MixMassFlow;
    4572            0 :                 Real64 OAMassFlowRate = OASignal * MixMassFlowRate;
    4573            0 :                 Real64 RecircMassFlowRate = max(MixMassFlowRate - OAMassFlowRate, 0.0);
    4574            0 :                 Real64 RecircEnth = state.dataLoopNodes->Node(this->RetNode).Enthalpy;
    4575            0 :                 Real64 RecircHumRat = state.dataLoopNodes->Node(this->RetNode).HumRat;
    4576              :                 Real64 MixEnth =
    4577            0 :                     (RecircMassFlowRate * RecircEnth + OAMassFlowRate * state.dataLoopNodes->Node(this->OANode).Enthalpy) / MixMassFlowRate;
    4578              :                 Real64 MixHumRat =
    4579            0 :                     (RecircMassFlowRate * RecircHumRat + OAMassFlowRate * state.dataLoopNodes->Node(this->OANode).HumRat) / MixMassFlowRate;
    4580            0 :                 Real64 MixTemp = Psychrometrics::PsyTdbFnHW(MixEnth, MixHumRat);
    4581            0 :                 return state.dataLoopNodes->Node(this->MixNode).TempSetPoint - MixTemp;
    4582            0 :             };
    4583              : 
    4584            0 :             General::SolveRoot(state, Acc, MaxIte, SolFla, OASignal, f, OutAirMinFrac, 1.0);
    4585            0 :             if (SolFla < 0) {
    4586            0 :                 OASignal = OutAirSignal;
    4587              :             }
    4588              :         }
    4589              : 
    4590      1746299 :     } else {
    4591     23856804 :         OASignal = OutAirSignal;
    4592              :     }
    4593              : 
    4594              :     // Economizer choice "Bypass" forces minimum OA except when high humidity air flow is active based on indoor RH
    4595     25603103 :     if (this->EconBypass && EconomizerAirFlowScheduleValue == 0.0) {
    4596       697950 :         OASignal = OutAirMinFrac;
    4597              :     }
    4598              : 
    4599              :     // Set outdoor air signal based on OA flow ratio if high humidity air flow is enabled
    4600     25603103 :     if (HighHumidityOperationFlag) {
    4601          394 :         if (this->MixMassFlow > 0.0) {
    4602              :             //   calculate the actual ratio of outside air to mixed air so the magnitude of OA during high humidity control is correct
    4603          394 :             OASignal = max(OutAirMinFrac, (this->HighRHOAFlowRatio * this->MaxOAMassFlowRate / this->MixMassFlow));
    4604          394 :             this->OALimitingFactor = OALimitFactor::HighHum;
    4605              :         }
    4606              :     }
    4607              : 
    4608     25603103 :     if (this->CoolCoilFreezeCheck) {
    4609            2 :         MaximumOAFracBySetPoint = min(max(MaximumOAFracBySetPoint, 0.0), 1.0);
    4610            2 :         this->MaxOAFracBySetPoint = MaximumOAFracBySetPoint;
    4611              : 
    4612              :         // This should not be messing with OutAirMinFrac, freeze protection should only limit economizer operation
    4613              :         // if (MaximumOAFracBySetPoint < OutAirMinFrac) {
    4614              :         // OutAirMinFrac = MaximumOAFracBySetPoint;
    4615              :         //    if (AirLoopNum > 0) AirLoopFlow(AirLoopNum).MinOutAir = OutAirMinFrac * this->MixMassFlow;
    4616              :         //}
    4617            2 :         if (MaximumOAFracBySetPoint < OASignal) {
    4618            2 :             OASignal = MaximumOAFracBySetPoint;
    4619            2 :             this->OALimitingFactor = OALimitFactor::Limits;
    4620              :         }
    4621            2 :         if (OutAirMinFrac > OASignal) {
    4622            2 :             OASignal = OutAirMinFrac;
    4623            2 :             this->OALimitingFactor = OALimitFactor::Limits;
    4624              :         }
    4625              :     }
    4626              : 
    4627     25603103 :     if (AirLoopNum > 0) {
    4628              : 
    4629              :         // Set the air loop economizer and high humidity control flags.
    4630     25039224 :         state.dataAirLoop->AirLoopControlInfo(AirLoopNum).EconoActive = EconomizerOperationFlag;
    4631     25039224 :         state.dataAirLoop->AirLoopControlInfo(AirLoopNum).HighHumCtrlActive = HighHumidityOperationFlag;
    4632     25039224 :         if (state.dataAirLoop->AirLoopControlInfo(AirLoopNum).EconomizerFlowLocked) {
    4633      1228860 :             this->OAMassFlow = state.dataAirLoop->AirLoopFlow(AirLoopNum).MinOutAir;
    4634      1228860 :             state.dataAirLoop->AirLoopFlow(AirLoopNum).OAFrac = this->OAMassFlow / this->MixMassFlow;
    4635      1228860 :             state.dataAirLoop->AirLoopFlow(AirLoopNum).OAFlow = this->OAMassFlow;
    4636              :         }
    4637              : 
    4638              :         // Check heat exchanger bypass control
    4639     25039224 :         state.dataAirLoop->AirLoopControlInfo(AirLoopNum).HeatRecoveryBypass = false;
    4640     25039224 :         this->HeatRecoveryBypassStatus = 0;
    4641     25039224 :         if (EconomizerOperationFlag) {
    4642      5535536 :             if (this->HeatRecoveryBypassControlType == HVAC::BypassWhenWithinEconomizerLimits) {
    4643      5110431 :                 state.dataAirLoop->AirLoopControlInfo(AirLoopNum).HeatRecoveryBypass = true;
    4644      5110431 :                 this->HeatRecoveryBypassStatus = 1;
    4645       425105 :             } else if (this->HeatRecoveryBypassControlType == HVAC::BypassWhenOAFlowGreaterThanMinimum) {
    4646       425105 :                 Real64 OAMassFlowMin = OutAirMinFrac * state.dataAirLoop->AirLoopFlow(AirLoopNum).DesSupply;
    4647       425105 :                 Real64 OAMassFlowActual = OASignal * this->MixMassFlow;
    4648       425105 :                 Real64 reasonablySmallMassFlow = 1e-6;
    4649       425105 :                 if (OAMassFlowActual > (OAMassFlowMin + reasonablySmallMassFlow)) {
    4650       342825 :                     state.dataAirLoop->AirLoopControlInfo(AirLoopNum).HeatRecoveryBypass = true;
    4651       342825 :                     this->HeatRecoveryBypassStatus = 1;
    4652              :                 }
    4653              :             }
    4654              :         }
    4655              :     }
    4656              : 
    4657              :     // Set economizer report variable and status flag
    4658     25603103 :     if (this->Econo == EconoOp::NoEconomizer) {
    4659              :         // No economizer
    4660      8153113 :         this->EconomizerStatus = 0;
    4661      8153113 :         this->EconoActive = false;
    4662              :     } else {
    4663              :         // With economizer.
    4664     17449990 :         if (EconomizerOperationFlag) {
    4665              :             // Economizer is enabled
    4666      5536384 :             this->EconomizerStatus = 1;
    4667      5536384 :             this->EconoActive = true;
    4668      5536384 :             if ((OASignal > OutAirMinFrac) && !HighHumidityOperationFlag) {
    4669      3799728 :                 this->OALimitingFactor = OALimitFactor::Economizer;
    4670              :             }
    4671              :         } else {
    4672              :             // Economizer is disabled
    4673     11913606 :             this->EconomizerStatus = 0;
    4674     11913606 :             this->EconoActive = false;
    4675              :         }
    4676              :     }
    4677              : 
    4678              :     // Night ventilation control overrides economizer and high humidity control.
    4679     25603103 :     if (AirLoopNightVent) {
    4680            0 :         OASignal = 1.0;
    4681            0 :         this->OALimitingFactor = OALimitFactor::NightVent;
    4682              :     }
    4683              : 
    4684              :     // Set high humidity control report variable and status flag
    4685     25603103 :     if (HighHumidityOperationFlag) {
    4686          394 :         this->HighHumCtrlStatus = 1;
    4687          394 :         this->HighHumCtrlActive = true;
    4688              :     } else {
    4689     25602709 :         this->HighHumCtrlStatus = 0;
    4690     25602709 :         this->HighHumCtrlActive = false;
    4691              :     }
    4692     25603103 : }
    4693              : 
    4694     60004604 : void OAMixerProps::CalcOAMixer(EnergyPlusData &state)
    4695              : {
    4696              : 
    4697              :     // SUBROUTINE INFORMATION:
    4698              :     //       AUTHOR         Fred Buhl
    4699              :     //       DATE WRITTEN   Oct 1998
    4700              : 
    4701              :     // PURPOSE OF THIS SUBROUTINE
    4702              :     // Calculate the mixed air flow and conditions
    4703              : 
    4704              :     // Define a recirculation mass flow rate
    4705     60004604 :     Real64 RecircMassFlowRate = this->RetMassFlowRate - this->RelMassFlowRate;
    4706              :     // In certain low flow conditions the return air mass flow rate can be below the outside air value established
    4707              :     //  by the user.  This check will ensure that this condition does not result in non-physical air properties.
    4708     60004604 :     if (RecircMassFlowRate < 0.0) {
    4709        69258 :         RecircMassFlowRate = 0.0;
    4710        69258 :         this->RelMassFlowRate = this->RetMassFlowRate;
    4711              :     }
    4712              : 
    4713              :     // Pass through the return air conditions to the relief air stream.  The return air is "split" to
    4714              :     // the relief air and the recirculation air.
    4715     60004604 :     this->RelTemp = this->RetTemp;
    4716     60004604 :     this->RelHumRat = this->RetHumRat;
    4717     60004604 :     this->RelEnthalpy = this->RetEnthalpy;
    4718     60004604 :     this->RelPressure = this->RetPressure;
    4719     60004604 :     Real64 RecircPressure = this->RetPressure;
    4720     60004604 :     Real64 RecircEnthalpy = this->RetEnthalpy;
    4721     60004604 :     Real64 RecircHumRat = this->RetHumRat;
    4722              :     // The recirculation air and the outside air are mixed to form the mixed air stream
    4723     60004604 :     this->MixMassFlowRate = this->OAMassFlowRate + RecircMassFlowRate;
    4724              :     // Check for zero flow
    4725     60004604 :     if (this->MixMassFlowRate <= HVAC::VerySmallMassFlow) {
    4726      6462483 :         this->MixEnthalpy = this->RetEnthalpy;
    4727      6462483 :         this->MixHumRat = this->RetHumRat;
    4728      6462483 :         this->MixPressure = this->RetPressure;
    4729      6462483 :         this->MixTemp = this->RetTemp;
    4730      6462483 :         return;
    4731              :     }
    4732              : 
    4733     53542121 :     this->MixEnthalpy = (RecircMassFlowRate * RecircEnthalpy + this->OAMassFlowRate * this->OAEnthalpy) / this->MixMassFlowRate;
    4734     53542121 :     this->MixHumRat = (RecircMassFlowRate * RecircHumRat + this->OAMassFlowRate * this->OAHumRat) / this->MixMassFlowRate;
    4735     53542121 :     this->MixPressure = (RecircMassFlowRate * RecircPressure + this->OAMassFlowRate * this->OAPressure) / this->MixMassFlowRate;
    4736              :     // Mixed air temperature is calculated from the mixed air enthalpy and humidity ratio.
    4737     53542121 :     this->MixTemp = Psychrometrics::PsyTdbFnHW(this->MixEnthalpy, this->MixHumRat);
    4738              : 
    4739              :     // Check for saturation temperature > dry-bulb temperature and modify temperature at constant enthalpy
    4740     53542121 :     Real64 T_sat = Psychrometrics::PsyTsatFnHPb(state, this->MixEnthalpy, this->MixPressure);
    4741     53542121 :     if (this->MixTemp < T_sat) {
    4742      1361502 :         this->MixTemp = T_sat;
    4743      1361502 :         this->MixHumRat = Psychrometrics::PsyWFnTdbH(state, T_sat, this->MixEnthalpy);
    4744              :     }
    4745              : }
    4746              : 
    4747              : // End of Calculation/Simulation Section of the Module
    4748              : //******************************************************************************
    4749              : 
    4750              : // Beginning Sizing Section of the Module
    4751              : //******************************************************************************
    4752              : 
    4753         1171 : void OAControllerProps::SizeOAController(EnergyPlusData &state)
    4754              : {
    4755              : 
    4756              :     // SUBROUTINE INFORMATION:
    4757              :     //       AUTHOR         Fred Buhl
    4758              :     //       DATE WRITTEN   September 2001
    4759              : 
    4760              :     // PURPOSE OF THIS SUBROUTINE:
    4761              :     // This subroutine is for sizing OAController Components for which flow rates have not been
    4762              :     // specified in the input.
    4763              : 
    4764              :     // METHODOLOGY EMPLOYED:
    4765              :     // Obtains flow rates from the zone or system sizing arrays.
    4766              : 
    4767              :     // SUBROUTINE PARAMETER DEFINITIONS:
    4768              :     static std::string_view const &CurrentModuleObject(CurrentModuleObjects[static_cast<int>(CMO::OAController)]);
    4769              : 
    4770              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    4771         1171 :     bool ErrorsFound = false;
    4772         1171 :     if (this->MaxOA == AutoSize) {
    4773              : 
    4774          919 :         if (state.dataSize->CurSysNum > 0) {
    4775              : 
    4776          919 :             switch (this->ControllerType) {
    4777          919 :             case MixedAirControllerType::ControllerOutsideAir: {
    4778          919 :                 CheckSysSizing(state, CurrentModuleObject, this->Name);
    4779          919 :                 switch (state.dataSize->CurDuctType) {
    4780            0 :                 case HVAC::AirDuctType::Cooling: {
    4781            0 :                     this->MaxOA = state.dataSize->FinalSysSizing(state.dataSize->CurSysNum).DesCoolVolFlow;
    4782            0 :                 } break;
    4783            1 :                 case HVAC::AirDuctType::Heating: {
    4784            1 :                     this->MaxOA = state.dataSize->FinalSysSizing(state.dataSize->CurSysNum).DesHeatVolFlow;
    4785            1 :                 } break;
    4786          918 :                 case HVAC::AirDuctType::Main:
    4787              :                 case HVAC::AirDuctType::Other:
    4788              :                 default: {
    4789          918 :                     this->MaxOA = state.dataSize->FinalSysSizing(state.dataSize->CurSysNum).DesMainVolFlow;
    4790          918 :                 } break;
    4791              :                 }
    4792          919 :             } break;
    4793            0 :             case MixedAirControllerType::ControllerStandAloneERV: {
    4794            0 :             } break;
    4795            0 :             default:
    4796            0 :                 break;
    4797              :             }
    4798              : 
    4799            0 :         } else if (state.dataSize->CurZoneEqNum > 0) {
    4800              : 
    4801            0 :             switch (this->ControllerType) {
    4802            0 :             case MixedAirControllerType::ControllerOutsideAir: {
    4803            0 :                 CheckZoneSizing(state, CurrentModuleObject, this->Name);
    4804            0 :                 this->MaxOA = max(state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).DesCoolVolFlow,
    4805            0 :                                   state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).DesHeatVolFlow);
    4806            0 :             } break;
    4807            0 :             case MixedAirControllerType::ControllerStandAloneERV: {
    4808            0 :             } break;
    4809            0 :             default:
    4810            0 :                 break;
    4811              :             }
    4812              :         }
    4813              : 
    4814          919 :         if (this->MaxOA < HVAC::SmallAirVolFlow) {
    4815            0 :             this->MaxOA = 0.0;
    4816              :         }
    4817              : 
    4818          919 :         BaseSizer::reportSizerOutput(state, CurrentModuleObject, this->Name, "Maximum Outdoor Air Flow Rate [m3/s]", this->MaxOA);
    4819              :     }
    4820              : 
    4821         1171 :     if (this->MinOA == AutoSize) {
    4822              : 
    4823          850 :         if (state.dataSize->CurSysNum > 0) {
    4824              : 
    4825          850 :             CheckSysSizing(state, CurrentModuleObject, this->Name);
    4826          850 :             if (state.dataSize->FinalSysSizing(state.dataSize->CurSysNum).DesOutAirVolFlow >= HVAC::SmallAirVolFlow) {
    4827          840 :                 this->MinOA = min(state.dataSize->FinalSysSizing(state.dataSize->CurSysNum).DesOutAirVolFlow, this->MaxOA);
    4828              :             } else {
    4829           10 :                 this->MinOA = 0.0;
    4830              :             }
    4831              :         }
    4832              : 
    4833          850 :         BaseSizer::reportSizerOutput(state, CurrentModuleObject, this->Name, "Minimum Outdoor Air Flow Rate [m3/s]", this->MinOA);
    4834              : 
    4835          850 :         if (this->HumidistatZoneNum > 0 && this->FixedMin) {
    4836            1 :             if (this->MaxOA > 0.0) {
    4837            1 :                 Real64 OAFlowRatio = this->MinOA / this->MaxOA;
    4838            1 :                 if (this->HighRHOAFlowRatio < OAFlowRatio) {
    4839            0 :                     ShowWarningError(state, format("{} \"{}\"", CurrentModuleObject, this->Name));
    4840            0 :                     ShowContinueError(state, "... A fixed minimum outdoor air flow rate and high humidity control have been specified.");
    4841            0 :                     ShowContinueError(state,
    4842              :                                       "... The High Humidity Outdoor Air Flow Ratio is less than the ratio of the outdoor air controllers "
    4843              :                                       "minimum to maximum outside air flow rate.");
    4844            0 :                     ShowContinueError(state, format("... Controller minimum flow rate = {:.4T} m3/s.", this->MinOA));
    4845            0 :                     ShowContinueError(state, format("... Controller maximum flow rate = {:.4T} m3/s.", this->MaxOA));
    4846            0 :                     ShowContinueError(state, format("... Controller minimum to maximum flow ratio = {:.4T}.", OAFlowRatio));
    4847            0 :                     ShowContinueError(state, format("... High humidity control flow ratio = {:.4T}.", this->HighRHOAFlowRatio));
    4848              :                 }
    4849              :             }
    4850              :         }
    4851              :     }
    4852              :     // If there is an outside air system, loop over components in the OA system; pass the design air flow rate
    4853              :     // to the coil components that don't have design air flow as an input.
    4854         1171 :     if (state.dataSize->CurOASysNum > 0) {
    4855         2269 :         for (int CompNum = 1; CompNum <= state.dataAirLoop->OutsideAirSys(state.dataSize->CurOASysNum).NumComponents; ++CompNum) {
    4856         1202 :             std::string const &CompType = state.dataAirLoop->OutsideAirSys(state.dataSize->CurOASysNum).ComponentType(CompNum);
    4857         1202 :             std::string const &CompName = state.dataAirLoop->OutsideAirSys(state.dataSize->CurOASysNum).ComponentName(CompNum);
    4858         2374 :             if (Util::SameString(CompType, "COIL:COOLING:WATER:DETAILEDGEOMETRY") || Util::SameString(CompType, "COIL:HEATING:WATER") ||
    4859         2374 :                 Util::SameString(CompType, "COILSYSTEM:COOLING:WATER:HEATEXCHANGERASSISTED")) {
    4860           30 :                 std::string CoilName;
    4861           30 :                 std::string CoilType;
    4862              : 
    4863           30 :                 if (Util::SameString(CompType, "COILSYSTEM:COOLING:WATER:HEATEXCHANGERASSISTED")) {
    4864            0 :                     CoilName = HVACHXAssistedCoolingCoil::GetHXDXCoilName(state, CompType, CompName, ErrorsFound);
    4865            0 :                     CoilType = HVACHXAssistedCoolingCoil::GetHXCoilType(state, CompType, CompName, ErrorsFound);
    4866              :                 } else {
    4867           30 :                     CoilName = CompName;
    4868           30 :                     CoilType = CompType;
    4869              :                 }
    4870           30 :                 WaterCoils::SetCoilDesFlow(state, CoilType, CoilName, this->MinOA, ErrorsFound);
    4871           30 :             }
    4872              :         } // End of component loop
    4873              :     }
    4874         1171 :     if (ErrorsFound) {
    4875            0 :         ShowFatalError(state, "Preceding sizing errors cause program termination");
    4876              :     }
    4877         1171 : }
    4878              : 
    4879              : // End of Sizing Section of the Module
    4880              : //******************************************************************************
    4881              : 
    4882              : // Beginning Update/Reporting Section of the Module
    4883              : //******************************************************************************
    4884              : 
    4885     27596359 : void OAControllerProps::UpdateOAController(EnergyPlusData &state)
    4886              : {
    4887              : 
    4888              :     // SUBROUTINE INFORMATION:
    4889              :     //       AUTHOR         Fred Buhl
    4890              :     //       DATE WRITTEN   Oct 1998
    4891              :     //       MODIFIED       Shirey/Raustad FSEC, June 2003
    4892              : 
    4893              :     // PURPOSE OF THIS SUBROUTINE
    4894              :     // Move the results of CalcOAController to the affected nodes
    4895              : 
    4896              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    4897     27596359 :     int OutAirNodeNum = this->OANode;
    4898     27596359 :     int InletAirNodeNum = this->InletNode;
    4899     27596359 :     int RelAirNodeNum = this->RelNode;
    4900     27596359 :     int RetAirNodeNum = this->RetNode;
    4901              : 
    4902     27596359 :     if (this->ControllerType == MixedAirControllerType::ControllerOutsideAir) {
    4903              :         // The outside air controller sets the outside air flow rate and the relief air flow rate
    4904     27038038 :         if (!state.dataGlobal->WarmupFlag && !state.dataGlobal->DoingSizing && (this->ManageDemand) &&
    4905         5660 :             (this->OAMassFlow > this->DemandLimitFlowRate)) {
    4906            0 :             state.dataLoopNodes->Node(OutAirNodeNum).MassFlowRate = this->DemandLimitFlowRate;
    4907            0 :             state.dataLoopNodes->Node(InletAirNodeNum).MassFlowRate = this->DemandLimitFlowRate;
    4908            0 :             state.dataLoopNodes->Node(OutAirNodeNum).MassFlowRateMaxAvail = this->DemandLimitFlowRate;
    4909              :         } else {
    4910     27032378 :             state.dataLoopNodes->Node(OutAirNodeNum).MassFlowRate = this->OAMassFlow;
    4911     27032378 :             state.dataLoopNodes->Node(InletAirNodeNum).MassFlowRate = this->OAMassFlow;
    4912     27032378 :             state.dataLoopNodes->Node(OutAirNodeNum).MassFlowRateMaxAvail = this->OAMassFlow;
    4913              :         }
    4914     27032378 :         state.dataLoopNodes->Node(RelAirNodeNum).MassFlowRate = this->RelMassFlow;
    4915              :     } else {
    4916              :         // The ERV controller sets the supply and secondary inlet node information for the Stand Alone ERV
    4917              :         // Currently, the Stand Alone ERV only has constant air flows (supply and exhaust), and these are
    4918              :         // already set in HVACStandAloneERV.cc (subroutine init). Therefore, these flow assignments below are
    4919              :         // currently redundant but may be useful in the future as mass flow rates can vary based on the controller signal.
    4920       563981 :         if (!state.dataGlobal->WarmupFlag && !state.dataGlobal->DoingSizing && (this->ManageDemand) &&
    4921            0 :             (this->OAMassFlow > this->DemandLimitFlowRate)) {
    4922            0 :             state.dataLoopNodes->Node(OutAirNodeNum).MassFlowRate = this->DemandLimitFlowRate;
    4923            0 :             state.dataLoopNodes->Node(OutAirNodeNum).MassFlowRateMaxAvail = this->DemandLimitFlowRate;
    4924              :         } else {
    4925       563981 :             state.dataLoopNodes->Node(OutAirNodeNum).MassFlowRate = this->OAMassFlow;
    4926       563981 :             state.dataLoopNodes->Node(OutAirNodeNum).MassFlowRateMaxAvail = this->OAMassFlow;
    4927              :         }
    4928       563981 :         state.dataLoopNodes->Node(RetAirNodeNum).MassFlowRate = state.dataLoopNodes->Node(this->RetNode).MassFlowRate;
    4929       563981 :         state.dataLoopNodes->Node(RetAirNodeNum).MassFlowRateMaxAvail = state.dataLoopNodes->Node(this->RetNode).MassFlowRate;
    4930              :     }
    4931     27596359 : }
    4932              : 
    4933     60004604 : void OAMixerProps::UpdateOAMixer(EnergyPlusData &state) const
    4934              : {
    4935              : 
    4936              :     // SUBROUTINE INFORMATION:
    4937              :     //       AUTHOR         Fred Buhl
    4938              :     //       DATE WRITTEN   Oct 1998
    4939              : 
    4940              :     // PURPOSE OF THIS SUBROUTINE
    4941              :     // Move the results of CalcOAMixer to the affected nodes
    4942              : 
    4943              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    4944     60004604 :     int MixNode = this->MixNode;
    4945     60004604 :     int RelNode = this->RelNode;
    4946     60004604 :     int RetNode = this->RetNode;
    4947              :     // Move mixed air data to the mixed air node
    4948     60004604 :     state.dataLoopNodes->Node(MixNode).MassFlowRate = this->MixMassFlowRate;
    4949     60004604 :     state.dataLoopNodes->Node(MixNode).Temp = this->MixTemp;
    4950     60004604 :     state.dataLoopNodes->Node(MixNode).HumRat = this->MixHumRat;
    4951     60004604 :     state.dataLoopNodes->Node(MixNode).Enthalpy = this->MixEnthalpy;
    4952     60004604 :     state.dataLoopNodes->Node(MixNode).Press = this->MixPressure;
    4953     60004604 :     state.dataLoopNodes->Node(MixNode).MassFlowRateMaxAvail = this->MixMassFlowRate;
    4954              :     // Move the relief air data to the relief air node
    4955     60004604 :     state.dataLoopNodes->Node(RelNode).MassFlowRate = this->RelMassFlowRate;
    4956     60004604 :     state.dataLoopNodes->Node(RelNode).Temp = this->RelTemp;
    4957     60004604 :     state.dataLoopNodes->Node(RelNode).HumRat = this->RelHumRat;
    4958     60004604 :     state.dataLoopNodes->Node(RelNode).Enthalpy = this->RelEnthalpy;
    4959     60004604 :     state.dataLoopNodes->Node(RelNode).Press = this->RelPressure;
    4960     60004604 :     state.dataLoopNodes->Node(RelNode).MassFlowRateMaxAvail = this->RelMassFlowRate;
    4961              : 
    4962     60004604 :     if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
    4963        76057 :         state.dataLoopNodes->Node(RelNode).CO2 = state.dataLoopNodes->Node(RetNode).CO2;
    4964        76057 :         if (this->MixMassFlowRate <= HVAC::VerySmallMassFlow) {
    4965         5561 :             state.dataLoopNodes->Node(MixNode).CO2 = state.dataLoopNodes->Node(RetNode).CO2;
    4966              :         } else {
    4967        70496 :             state.dataLoopNodes->Node(MixNode).CO2 =
    4968        70496 :                 ((state.dataLoopNodes->Node(RetNode).MassFlowRate - state.dataLoopNodes->Node(RelNode).MassFlowRate) *
    4969        70496 :                      state.dataLoopNodes->Node(RetNode).CO2 +
    4970        70496 :                  this->OAMassFlowRate * state.dataContaminantBalance->OutdoorCO2) /
    4971        70496 :                 this->MixMassFlowRate;
    4972              :         }
    4973              :     }
    4974              : 
    4975     60004604 :     if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
    4976        18150 :         state.dataLoopNodes->Node(RelNode).GenContam = state.dataLoopNodes->Node(RetNode).GenContam;
    4977        18150 :         if (this->MixMassFlowRate <= HVAC::VerySmallMassFlow) {
    4978         1957 :             state.dataLoopNodes->Node(MixNode).GenContam = state.dataLoopNodes->Node(RetNode).GenContam;
    4979              :         } else {
    4980        16193 :             state.dataLoopNodes->Node(MixNode).GenContam =
    4981        16193 :                 ((state.dataLoopNodes->Node(RetNode).MassFlowRate - state.dataLoopNodes->Node(RelNode).MassFlowRate) *
    4982        16193 :                      state.dataLoopNodes->Node(RetNode).GenContam +
    4983        16193 :                  this->OAMassFlowRate * state.dataContaminantBalance->OutdoorGC) /
    4984        16193 :                 this->MixMassFlowRate;
    4985              :         }
    4986              :     }
    4987     60004604 : }
    4988              : 
    4989              : // End of Sizing Section of the Module
    4990              : //******************************************************************************
    4991              : 
    4992              : // Beginning Utility Section of the Module
    4993              : //******************************************************************************
    4994              : 
    4995          877 : Array1D_int GetOAMixerNodeNumbers(EnergyPlusData &state,
    4996              :                                   std::string const &OAMixerName, // must match OA mixer names for the OA mixer type
    4997              :                                   bool &ErrorsFound               // set to true if problem
    4998              : )
    4999              : {
    5000              : 
    5001              :     // FUNCTION INFORMATION:
    5002              :     //       AUTHOR         Richard Raustad
    5003              :     //       DATE WRITTEN   June 2006
    5004              : 
    5005              :     // PURPOSE OF THIS FUNCTION:
    5006              :     // This function looks up the given OA mixer and returns the node numbers.  If
    5007              :     // incorrect OA mixer name is given, ErrorsFound is returned as true
    5008              :     // as zero.
    5009              : 
    5010              :     // Return value
    5011          877 :     Array1D_int OANodeNumbers(4); // return OA mixer nodes
    5012              : 
    5013              :     // Obtains and Allocates OA mixer related parameters from input file
    5014          877 :     if (state.dataMixedAir->GetOAMixerInputFlag) { // First time subroutine has been entered
    5015           37 :         GetOAMixerInputs(state);
    5016           37 :         state.dataMixedAir->GetOAMixerInputFlag = false;
    5017              :     }
    5018              : 
    5019          877 :     int WhichOAMixer = Util::FindItemInList(OAMixerName, state.dataMixedAir->OAMixer);
    5020          877 :     if (WhichOAMixer != 0) {
    5021          877 :         OANodeNumbers(1) = state.dataMixedAir->OAMixer(WhichOAMixer).InletNode;
    5022          877 :         OANodeNumbers(2) = state.dataMixedAir->OAMixer(WhichOAMixer).RelNode;
    5023          877 :         OANodeNumbers(3) = state.dataMixedAir->OAMixer(WhichOAMixer).RetNode;
    5024          877 :         OANodeNumbers(4) = state.dataMixedAir->OAMixer(WhichOAMixer).MixNode;
    5025              :     }
    5026              : 
    5027          877 :     if (WhichOAMixer == 0) {
    5028            0 :         ShowSevereError(state, format("GetOAMixerNodeNumbers: Could not find OA Mixer = \"{}\"", OAMixerName));
    5029            0 :         ErrorsFound = true;
    5030            0 :         OANodeNumbers = 0;
    5031              :     }
    5032              : 
    5033          877 :     return OANodeNumbers;
    5034            0 : }
    5035              : 
    5036           30 : int GetNumOAMixers(EnergyPlusData &state)
    5037              : {
    5038              : 
    5039              :     // FUNCTION INFORMATION:
    5040              :     //       AUTHOR         Linda Lawrie
    5041              :     //       DATE WRITTEN   October 2006
    5042              : 
    5043              :     // PURPOSE OF THIS FUNCTION:
    5044              :     // After making sure get input is done, the number of OA mixers is returned.
    5045              : 
    5046           30 :     if (state.dataMixedAir->GetOAMixerInputFlag) { // First time subroutine has been entered
    5047            0 :         GetOAMixerInputs(state);
    5048            0 :         state.dataMixedAir->GetOAMixerInputFlag = false;
    5049              :     }
    5050              : 
    5051           30 :     return state.dataMixedAir->NumOAMixers;
    5052              : }
    5053              : 
    5054            0 : int GetNumOAControllers(EnergyPlusData &state)
    5055              : {
    5056              : 
    5057              :     // FUNCTION INFORMATION:
    5058              :     //       AUTHOR         Linda Lawrie
    5059              :     //       DATE WRITTEN   October 2006
    5060              : 
    5061              :     // PURPOSE OF THIS FUNCTION:
    5062              :     // After making sure get input is done, the number of OA Controllers is returned.
    5063              : 
    5064            0 :     if (state.dataMixedAir->AllocateOAControllersFlag) {
    5065              :         // Make sure OAControllers are allocated
    5066            0 :         AllocateOAControllers(state);
    5067              :     }
    5068              : 
    5069            0 :     return state.dataMixedAir->NumOAControllers;
    5070              : }
    5071              : 
    5072           15 : int GetOAMixerReliefNodeNumber(EnergyPlusData &state, int const OAMixerNum) // Which Mixer
    5073              : {
    5074              : 
    5075              :     // FUNCTION INFORMATION:
    5076              :     //       AUTHOR         Linda Lawrie
    5077              :     //       DATE WRITTEN   October 2006
    5078              : 
    5079              :     // PURPOSE OF THIS FUNCTION:
    5080              :     // After making sure get input is done, the relief node number of indicated mixer is returned.
    5081              : 
    5082           15 :     if (state.dataMixedAir->GetOAMixerInputFlag) { // First time subroutine has been entered
    5083            0 :         GetOAMixerInputs(state);
    5084            0 :         state.dataMixedAir->GetOAMixerInputFlag = false;
    5085              :     }
    5086              : 
    5087           15 :     if (OAMixerNum > state.dataMixedAir->NumOAMixers) {
    5088            0 :         ShowFatalError(state,
    5089            0 :                        format("GetOAMixerReliefNodeNumber: Requested Mixer #={}, which is > number of OA Mixers={}",
    5090              :                               OAMixerNum,
    5091            0 :                               state.dataMixedAir->NumOAMixers));
    5092              :     }
    5093              : 
    5094           15 :     return state.dataMixedAir->OAMixer(OAMixerNum).RelNode;
    5095              : }
    5096              : 
    5097         1072 : int GetOASysControllerListIndex(EnergyPlusData &state, int const OASysNumber) // OA Sys Number
    5098              : {
    5099              : 
    5100              :     // FUNCTION INFORMATION:
    5101              :     //       AUTHOR         Fred Buhl
    5102              :     //       DATE WRITTEN   April 2007
    5103              : 
    5104              :     // PURPOSE OF THIS FUNCTION:
    5105              :     // After making sure get input is done, the Controller List index of the indicated OA System is returned.
    5106              : 
    5107         1072 :     if (state.dataMixedAir->GetOASysInputFlag) {
    5108            0 :         GetOutsideAirSysInputs(state);
    5109            0 :         state.dataMixedAir->GetOASysInputFlag = false;
    5110              :     }
    5111              : 
    5112         1072 :     return state.dataAirLoop->OutsideAirSys(OASysNumber).ControllerListNum;
    5113              : }
    5114              : 
    5115         1072 : int GetOASysNumSimpControllers(EnergyPlusData &state, int const OASysNumber) // OA Sys Number
    5116              : {
    5117              : 
    5118              :     // FUNCTION INFORMATION:
    5119              :     //       AUTHOR         Fred Buhl
    5120              :     //       DATE WRITTEN   April 2007
    5121              : 
    5122              :     // PURPOSE OF THIS FUNCTION:
    5123              :     // After making sure get input is done, the number of Controller:Simple objects in the OA System is returned.
    5124              : 
    5125         1072 :     if (state.dataMixedAir->GetOASysInputFlag) {
    5126            0 :         GetOutsideAirSysInputs(state);
    5127            0 :         state.dataMixedAir->GetOASysInputFlag = false;
    5128              :     }
    5129              : 
    5130         1072 :     return state.dataAirLoop->OutsideAirSys(OASysNumber).NumSimpleControllers;
    5131              : }
    5132              : 
    5133         1072 : int GetOASysNumHeatingCoils(EnergyPlusData &state, int const OASysNumber) // OA Sys Number
    5134              : {
    5135              : 
    5136              :     // FUNCTION INFORMATION:
    5137              :     //       AUTHOR         Fred Buhl
    5138              :     //       DATE WRITTEN   May 2007
    5139              : 
    5140              :     // PURPOSE OF THIS FUNCTION:
    5141              :     // After making sure get input is done, the number of heating coils in the OA System is returned.
    5142              : 
    5143              :     // FUNCTION LOCAL VARIABLE DECLARATIONS:
    5144         1072 :     bool Sim(false);
    5145         1072 :     bool FirstHVACIteration(false);
    5146         1072 :     bool OAHeatingCoil(false);
    5147         1072 :     bool OACoolingCoil(false);
    5148         1072 :     int AirLoopNum(0);
    5149         1072 :     bool OAHX(false);
    5150              : 
    5151         1072 :     if (state.dataMixedAir->GetOASysInputFlag) {
    5152            0 :         GetOutsideAirSysInputs(state);
    5153            0 :         state.dataMixedAir->GetOASysInputFlag = false;
    5154              :     }
    5155              : 
    5156         1072 :     int NumHeatingCoils = 0;
    5157         2279 :     for (int CompNum = 1; CompNum <= state.dataAirLoop->OutsideAirSys(OASysNumber).NumComponents; ++CompNum) {
    5158         1207 :         std::string const &CompType = state.dataAirLoop->OutsideAirSys(OASysNumber).ComponentType(CompNum);
    5159         1207 :         std::string const &CompName = state.dataAirLoop->OutsideAirSys(OASysNumber).ComponentName(CompNum);
    5160         4828 :         SimOAComponent(state,
    5161              :                        CompType,
    5162              :                        CompName,
    5163         1207 :                        state.dataAirLoop->OutsideAirSys(OASysNumber).ComponentTypeEnum(CompNum),
    5164              :                        FirstHVACIteration,
    5165         1207 :                        state.dataAirLoop->OutsideAirSys(OASysNumber).ComponentIndex(CompNum),
    5166              :                        AirLoopNum,
    5167              :                        Sim,
    5168              :                        OASysNumber,
    5169              :                        OAHeatingCoil,
    5170              :                        OACoolingCoil,
    5171              :                        OAHX);
    5172         1207 :         if (OAHeatingCoil) {
    5173           32 :             ++NumHeatingCoils;
    5174              :         }
    5175              :     }
    5176              : 
    5177         1072 :     return NumHeatingCoils;
    5178              : }
    5179              : 
    5180         1072 : int GetOASysNumHXs(EnergyPlusData &state, int const OASysNumber)
    5181              : {
    5182              : 
    5183              :     // FUNCTION INFORMATION:
    5184              :     //       AUTHOR         Fred Buhl, Rongpeng Zhang
    5185              :     //       DATE WRITTEN   Oct. 2015
    5186              : 
    5187              :     // PURPOSE OF THIS FUNCTION:
    5188              :     // After making sure get input is done, the number of heat recovery exchangers in the OA System is returned.
    5189              : 
    5190         1072 :     if (state.dataMixedAir->GetOASysInputFlag) {
    5191            0 :         GetOutsideAirSysInputs(state);
    5192            0 :         state.dataMixedAir->GetOASysInputFlag = false;
    5193              :     }
    5194              : 
    5195         1072 :     int NumHX = 0;
    5196              : 
    5197         1072 :     auto const &componentType_Num = state.dataAirLoop->OutsideAirSys(OASysNumber).ComponentTypeEnum;
    5198         2279 :     for (int CompNum = 1; CompNum <= state.dataAirLoop->OutsideAirSys(OASysNumber).NumComponents; ++CompNum) {
    5199         1207 :         SimAirServingZones::CompType const componentTypeNum = componentType_Num(CompNum);
    5200         1207 :         if (SimAirServingZones::CompType::HeatXchngr == componentTypeNum || SimAirServingZones::CompType::Desiccant == componentTypeNum) {
    5201           34 :             ++NumHX;
    5202              :         }
    5203              :     }
    5204              : 
    5205         1072 :     return NumHX;
    5206              : }
    5207              : 
    5208         1072 : int GetOASysNumCoolingCoils(EnergyPlusData &state, int const OASysNumber) // OA Sys Number
    5209              : {
    5210              : 
    5211              :     // FUNCTION INFORMATION:
    5212              :     //       AUTHOR         Fred Buhl
    5213              :     //       DATE WRITTEN   May 2007
    5214              : 
    5215              :     // PURPOSE OF THIS FUNCTION:
    5216              :     // After making sure get input is done, the number of cooling coils in the OA System is returned.
    5217              : 
    5218              :     // FUNCTION LOCAL VARIABLE DECLARATIONS:
    5219         1072 :     bool Sim(false);
    5220         1072 :     bool FirstHVACIteration(false);
    5221         1072 :     bool OAHeatingCoil(false);
    5222         1072 :     bool OACoolingCoil(false);
    5223         1072 :     int AirLoopNum(0);
    5224         1072 :     bool OAHX(false);
    5225              : 
    5226         1072 :     if (state.dataMixedAir->GetOASysInputFlag) {
    5227            0 :         GetOutsideAirSysInputs(state);
    5228            0 :         state.dataMixedAir->GetOASysInputFlag = false;
    5229              :     }
    5230              : 
    5231         1072 :     int NumCoolingCoils = 0;
    5232         2279 :     for (int CompNum = 1; CompNum <= state.dataAirLoop->OutsideAirSys(OASysNumber).NumComponents; ++CompNum) {
    5233         1207 :         std::string const &CompType = state.dataAirLoop->OutsideAirSys(OASysNumber).ComponentType(CompNum);
    5234         1207 :         std::string const &CompName = state.dataAirLoop->OutsideAirSys(OASysNumber).ComponentName(CompNum);
    5235         4828 :         SimOAComponent(state,
    5236              :                        CompType,
    5237              :                        CompName,
    5238         1207 :                        state.dataAirLoop->OutsideAirSys(OASysNumber).ComponentTypeEnum(CompNum),
    5239              :                        FirstHVACIteration,
    5240         1207 :                        state.dataAirLoop->OutsideAirSys(OASysNumber).ComponentIndex(CompNum),
    5241              :                        AirLoopNum,
    5242              :                        Sim,
    5243              :                        OASysNumber,
    5244              :                        OAHeatingCoil,
    5245              :                        OACoolingCoil,
    5246              :                        OAHX);
    5247         1207 :         if (OACoolingCoil) {
    5248           32 :             ++NumCoolingCoils;
    5249              :         }
    5250              :     }
    5251              : 
    5252         1072 :     return NumCoolingCoils;
    5253              : }
    5254              : 
    5255         1072 : int GetOASystemNumber(EnergyPlusData &state, std::string const &OASysName) // OA Sys Name
    5256              : {
    5257              : 
    5258              :     // FUNCTION INFORMATION:
    5259              :     //       AUTHOR         Linda Lawrie
    5260              :     //       DATE WRITTEN   October 2006
    5261              : 
    5262              :     // PURPOSE OF THIS FUNCTION:
    5263              :     // After making sure get input is done, the OA System number of indicated OA System is returned.
    5264              : 
    5265         1072 :     if (state.dataMixedAir->GetOASysInputFlag) {
    5266          212 :         GetOutsideAirSysInputs(state);
    5267          212 :         state.dataMixedAir->GetOASysInputFlag = false;
    5268              :     }
    5269              : 
    5270         1072 :     return Util::FindItemInList(OASysName, state.dataAirLoop->OutsideAirSys);
    5271              : }
    5272              : 
    5273         1072 : int FindOAMixerMatchForOASystem(EnergyPlusData &state, int const OASysNumber) // Which OA System
    5274              : {
    5275              : 
    5276              :     // FUNCTION INFORMATION:
    5277              :     //       AUTHOR         Linda Lawrie
    5278              :     //       DATE WRITTEN   October 2006
    5279              : 
    5280              :     // PURPOSE OF THIS FUNCTION:
    5281              :     // After making sure get input is done, the matched mixer number is found.
    5282              :     // Note -- only the first is looked at for an Outside Air System.
    5283              : 
    5284         1072 :     if (state.dataMixedAir->GetOAMixerInputFlag) {
    5285          391 :         GetOAMixerInputs(state);
    5286          391 :         state.dataMixedAir->GetOAMixerInputFlag = false;
    5287              :     }
    5288              : 
    5289         1072 :     int OAMixerNumber = 0;
    5290         1072 :     if (OASysNumber > 0 && OASysNumber <= state.dataAirLoop->NumOASystems) {
    5291         1204 :         for (int OACompNum = 1; OACompNum <= state.dataAirLoop->OutsideAirSys(OASysNumber).NumComponents; ++OACompNum) {
    5292         1204 :             if (Util::SameString(state.dataAirLoop->OutsideAirSys(OASysNumber).ComponentType(OACompNum), "OUTDOORAIR:MIXER")) {
    5293              :                 OAMixerNumber =
    5294         1072 :                     Util::FindItemInList(state.dataAirLoop->OutsideAirSys(OASysNumber).ComponentName(OACompNum), state.dataMixedAir->OAMixer);
    5295         1072 :                 break;
    5296              :             }
    5297              :         }
    5298              :     }
    5299              : 
    5300         1072 :     return OAMixerNumber;
    5301              : }
    5302              : 
    5303          600 : int GetOAMixerIndex(EnergyPlusData &state, std::string const &OAMixerName) // Which Mixer
    5304              : {
    5305              : 
    5306              :     // FUNCTION INFORMATION:
    5307              :     //       AUTHOR         Linda Lawrie
    5308              :     //       DATE WRITTEN   December 2010
    5309              : 
    5310              :     // PURPOSE OF THIS FUNCTION:
    5311              :     // After making sure get input is done, the mixer index of indicated mixer is returned.
    5312              : 
    5313          600 :     if (state.dataMixedAir->GetOAMixerInputFlag) {
    5314           26 :         GetOAMixerInputs(state);
    5315           26 :         state.dataMixedAir->GetOAMixerInputFlag = false;
    5316              :     }
    5317              : 
    5318          600 :     int OAMixerIndex = Util::FindItem(OAMixerName, state.dataMixedAir->OAMixer);
    5319              : 
    5320          600 :     if (OAMixerIndex == 0) {
    5321            0 :         ShowSevereError(state, format("GetOAMixerIndex: Could not find OutdoorAir:Mixer, Name=\"{}\"", OAMixerName));
    5322              :     }
    5323              : 
    5324          600 :     return OAMixerIndex;
    5325              : }
    5326              : 
    5327         1080 : int GetOAMixerInletNodeNumber(EnergyPlusData &state, int const OAMixerNumber) // Which Mixer
    5328              : {
    5329              : 
    5330              :     // FUNCTION INFORMATION:
    5331              :     //       AUTHOR         Linda Lawrie
    5332              :     //       DATE WRITTEN   October 2006
    5333              : 
    5334              :     // PURPOSE OF THIS FUNCTION:
    5335              :     // After making sure get input is done, the mixer inlet node number of indicated mixer is returned.
    5336              : 
    5337         1080 :     if (state.dataMixedAir->GetOAMixerInputFlag) {
    5338            0 :         GetOAMixerInputs(state);
    5339            0 :         state.dataMixedAir->GetOAMixerInputFlag = false;
    5340              :     }
    5341              : 
    5342         1080 :     int OAMixerInletNodeNumber = 0;
    5343         1080 :     if (OAMixerNumber > 0 && OAMixerNumber <= state.dataMixedAir->NumOAMixers) {
    5344         1080 :         OAMixerInletNodeNumber = state.dataMixedAir->OAMixer(OAMixerNumber).InletNode;
    5345              :     }
    5346              : 
    5347         1080 :     return OAMixerInletNodeNumber;
    5348              : }
    5349              : 
    5350        40088 : int GetOAMixerReturnNodeNumber(EnergyPlusData &state, int const OAMixerNumber) // Which Mixer
    5351              : {
    5352              : 
    5353              :     // FUNCTION INFORMATION:
    5354              :     //       AUTHOR         Brent Griffith
    5355              :     //       DATE WRITTEN   December 2006
    5356              : 
    5357              :     // PURPOSE OF THIS FUNCTION:
    5358              :     // After making sure get input is done, the mixer return node number of indicated mixer is returned.
    5359              : 
    5360              :     // METHODOLOGY EMPLOYED:
    5361              :     // followed Linda Lawrie's GetOAMixerInletNodeNumber
    5362              : 
    5363        40088 :     if (state.dataMixedAir->GetOAMixerInputFlag) {
    5364            0 :         GetOAMixerInputs(state);
    5365            0 :         state.dataMixedAir->GetOAMixerInputFlag = false;
    5366              :     }
    5367              : 
    5368        40088 :     int OAMixerReturnNodeNumber = 0;
    5369        40088 :     if (OAMixerNumber > 0 && OAMixerNumber <= state.dataMixedAir->NumOAMixers) {
    5370        40088 :         OAMixerReturnNodeNumber = state.dataMixedAir->OAMixer(OAMixerNumber).RetNode;
    5371              :     }
    5372              : 
    5373        40088 :     return OAMixerReturnNodeNumber;
    5374              : }
    5375              : 
    5376        40088 : int GetOAMixerMixedNodeNumber(EnergyPlusData &state, int const OAMixerNumber) // Which Mixer
    5377              : {
    5378              : 
    5379              :     // FUNCTION INFORMATION:
    5380              :     //       AUTHOR         Brent Griffith
    5381              :     //       DATE WRITTEN   December 2006
    5382              : 
    5383              :     // PURPOSE OF THIS FUNCTION:
    5384              :     // After making sure get input is done, the mixer mixed air node number of indicated mixer is returned.
    5385              : 
    5386        40088 :     if (state.dataMixedAir->GetOAMixerInputFlag) {
    5387            0 :         GetOAMixerInputs(state);
    5388            0 :         state.dataMixedAir->GetOAMixerInputFlag = false;
    5389              :     }
    5390              : 
    5391        40088 :     int OAMixerMixedNodeNumber = 0;
    5392        40088 :     if (OAMixerNumber > 0 && OAMixerNumber <= state.dataMixedAir->NumOAMixers) {
    5393        40088 :         OAMixerMixedNodeNumber = state.dataMixedAir->OAMixer(OAMixerNumber).MixNode;
    5394              :     }
    5395              : 
    5396        40088 :     return OAMixerMixedNodeNumber;
    5397              : }
    5398              : 
    5399          902 : bool CheckForControllerWaterCoil(EnergyPlusData &state,
    5400              :                                  DataAirLoop::ControllerKind ControllerType, // should be passed in as UPPERCASE
    5401              :                                  std::string const &ControllerName           // should be passed in as UPPERCASE
    5402              : )
    5403              : {
    5404              : 
    5405              :     // FUNCTION INFORMATION:
    5406              :     //       AUTHOR         Linda Lawrie
    5407              :     //       DATE WRITTEN   May 2009
    5408              : 
    5409              :     // PURPOSE OF THIS FUNCTION:
    5410              :     // This routine checks the controller list for existence of the reference coil.
    5411              : 
    5412          902 :     if (state.dataMixedAir->GetOASysInputFlag) {
    5413          284 :         GetOutsideAirSysInputs(state);
    5414          284 :         state.dataMixedAir->GetOASysInputFlag = false;
    5415              :     }
    5416              : 
    5417          902 :     int OnControllerList = false;
    5418              : 
    5419         6161 :     for (int Num = 1; Num <= state.dataMixedAir->NumControllerLists; ++Num) {
    5420        14303 :         for (int CompNum = 1; CompNum <= state.dataMixedAir->ControllerLists(Num).NumControllers; ++CompNum) {
    5421              : 
    5422         9946 :             if (state.dataMixedAir->ControllerLists(Num).ControllerType(CompNum) != ControllerType) {
    5423         2718 :                 continue;
    5424              :             }
    5425         7228 :             if (!Util::SameString(state.dataMixedAir->ControllerLists(Num).ControllerName(CompNum), ControllerName)) {
    5426         6326 :                 continue;
    5427              :             }
    5428          902 :             OnControllerList = true;
    5429          902 :             break;
    5430              :         }
    5431              :     }
    5432              : 
    5433          902 :     return OnControllerList;
    5434              : }
    5435              : 
    5436          800 : void CheckControllerLists(EnergyPlusData &state, bool &ErrFound)
    5437              : {
    5438              : 
    5439              :     // SUBROUTINE INFORMATION:
    5440              :     //       AUTHOR         Linda Lawrie
    5441              :     //       DATE WRITTEN   May 2009
    5442              : 
    5443              :     // PURPOSE OF THIS SUBROUTINE:
    5444              :     // This routine checks for a "dangling" controller list (AirLoopHVAC:ControllerList).
    5445              :     // It must be either found on a AirLoopHVAC or AirLoopHVAC:OutdoorAirSystem.
    5446              : 
    5447              :     // SUBROUTINE PARAMETER DEFINITIONS:
    5448         2400 :     static std::string const CurrentModuleObject("AirLoopHVAC:ControllerList");
    5449         2400 :     static std::string const AirLoopObject("AirLoopHVAC");
    5450              : 
    5451              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    5452              :     int NumAlphas;
    5453              :     int NumNumbers;
    5454              :     int IOStat;
    5455              : 
    5456          800 :     if (state.dataMixedAir->GetOASysInputFlag) {
    5457          254 :         GetOutsideAirSysInputs(state);
    5458          254 :         state.dataMixedAir->GetOASysInputFlag = false;
    5459              :     }
    5460              : 
    5461          800 :     int NumControllers = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject);
    5462          800 :     int NumAirLoop = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, AirLoopObject);
    5463          800 :     std::string_view AirLoopName = "";
    5464              : 
    5465         2309 :     for (int Item = 1; Item <= NumControllers; ++Item) {
    5466              : 
    5467         3018 :         state.dataInputProcessing->inputProcessor->getObjectItem(
    5468         1509 :             state, CurrentModuleObject, Item, state.dataIPShortCut->cAlphaArgs, NumAlphas, state.dataIPShortCut->rNumericArgs, NumNumbers, IOStat);
    5469         1509 :         std::string const ControllerListName = state.dataIPShortCut->cAlphaArgs(1);
    5470         1509 :         int Count = 0;
    5471              : 
    5472              :         // Check AirLoopHVAC -- brute force, get each AirLoopHVAC
    5473              : 
    5474        14459 :         for (int Loop = 1; Loop <= NumAirLoop; ++Loop) {
    5475        25900 :             state.dataInputProcessing->inputProcessor->getObjectItem(
    5476        12950 :                 state, AirLoopObject, Loop, state.dataIPShortCut->cAlphaArgs, NumAlphas, state.dataIPShortCut->rNumericArgs, NumNumbers, IOStat);
    5477        12950 :             if (state.dataIPShortCut->cAlphaArgs(2) != ControllerListName) {
    5478        12509 :                 continue;
    5479              :             }
    5480          441 :             if (++Count == 1) {
    5481          441 :                 AirLoopName = state.dataIPShortCut->cAlphaArgs(1);
    5482              :             }
    5483              :         }
    5484              : 
    5485              :         //  Now check AirLoopHVAC and AirLoopHVAC:OutdoorAirSystem
    5486         1509 :         int Found = 0;
    5487         1509 :         if (state.dataAirLoop->NumOASystems > 0) {
    5488         1427 :             Found = Util::FindItemInList(ControllerListName, state.dataAirLoop->OutsideAirSys, &OutsideAirSysProps::ControllerListName);
    5489         1427 :             if (Found > 0) {
    5490         1068 :                 ++Count;
    5491              :             }
    5492              :         }
    5493              : 
    5494         1509 :         if (Count == 0) {
    5495            0 :             ShowSevereError(state,
    5496            0 :                             format("{}=\"{}\" is not referenced on a AirLoopHVAC or AirLoopHVAC:OutdoorAirSystem object.",
    5497              :                                    CurrentModuleObject,
    5498              :                                    ControllerListName));
    5499            0 :             ErrFound = true;
    5500         1509 :         } else if (Count > 1) {
    5501            0 :             ShowSevereError(state,
    5502            0 :                             format("{}=\"{}\" has too many references on AirLoopHVAC or AirLoopHVAC:OutdoorAirSystem objects.",
    5503              :                                    CurrentModuleObject,
    5504              :                                    ControllerListName));
    5505            0 :             if (Found > 0) {
    5506            0 :                 ShowContinueError(state, format("...AirLoopHVAC:OutdoorAirSystem=\"{}\".", state.dataAirLoop->OutsideAirSys(Found).Name));
    5507              :             }
    5508            0 :             ShowContinueError(state, format("...also on AirLoopHVAC=\"{}\".", AirLoopName));
    5509            0 :             ErrFound = true;
    5510              :         }
    5511         1509 :     }
    5512          800 : }
    5513              : 
    5514          104 : void CheckOAControllerName(
    5515              :     EnergyPlusData &state, std::string &OAControllerName, std::string const &ObjectType, std::string const &FieldName, bool &ErrorsFound)
    5516              : {
    5517              : 
    5518              :     // SUBROUTINE INFORMATION:
    5519              :     //       AUTHOR         Linda Lawrie
    5520              :     //       DATE WRITTEN   October 2006
    5521              : 
    5522              :     // PURPOSE OF THIS SUBROUTINE:
    5523              :     // When OA Controller data is gotten from other routines, must check to make sure
    5524              :     // new name doesn't duplicate.  (Essentially a pass through to call Verify Name)
    5525              :     // Currently, this is only called from HVACStandAlongERV::GetStandaloneERV()
    5526              : 
    5527          104 :     if (state.dataMixedAir->AllocateOAControllersFlag) {
    5528              :         // Make sure OAControllers are allocated
    5529            3 :         AllocateOAControllers(state);
    5530              :     }
    5531              : 
    5532          104 :     GlobalNames::VerifyUniqueInterObjectName(
    5533          104 :         state, state.dataMixedAir->OAControllerUniqueNames, OAControllerName, ObjectType, FieldName, ErrorsFound);
    5534          104 : }
    5535              : 
    5536     16528585 : void OAControllerProps::Checksetpoints(EnergyPlusData &state,
    5537              :                                        Real64 const OutAirMinFrac,   // Local variable used to calculate min OA fraction
    5538              :                                        Real64 &OutAirSignal,         // Used to set OA mass flow rate
    5539              :                                        bool &EconomizerOperationFlag // logical used to show economizer status
    5540              : )
    5541              : {
    5542              : 
    5543              :     // SUBROUTINE INFORMATION:
    5544              :     //       AUTHOR         Amit bhansali
    5545              :     //       DATE WRITTEN   August 2008?
    5546              : 
    5547              :     // PURPOSE OF THIS SUBROUTINE:
    5548              :     // This subroutine checks the setpoints of the upper limits of temperatures, limit enthalpy
    5549              :     // Limit dew point, Enthalpy curve
    5550              : 
    5551     16528585 :     if (this->TempLim != HVAC::BlankNumeric && this->OATemp > this->TempLim) {
    5552      6231231 :         OutAirSignal = OutAirMinFrac;
    5553      6231231 :         EconomizerOperationFlag = false;
    5554              :     }
    5555              :     // Outside air enthalpy limit
    5556     16528585 :     if (this->EnthLim != HVAC::BlankNumeric && this->OAEnth > this->EnthLim) {
    5557      5580202 :         OutAirSignal = OutAirMinFrac;
    5558      5580202 :         EconomizerOperationFlag = false;
    5559              :     }
    5560              : 
    5561     16528585 :     if (this->DPTempLim != HVAC::BlankNumeric) {
    5562        93921 :         Real64 OADPTemp = Psychrometrics::PsyTdpFnWPb(state, this->OAHumRat, this->OAPress);
    5563        93921 :         if (OADPTemp > this->DPTempLim) {
    5564        46463 :             OutAirSignal = OutAirMinFrac;
    5565        46463 :             EconomizerOperationFlag = false;
    5566              :         }
    5567              :     }
    5568              : 
    5569     16528585 :     if (this->EnthalpyCurvePtr > 0) {
    5570        65070 :         if (this->OAHumRat > Curve::CurveValue(state, this->EnthalpyCurvePtr, this->OATemp)) {
    5571        36383 :             OutAirSignal = OutAirMinFrac;
    5572        36383 :             EconomizerOperationFlag = false;
    5573              :         }
    5574              :     }
    5575     16528585 : }
    5576              : 
    5577          612 : int GetNumOASystems(EnergyPlusData &state)
    5578              : {
    5579              : 
    5580              :     // FUNCTION INFORMATION:
    5581              :     //       AUTHOR         Linda Lawrie
    5582              :     //       DATE WRITTEN   November 2010
    5583              : 
    5584              :     // PURPOSE OF THIS FUNCTION:
    5585              :     // Get Number of OA Systems, After making sure get input is done
    5586              : 
    5587          612 :     if (state.dataMixedAir->GetOASysInputFlag) {
    5588           51 :         GetOutsideAirSysInputs(state);
    5589           51 :         state.dataMixedAir->GetOASysInputFlag = false;
    5590              :     }
    5591              : 
    5592          612 :     return state.dataAirLoop->NumOASystems;
    5593              : }
    5594              : 
    5595         1073 : int GetOACompListNumber(EnergyPlusData &state, int const OASysNum) // OA Sys Number
    5596              : {
    5597              : 
    5598              :     // FUNCTION INFORMATION:
    5599              :     //       AUTHOR         Heejin Cho
    5600              :     //       DATE WRITTEN   November 2010
    5601              : 
    5602              :     // PURPOSE OF THIS FUNCTION:
    5603              :     // After making sure get input is done, the OA System number of indicated OA System is returned.
    5604              : 
    5605         1073 :     if (state.dataMixedAir->GetOASysInputFlag) {
    5606            0 :         GetOutsideAirSysInputs(state);
    5607            0 :         state.dataMixedAir->GetOASysInputFlag = false;
    5608              :     }
    5609              : 
    5610         1073 :     return state.dataAirLoop->OutsideAirSys(OASysNum).NumComponents;
    5611              : }
    5612              : 
    5613           61 : std::string GetOACompName(EnergyPlusData &state,
    5614              :                           int const OASysNum, // OA Sys Number
    5615              :                           int const InListNum // In-list Number
    5616              : )
    5617              : {
    5618              : 
    5619              :     // FUNCTION INFORMATION:
    5620              :     //       AUTHOR         Heejin Cho
    5621              :     //       DATE WRITTEN   November 2010
    5622              : 
    5623              :     // PURPOSE OF THIS FUNCTION:
    5624              :     // After making sure get input is done, the number of heating coils in the OA System is returned.
    5625              : 
    5626           61 :     if (state.dataMixedAir->GetOASysInputFlag) {
    5627            0 :         GetOutsideAirSysInputs(state);
    5628            0 :         state.dataMixedAir->GetOASysInputFlag = false;
    5629              :     }
    5630              : 
    5631           61 :     return state.dataAirLoop->OutsideAirSys(OASysNum).ComponentName(InListNum);
    5632              : }
    5633              : 
    5634           61 : std::string GetOACompType(EnergyPlusData &state,
    5635              :                           int const OASysNum, // OA Sys Number
    5636              :                           int const InListNum // In-list Number
    5637              : )
    5638              : {
    5639              : 
    5640              :     // FUNCTION INFORMATION:
    5641              :     //       AUTHOR         Heejin Cho
    5642              :     //       DATE WRITTEN   November 2010
    5643              : 
    5644              :     // PURPOSE OF THIS FUNCTION:
    5645              :     // After making sure get input is done, the number of heating coils in the OA System is returned.
    5646              : 
    5647           61 :     if (state.dataMixedAir->GetOASysInputFlag) {
    5648            0 :         GetOutsideAirSysInputs(state);
    5649            0 :         state.dataMixedAir->GetOASysInputFlag = false;
    5650              :     }
    5651              : 
    5652           61 :     return state.dataAirLoop->OutsideAirSys(OASysNum).ComponentType(InListNum);
    5653              : }
    5654              : 
    5655         1210 : SimAirServingZones::CompType GetOACompTypeNum(EnergyPlusData &state,
    5656              :                                               int const OASysNum, // OA Sys Number
    5657              :                                               int const InListNum // In-list Number
    5658              : )
    5659              : {
    5660              : 
    5661              :     // FUNCTION INFORMATION:
    5662              :     //       AUTHOR         Heejin Cho
    5663              :     //       DATE WRITTEN   November 2010
    5664              : 
    5665              :     // PURPOSE OF THIS FUNCTION:
    5666              :     // After making sure get input is done, the number of heating coils in the OA System is returned.
    5667              : 
    5668         1210 :     if (state.dataMixedAir->GetOASysInputFlag) {
    5669            0 :         GetOutsideAirSysInputs(state);
    5670            0 :         state.dataMixedAir->GetOASysInputFlag = false;
    5671              :     }
    5672              : 
    5673         1210 :     return state.dataAirLoop->OutsideAirSys(OASysNum).ComponentTypeEnum(InListNum);
    5674              : }
    5675              : 
    5676            4 : int GetOAMixerNumber(EnergyPlusData &state, std::string const &OAMixerName // must match OA mixer names for the OA mixer type
    5677              : )
    5678              : {
    5679              : 
    5680              :     // FUNCTION INFORMATION:
    5681              :     //       AUTHOR         Lixing Gu
    5682              :     //       DATE WRITTEN   Feb. 2018
    5683              : 
    5684              :     // PURPOSE OF THIS FUNCTION:
    5685              :     // This function looks up the given OA mixer and returns the OAMixer number.  If
    5686              :     // incorrect OA mixer name is given, ErrorsFound is returned as true
    5687              : 
    5688              :     // Obtains and Allocates OA mixer related parameters from input file
    5689            4 :     if (state.dataMixedAir->GetOAMixerInputFlag) { // First time subroutine has been entered
    5690            2 :         GetOAMixerInputs(state);
    5691            2 :         state.dataMixedAir->GetOAMixerInputFlag = false;
    5692              :     }
    5693              : 
    5694            4 :     return Util::FindItemInList(OAMixerName, state.dataMixedAir->OAMixer);
    5695              : }
    5696              : // End of Utility Section of the Module
    5697              : //******************************************************************************
    5698              : 
    5699              : } // namespace EnergyPlus::MixedAir
        

Generated by: LCOV version 2.0-1