LCOV - code coverage report
Current view: top level - EnergyPlus - MixedAir.cc (source / functions) Hit Total Coverage
Test: lcov.output.filtered Lines: 2098 2861 73.3 %
Date: 2024-08-23 23:50:59 Functions: 53 56 94.6 %

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

Generated by: LCOV version 1.14