LCOV - code coverage report
Current view: top level - EnergyPlus - PurchasedAirManager.cc (source / functions) Hit Total Coverage
Test: lcov.output.filtered Lines: 1146 1911 60.0 %
Date: 2024-08-23 23:50:59 Functions: 16 17 94.1 %

          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             : 
      51             : // ObjexxFCL Headers
      52             : #include <ObjexxFCL/Array.functions.hh>
      53             : #include <ObjexxFCL/Fmath.hh>
      54             : #include <ObjexxFCL/string.functions.hh>
      55             : 
      56             : // EnergyPlus Headers
      57             : #include <EnergyPlus/Autosizing/CoolingAirFlowSizing.hh>
      58             : #include <EnergyPlus/Autosizing/CoolingCapacitySizing.hh>
      59             : #include <EnergyPlus/Autosizing/HeatingAirFlowSizing.hh>
      60             : #include <EnergyPlus/Autosizing/HeatingCapacitySizing.hh>
      61             : #include <EnergyPlus/Data/EnergyPlusData.hh>
      62             : #include <EnergyPlus/DataContaminantBalance.hh>
      63             : #include <EnergyPlus/DataEnvironment.hh>
      64             : #include <EnergyPlus/DataHVACGlobals.hh>
      65             : #include <EnergyPlus/DataHeatBalFanSys.hh>
      66             : #include <EnergyPlus/DataHeatBalance.hh>
      67             : #include <EnergyPlus/DataIPShortCuts.hh>
      68             : #include <EnergyPlus/DataLoopNode.hh>
      69             : #include <EnergyPlus/DataSizing.hh>
      70             : #include <EnergyPlus/DataZoneEnergyDemands.hh>
      71             : #include <EnergyPlus/DataZoneEquipment.hh>
      72             : #include <EnergyPlus/EMSManager.hh>
      73             : #include <EnergyPlus/General.hh>
      74             : #include <EnergyPlus/GeneralRoutines.hh>
      75             : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
      76             : #include <EnergyPlus/NodeInputManager.hh>
      77             : #include <EnergyPlus/OutAirNodeManager.hh>
      78             : #include <EnergyPlus/OutputProcessor.hh>
      79             : #include <EnergyPlus/Psychrometrics.hh>
      80             : #include <EnergyPlus/PurchasedAirManager.hh>
      81             : #include <EnergyPlus/ScheduleManager.hh>
      82             : #include <EnergyPlus/UtilityRoutines.hh>
      83             : #include <EnergyPlus/ZonePlenum.hh>
      84             : #include <EnergyPlus/ZoneTempPredictorCorrector.hh>
      85             : 
      86             : namespace EnergyPlus::PurchasedAirManager {
      87             : 
      88             : // Module containing data and routines dealing with Ideal Loads Air System (formerly PURCHASED AIR).
      89             : 
      90             : // MODULE INFORMATION:
      91             : //       AUTHOR         Russ Taylor
      92             : //       DATE WRITTEN   May 1997
      93             : //       MODIFIED       Fred Buhl Dec 1999
      94             : //                      B. Griffith Dec 2006. added OA lookup function, moved getinputflag up to Module
      95             : //                      M. Witte June 2011, add new features including DCV, economizer, dehumidification and humidification
      96             : //                      NOTE: MJW Sep 13, 2011:  Still need to review checks for negative loads and impossible supply temps???
      97             : //                           There are no Deallocate statements in here - should there be?
      98             : //       RE-ENGINEERED  na
      99             : 
     100             : // PURPOSE OF THIS MODULE:
     101             : // To encapsulate the data and algorithms required to simulate the
     102             : // Zone Ideal Loads Air System component. This component supplies hot or cold air
     103             : // at a fixed or variable temperature to a zone to meet the zone load.
     104             : // With the June 2011 enhancements it will also supply outdoor air with optional demand-controlled ventilation
     105             : // and economizer controls, plus new options for controlling zone humidity.
     106             : 
     107             : // METHODOLOGY EMPLOYED:
     108             : // The user can choose via input the max/min hot and cold supply air
     109             : // temperature and humidity ratio. The air mass flow rate is chosen
     110             : // to meet the (remaining) zone load or based on the outdoor air flow requirement.
     111             : // If the outdoor air flow sets the flow rate, the supply air temperature and
     112             : // humidity ratio are adjusted to meet the zone load.
     113             : 
     114             : // Using/Aliasing
     115             : using namespace ScheduleManager;
     116             : using Psychrometrics::PsyCpAirFnW;
     117             : using Psychrometrics::PsyHFnTdbW;
     118             : using Psychrometrics::PsyRhoAirFnPbTdbW;
     119             : using Psychrometrics::PsyTdbFnHW;
     120             : using Psychrometrics::PsyTsatFnHPb;
     121             : using Psychrometrics::PsyWFnTdbH;
     122             : using Psychrometrics::PsyWFnTdbRhPb;
     123             : 
     124             : // Delta humidity ratio limit, 0.00025 equals delta between 45F dewpoint and 46F dewpoint
     125             : // used to prevent dividing by near zero
     126             : Real64 constexpr SmallDeltaHumRat(0.00025);
     127             : 
     128     2076247 : void SimPurchasedAir(EnergyPlusData &state,
     129             :                      std::string const &PurchAirName,
     130             :                      Real64 &SysOutputProvided,
     131             :                      Real64 &MoistOutputProvided, // Moisture output provided (kg/s), dehumidification = negative
     132             :                      bool const FirstHVACIteration,
     133             :                      int const ControlledZoneNum,
     134             :                      int &CompIndex)
     135             : {
     136             : 
     137             :     // SUBROUTINE INFORMATION:
     138             :     //       AUTHOR         Russ Taylor
     139             :     //       DATE WRITTEN   May 1997
     140             :     //       MODIFIED       Don Shirey, Aug 2009 (LatOutputProvided - now MoistOutputProvided)
     141             :     //       RE-ENGINEERED  na
     142             : 
     143             :     // PURPOSE OF THIS SUBROUTINE:
     144             :     // This subroutine manages Purchased Air component simulation.
     145             :     // It is called from SimZoneEquipment in the ZoneEquipmentManager
     146             :     // at the system time step.
     147             : 
     148             :     int PurchAirNum;
     149             : 
     150     2076247 :     if (state.dataPurchasedAirMgr->GetPurchAirInputFlag) {
     151          78 :         GetPurchasedAir(state);
     152          78 :         state.dataPurchasedAirMgr->GetPurchAirInputFlag = false;
     153             :     }
     154             : 
     155             :     // Find the correct PurchasedAir Equipment
     156     2076247 :     if (CompIndex == 0) {
     157         219 :         PurchAirNum = Util::FindItemInList(PurchAirName, state.dataPurchasedAirMgr->PurchAir);
     158         219 :         if (PurchAirNum == 0) {
     159           0 :             ShowFatalError(state, format("SimPurchasedAir: Unit not found={}", PurchAirName));
     160             :         }
     161         219 :         CompIndex = PurchAirNum;
     162             :     } else {
     163     2076028 :         PurchAirNum = CompIndex;
     164     2076028 :         if (PurchAirNum > state.dataPurchasedAirMgr->NumPurchAir || PurchAirNum < 1) {
     165           0 :             ShowFatalError(state,
     166           0 :                            format("SimPurchasedAir:  Invalid CompIndex passed={}, Number of Units={}, Entered Unit name={}",
     167             :                                   PurchAirNum,
     168           0 :                                   state.dataPurchasedAirMgr->NumPurchAir,
     169             :                                   PurchAirName));
     170             :         }
     171     2076028 :         if (state.dataPurchasedAirMgr->CheckEquipName(PurchAirNum)) {
     172         219 :             if (PurchAirName != state.dataPurchasedAirMgr->PurchAir(PurchAirNum).Name) {
     173           0 :                 ShowFatalError(state,
     174           0 :                                format("SimPurchasedAir: Invalid CompIndex passed={}, Unit name={}, stored Unit Name for that index={}",
     175             :                                       PurchAirNum,
     176             :                                       PurchAirName,
     177           0 :                                       state.dataPurchasedAirMgr->PurchAir(PurchAirNum).Name));
     178             :             }
     179         219 :             state.dataPurchasedAirMgr->CheckEquipName(PurchAirNum) = false;
     180             :         }
     181             :     }
     182             : 
     183     2076247 :     InitPurchasedAir(state, PurchAirNum, ControlledZoneNum);
     184             : 
     185     2076247 :     CalcPurchAirLoads(state, PurchAirNum, SysOutputProvided, MoistOutputProvided, ControlledZoneNum);
     186             : 
     187     2076247 :     UpdatePurchasedAir(state, PurchAirNum, FirstHVACIteration);
     188             : 
     189     2076247 :     ReportPurchasedAir(state, PurchAirNum);
     190     2076247 : }
     191             : 
     192         266 : void GetPurchasedAir(EnergyPlusData &state)
     193             : {
     194             : 
     195             :     // SUBROUTINE INFORMATION:
     196             :     //       AUTHOR         Russ Taylor
     197             :     //       DATE WRITTEN   June 1997
     198             :     //       MODIFIED       M. Witte, June 2011, add new features including DCV, economizer, dehumidification
     199             :     //                                           and humidification controls
     200             :     //       RE-ENGINEERED  na
     201             : 
     202             :     // PURPOSE OF THIS SUBROUTINE:
     203             :     // Get the input data for the Purchased Air objects.
     204             :     // Set up output variables.
     205             : 
     206             :     // Using/Aliasing
     207             :     using NodeInputManager::CheckUniqueNodeNames;
     208             :     using NodeInputManager::EndUniqueNodeCheck;
     209             :     using NodeInputManager::GetOnlySingleNode;
     210             :     using NodeInputManager::InitUniqueNodeCheck;
     211             :     using OutAirNodeManager::CheckAndAddAirNodeNumber;
     212             :     using namespace DataLoopNode;
     213             :     using ZonePlenum::GetReturnPlenumIndex;
     214             : 
     215             :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     216             :     int PurchAirNum;
     217             :     int NumAlphas;
     218             :     int NumNums;
     219             :     int IOStat;
     220             :     int CtrlZone;                                                       // zone index
     221             :     int NodeNum;                                                        // node index
     222             :     static constexpr std::string_view RoutineName("GetPurchasedAir: "); // include trailing blank space
     223         266 :     bool ErrorsFound(false);                                            // If errors detected in input
     224             :     bool IsOANodeListed;                                                // Flag for OA node name listed in OutdoorAir:Node or Nodelist
     225             :     bool UniqueNodeError;                                               // Flag for non-unique node error(s)
     226         266 :     auto &cCurrentModuleObject = state.dataIPShortCut->cCurrentModuleObject;
     227         266 :     cCurrentModuleObject = "ZoneHVAC:IdealLoadsAirSystem";
     228             : 
     229         266 :     auto &PurchAir(state.dataPurchasedAirMgr->PurchAir);
     230             : 
     231         266 :     state.dataPurchasedAirMgr->NumPurchAir = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
     232             : 
     233         266 :     PurchAir.allocate(state.dataPurchasedAirMgr->NumPurchAir);
     234         266 :     state.dataPurchasedAirMgr->CheckEquipName.allocate(state.dataPurchasedAirMgr->NumPurchAir);
     235         266 :     state.dataPurchasedAirMgr->PurchAirNumericFields.allocate(state.dataPurchasedAirMgr->NumPurchAir);
     236         266 :     state.dataPurchasedAirMgr->CheckEquipName = true;
     237             : 
     238         266 :     if (state.dataPurchasedAirMgr->NumPurchAir > 0) {
     239          78 :         InitUniqueNodeCheck(state, cCurrentModuleObject);
     240         297 :         for (PurchAirNum = 1; PurchAirNum <= state.dataPurchasedAirMgr->NumPurchAir; ++PurchAirNum) {
     241         219 :             PurchAir(PurchAirNum).cObjectName = cCurrentModuleObject;
     242             : 
     243         438 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
     244             :                                                                      cCurrentModuleObject,
     245             :                                                                      PurchAirNum,
     246         219 :                                                                      state.dataIPShortCut->cAlphaArgs,
     247             :                                                                      NumAlphas,
     248         219 :                                                                      state.dataIPShortCut->rNumericArgs,
     249             :                                                                      NumNums,
     250             :                                                                      IOStat,
     251         219 :                                                                      state.dataIPShortCut->lNumericFieldBlanks,
     252         219 :                                                                      state.dataIPShortCut->lAlphaFieldBlanks,
     253         219 :                                                                      state.dataIPShortCut->cAlphaFieldNames,
     254         219 :                                                                      state.dataIPShortCut->cNumericFieldNames);
     255             : 
     256         219 :             state.dataPurchasedAirMgr->PurchAirNumericFields(PurchAirNum).FieldNames.allocate(NumNums);
     257         219 :             state.dataPurchasedAirMgr->PurchAirNumericFields(PurchAirNum).FieldNames = "";
     258         219 :             state.dataPurchasedAirMgr->PurchAirNumericFields(PurchAirNum).FieldNames = state.dataIPShortCut->cNumericFieldNames;
     259         219 :             Util::IsNameEmpty(state, state.dataIPShortCut->cAlphaArgs(1), cCurrentModuleObject, ErrorsFound);
     260             : 
     261         219 :             PurchAir(PurchAirNum).Name = state.dataIPShortCut->cAlphaArgs(1);
     262             :             // get optional  availability schedule
     263         219 :             PurchAir(PurchAirNum).AvailSched = state.dataIPShortCut->cAlphaArgs(2);
     264         219 :             if (state.dataIPShortCut->lAlphaFieldBlanks(2)) {
     265         214 :                 PurchAir(PurchAirNum).AvailSchedPtr = ScheduleManager::ScheduleAlwaysOn;
     266             :             } else {
     267           5 :                 PurchAir(PurchAirNum).AvailSchedPtr = GetScheduleIndex(state, state.dataIPShortCut->cAlphaArgs(2));
     268           5 :                 if (PurchAir(PurchAirNum).AvailSchedPtr == 0) {
     269           0 :                     ShowSevereError(state, format("{}{}=\"{} invalid data", RoutineName, cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
     270           0 :                     ShowContinueError(
     271             :                         state,
     272           0 :                         format("Invalid-not found {}=\"{}\".", state.dataIPShortCut->cAlphaFieldNames(2), state.dataIPShortCut->cAlphaArgs(2)));
     273           0 :                     ErrorsFound = true;
     274             :                 }
     275             :             }
     276             :             // Purchased air supply air node is an outlet node
     277         438 :             PurchAir(PurchAirNum).ZoneSupplyAirNodeNum = GetOnlySingleNode(state,
     278         219 :                                                                            state.dataIPShortCut->cAlphaArgs(3),
     279             :                                                                            ErrorsFound,
     280             :                                                                            DataLoopNode::ConnectionObjectType::ZoneHVACIdealLoadsAirSystem,
     281         219 :                                                                            state.dataIPShortCut->cAlphaArgs(1),
     282             :                                                                            DataLoopNode::NodeFluidType::Air,
     283             :                                                                            DataLoopNode::ConnectionType::Outlet,
     284             :                                                                            NodeInputManager::CompFluidStream::Primary,
     285             :                                                                            ObjectIsNotParent);
     286         219 :             UniqueNodeError = false;
     287         219 :             CheckUniqueNodeNames(state,
     288         219 :                                  state.dataIPShortCut->cAlphaFieldNames(3),
     289             :                                  UniqueNodeError,
     290         219 :                                  state.dataIPShortCut->cAlphaArgs(3),
     291         219 :                                  state.dataIPShortCut->cAlphaArgs(1));
     292         219 :             if (UniqueNodeError) ErrorsFound = true;
     293             :             // If new (optional) exhaust air node name is present, then register it as inlet
     294         219 :             if (!state.dataIPShortCut->lAlphaFieldBlanks(4)) {
     295           6 :                 if (state.dataIPShortCut->lAlphaFieldBlanks(5)) {
     296           2 :                     PurchAir(PurchAirNum).ZoneExhaustAirNodeNum = GetOnlySingleNode(state,
     297           1 :                                                                                     state.dataIPShortCut->cAlphaArgs(4),
     298             :                                                                                     ErrorsFound,
     299             :                                                                                     DataLoopNode::ConnectionObjectType::ZoneHVACIdealLoadsAirSystem,
     300           1 :                                                                                     state.dataIPShortCut->cAlphaArgs(1),
     301             :                                                                                     DataLoopNode::NodeFluidType::Air,
     302             :                                                                                     DataLoopNode::ConnectionType::Inlet,
     303             :                                                                                     NodeInputManager::CompFluidStream::Primary,
     304             :                                                                                     ObjectIsNotParent);
     305             :                 } else {
     306          10 :                     PurchAir(PurchAirNum).ZoneExhaustAirNodeNum = GetOnlySingleNode(state,
     307           5 :                                                                                     state.dataIPShortCut->cAlphaArgs(4),
     308             :                                                                                     ErrorsFound,
     309             :                                                                                     DataLoopNode::ConnectionObjectType::ZoneHVACIdealLoadsAirSystem,
     310           5 :                                                                                     state.dataIPShortCut->cAlphaArgs(1),
     311             :                                                                                     DataLoopNode::NodeFluidType::Air,
     312             :                                                                                     DataLoopNode::ConnectionType::Outlet,
     313             :                                                                                     NodeInputManager::CompFluidStream::Primary,
     314             :                                                                                     ObjectIsNotParent);
     315             :                 }
     316           6 :                 UniqueNodeError = false;
     317           6 :                 CheckUniqueNodeNames(state,
     318           6 :                                      state.dataIPShortCut->cAlphaFieldNames(4),
     319             :                                      UniqueNodeError,
     320           6 :                                      state.dataIPShortCut->cAlphaArgs(4),
     321           6 :                                      state.dataIPShortCut->cAlphaArgs(1));
     322           6 :                 if (UniqueNodeError) ErrorsFound = true;
     323             :             }
     324         219 :             if (!state.dataIPShortCut->lAlphaFieldBlanks(5)) {
     325          10 :                 PurchAir(PurchAirNum).PlenumExhaustAirNodeNum = GetOnlySingleNode(state,
     326           5 :                                                                                   state.dataIPShortCut->cAlphaArgs(5),
     327             :                                                                                   ErrorsFound,
     328             :                                                                                   DataLoopNode::ConnectionObjectType::ZoneHVACIdealLoadsAirSystem,
     329           5 :                                                                                   state.dataIPShortCut->cAlphaArgs(1),
     330             :                                                                                   DataLoopNode::NodeFluidType::Air,
     331             :                                                                                   DataLoopNode::ConnectionType::Inlet,
     332             :                                                                                   NodeInputManager::CompFluidStream::Primary,
     333             :                                                                                   ObjectIsNotParent);
     334             :             }
     335         219 :             PurchAir(PurchAirNum).MaxHeatSuppAirTemp = state.dataIPShortCut->rNumericArgs(1);
     336         219 :             PurchAir(PurchAirNum).MinCoolSuppAirTemp = state.dataIPShortCut->rNumericArgs(2);
     337         219 :             PurchAir(PurchAirNum).MaxHeatSuppAirHumRat = state.dataIPShortCut->rNumericArgs(3);
     338         219 :             PurchAir(PurchAirNum).MinCoolSuppAirHumRat = state.dataIPShortCut->rNumericArgs(4);
     339             : 
     340         219 :             if (Util::SameString(state.dataIPShortCut->cAlphaArgs(6), "NoLimit")) {
     341         217 :                 PurchAir(PurchAirNum).HeatingLimit = LimitType::NoLimit;
     342           2 :             } else if (Util::SameString(state.dataIPShortCut->cAlphaArgs(6), "LimitFlowRate")) {
     343           2 :                 if (state.dataIPShortCut->lNumericFieldBlanks(5)) {
     344           0 :                     PurchAir(PurchAirNum).HeatingLimit = LimitType::NoLimit;
     345             :                 } else {
     346           2 :                     PurchAir(PurchAirNum).HeatingLimit = LimitType::LimitFlowRate;
     347             :                 }
     348           0 :             } else if (Util::SameString(state.dataIPShortCut->cAlphaArgs(6), "LimitCapacity")) {
     349           0 :                 if (state.dataIPShortCut->lNumericFieldBlanks(6)) {
     350           0 :                     PurchAir(PurchAirNum).HeatingLimit = LimitType::NoLimit;
     351             :                 } else {
     352           0 :                     PurchAir(PurchAirNum).HeatingLimit = LimitType::LimitCapacity;
     353             :                 }
     354           0 :             } else if (Util::SameString(state.dataIPShortCut->cAlphaArgs(6), "LimitFlowRateAndCapacity")) {
     355           0 :                 if (state.dataIPShortCut->lNumericFieldBlanks(5) && state.dataIPShortCut->lNumericFieldBlanks(6)) {
     356           0 :                     PurchAir(PurchAirNum).HeatingLimit = LimitType::NoLimit;
     357           0 :                 } else if (state.dataIPShortCut->lNumericFieldBlanks(5)) {
     358           0 :                     PurchAir(PurchAirNum).HeatingLimit = LimitType::LimitCapacity;
     359           0 :                 } else if (state.dataIPShortCut->lNumericFieldBlanks(6)) {
     360           0 :                     PurchAir(PurchAirNum).HeatingLimit = LimitType::LimitFlowRate;
     361             :                 } else {
     362           0 :                     PurchAir(PurchAirNum).HeatingLimit = LimitType::LimitFlowRateAndCapacity;
     363             :                 }
     364             :             } else {
     365           0 :                 ShowSevereError(state, format("{}{}=\"{} invalid data", RoutineName, cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
     366           0 :                 ShowContinueError(state,
     367           0 :                                   format("Invalid-entry {}=\"{}\".", state.dataIPShortCut->cAlphaFieldNames(6), state.dataIPShortCut->cAlphaArgs(6)));
     368           0 :                 ShowContinueError(state, "Valid entries are NoLimit, LimitFlowRate, LimitCapacity, or LimitFlowRateAndCapacity");
     369           0 :                 ErrorsFound = true;
     370             :             }
     371         219 :             PurchAir(PurchAirNum).MaxHeatVolFlowRate = state.dataIPShortCut->rNumericArgs(5);
     372         219 :             PurchAir(PurchAirNum).MaxHeatSensCap = state.dataIPShortCut->rNumericArgs(6);
     373             : 
     374         219 :             if (Util::SameString(state.dataIPShortCut->cAlphaArgs(7), "NoLimit")) {
     375         215 :                 PurchAir(PurchAirNum).CoolingLimit = LimitType::NoLimit;
     376           4 :             } else if (Util::SameString(state.dataIPShortCut->cAlphaArgs(7), "LimitFlowRate")) {
     377           4 :                 if (state.dataIPShortCut->lNumericFieldBlanks(7)) {
     378           0 :                     PurchAir(PurchAirNum).CoolingLimit = LimitType::NoLimit;
     379             :                 } else {
     380           4 :                     PurchAir(PurchAirNum).CoolingLimit = LimitType::LimitFlowRate;
     381             :                 }
     382           0 :             } else if (Util::SameString(state.dataIPShortCut->cAlphaArgs(7), "LimitCapacity")) {
     383           0 :                 if (state.dataIPShortCut->lNumericFieldBlanks(8)) {
     384           0 :                     PurchAir(PurchAirNum).CoolingLimit = LimitType::NoLimit;
     385             :                 } else {
     386           0 :                     PurchAir(PurchAirNum).CoolingLimit = LimitType::LimitCapacity;
     387             :                 }
     388           0 :             } else if (Util::SameString(state.dataIPShortCut->cAlphaArgs(7), "LimitFlowRateAndCapacity")) {
     389           0 :                 if (state.dataIPShortCut->lNumericFieldBlanks(7) && state.dataIPShortCut->lNumericFieldBlanks(8)) {
     390           0 :                     PurchAir(PurchAirNum).CoolingLimit = LimitType::NoLimit;
     391           0 :                 } else if (state.dataIPShortCut->lNumericFieldBlanks(7)) {
     392           0 :                     PurchAir(PurchAirNum).CoolingLimit = LimitType::LimitCapacity;
     393           0 :                 } else if (state.dataIPShortCut->lNumericFieldBlanks(8)) {
     394           0 :                     PurchAir(PurchAirNum).CoolingLimit = LimitType::LimitFlowRate;
     395             :                 } else {
     396           0 :                     PurchAir(PurchAirNum).CoolingLimit = LimitType::LimitFlowRateAndCapacity;
     397             :                 }
     398             :             } else {
     399           0 :                 ShowSevereError(state, format("{}{}=\"{} invalid data", RoutineName, cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
     400           0 :                 ShowContinueError(state,
     401           0 :                                   format("Invalid-entry {}=\"{}\".", state.dataIPShortCut->cAlphaFieldNames(7), state.dataIPShortCut->cAlphaArgs(7)));
     402           0 :                 ShowContinueError(state, "Valid entries are NoLimit, LimitFlowRate, LimitCapacity, or LimitFlowRateAndCapacity");
     403           0 :                 ErrorsFound = true;
     404             :             }
     405         219 :             PurchAir(PurchAirNum).MaxCoolVolFlowRate = state.dataIPShortCut->rNumericArgs(7);
     406         219 :             PurchAir(PurchAirNum).MaxCoolTotCap = state.dataIPShortCut->rNumericArgs(8);
     407             : 
     408             :             // get optional heating availability schedule
     409         219 :             PurchAir(PurchAirNum).HeatSched = state.dataIPShortCut->cAlphaArgs(8);
     410         219 :             if (state.dataIPShortCut->lAlphaFieldBlanks(8)) {
     411         218 :                 PurchAir(PurchAirNum).HeatSchedPtr = ScheduleManager::ScheduleAlwaysOn;
     412             :             } else {
     413           1 :                 PurchAir(PurchAirNum).HeatSchedPtr = GetScheduleIndex(state, state.dataIPShortCut->cAlphaArgs(8));
     414           1 :                 if (PurchAir(PurchAirNum).HeatSchedPtr == 0) {
     415           0 :                     ShowSevereError(state, format("{}{}=\"{} invalid data", RoutineName, cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
     416           0 :                     ShowContinueError(
     417             :                         state,
     418           0 :                         format("Invalid-not found {}=\"{}\".", state.dataIPShortCut->cAlphaFieldNames(8), state.dataIPShortCut->cAlphaArgs(8)));
     419           0 :                     ErrorsFound = true;
     420             :                 }
     421             :             }
     422             :             // get optional cooling availability schedule
     423         219 :             PurchAir(PurchAirNum).CoolSched = state.dataIPShortCut->cAlphaArgs(9);
     424         219 :             if (state.dataIPShortCut->lAlphaFieldBlanks(9)) {
     425         218 :                 PurchAir(PurchAirNum).CoolSchedPtr = ScheduleManager::ScheduleAlwaysOn;
     426             :             } else {
     427           1 :                 PurchAir(PurchAirNum).CoolSchedPtr = GetScheduleIndex(state, state.dataIPShortCut->cAlphaArgs(9));
     428           1 :                 if (PurchAir(PurchAirNum).CoolSchedPtr == 0) {
     429           0 :                     ShowSevereError(state, format("{}{}=\"{} invalid data", RoutineName, cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
     430           0 :                     ShowContinueError(
     431             :                         state,
     432           0 :                         format("Invalid-not found {}=\"{}\".", state.dataIPShortCut->cAlphaFieldNames(9), state.dataIPShortCut->cAlphaArgs(9)));
     433           0 :                     ErrorsFound = true;
     434             :                 }
     435             :             }
     436             :             // get Dehumidification control type
     437         219 :             if (Util::SameString(state.dataIPShortCut->cAlphaArgs(10), "None")) {
     438           1 :                 PurchAir(PurchAirNum).DehumidCtrlType = HumControl::None;
     439         218 :             } else if (Util::SameString(state.dataIPShortCut->cAlphaArgs(10), "ConstantSensibleHeatRatio")) {
     440          25 :                 PurchAir(PurchAirNum).DehumidCtrlType = HumControl::ConstantSensibleHeatRatio;
     441         193 :             } else if (Util::SameString(state.dataIPShortCut->cAlphaArgs(10), "Humidistat")) {
     442           6 :                 PurchAir(PurchAirNum).DehumidCtrlType = HumControl::Humidistat;
     443         187 :             } else if (Util::SameString(state.dataIPShortCut->cAlphaArgs(10), "ConstantSupplyHumidityRatio")) {
     444         187 :                 PurchAir(PurchAirNum).DehumidCtrlType = HumControl::ConstantSupplyHumidityRatio;
     445             :             } else {
     446           0 :                 ShowSevereError(state, format("{}{}=\"{} invalid data", RoutineName, cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
     447           0 :                 ShowContinueError(
     448           0 :                     state, format("Invalid-entry {}=\"{}\".", state.dataIPShortCut->cAlphaFieldNames(10), state.dataIPShortCut->cAlphaArgs(10)));
     449           0 :                 ShowContinueError(state, "Valid entries are ConstantSensibleHeatRatio, Humidistat, or ConstantSupplyHumidityRatio");
     450           0 :                 ErrorsFound = true;
     451             :             }
     452         219 :             PurchAir(PurchAirNum).CoolSHR = state.dataIPShortCut->rNumericArgs(9);
     453             : 
     454             :             // get Humidification control type
     455         219 :             if (Util::SameString(state.dataIPShortCut->cAlphaArgs(11), "None")) {
     456          30 :                 PurchAir(PurchAirNum).HumidCtrlType = HumControl::None;
     457         189 :             } else if (Util::SameString(state.dataIPShortCut->cAlphaArgs(11), "Humidistat")) {
     458           2 :                 PurchAir(PurchAirNum).HumidCtrlType = HumControl::Humidistat;
     459         187 :             } else if (Util::SameString(state.dataIPShortCut->cAlphaArgs(11), "ConstantSupplyHumidityRatio")) {
     460         187 :                 PurchAir(PurchAirNum).HumidCtrlType = HumControl::ConstantSupplyHumidityRatio;
     461             :             } else {
     462           0 :                 ShowSevereError(state, format("{}{}=\"{} invalid data", RoutineName, cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
     463           0 :                 ShowContinueError(
     464           0 :                     state, format("Invalid-entry {}=\"{}\".", state.dataIPShortCut->cAlphaFieldNames(11), state.dataIPShortCut->cAlphaArgs(11)));
     465           0 :                 ShowContinueError(state, "Valid entries are None, Humidistat, or ConstantSupplyHumidityRatio");
     466           0 :                 ErrorsFound = true;
     467             :             }
     468             : 
     469             :             // get Design specification outdoor air object
     470         219 :             if (!state.dataIPShortCut->lAlphaFieldBlanks(12)) {
     471           4 :                 PurchAir(PurchAirNum).OARequirementsPtr = Util::FindItemInList(state.dataIPShortCut->cAlphaArgs(12), state.dataSize->OARequirements);
     472           4 :                 if (PurchAir(PurchAirNum).OARequirementsPtr == 0) {
     473           0 :                     ShowSevereError(state, format("{}{}=\"{} invalid data", RoutineName, cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
     474           0 :                     ShowContinueError(
     475             :                         state,
     476           0 :                         format("Invalid-not found{}=\"{}\".", state.dataIPShortCut->cAlphaFieldNames(12), state.dataIPShortCut->cAlphaArgs(12)));
     477           0 :                     ErrorsFound = true;
     478             :                 } else {
     479           4 :                     PurchAir(PurchAirNum).OutdoorAir = true;
     480             :                 }
     481             :             }
     482             : 
     483             :             // If outdoor air specified, then get Outdoor air inlet node and other outdoor air inputs
     484         219 :             if (PurchAir(PurchAirNum).OutdoorAir) {
     485           4 :                 if (state.dataIPShortCut->lAlphaFieldBlanks(13)) {
     486             :                     // If there is outdoor air and outdoor air inlet node is blank, then create one
     487           0 :                     if (len(state.dataIPShortCut->cAlphaArgs(1)) < Constant::MaxNameLength - 23) { // protect against long name leading to > 100 chars
     488           0 :                         state.dataIPShortCut->cAlphaArgs(13) = state.dataIPShortCut->cAlphaArgs(1) + " OUTDOOR AIR INLET NODE";
     489             :                     } else {
     490           0 :                         state.dataIPShortCut->cAlphaArgs(13) = state.dataIPShortCut->cAlphaArgs(1).substr(0, 75) + " OUTDOOR AIR INLET NODE";
     491             :                     }
     492           0 :                     if (state.dataGlobal->DisplayExtraWarnings) {
     493           0 :                         ShowWarningError(state,
     494           0 :                                          format("{}{}=\"{} blank field", RoutineName, cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
     495           0 :                         ShowContinueError(
     496             :                             state,
     497           0 :                             format("{} is blank, but there is outdoor air requested for this system.", state.dataIPShortCut->cAlphaFieldNames(13)));
     498           0 :                         ShowContinueError(state, format("Creating node name ={}", state.dataIPShortCut->cAlphaArgs(13)));
     499             :                     }
     500             :                 }
     501             :                 // Register OA node
     502           8 :                 PurchAir(PurchAirNum).OutdoorAirNodeNum = GetOnlySingleNode(state,
     503           4 :                                                                             state.dataIPShortCut->cAlphaArgs(13),
     504             :                                                                             ErrorsFound,
     505             :                                                                             DataLoopNode::ConnectionObjectType::ZoneHVACIdealLoadsAirSystem,
     506           4 :                                                                             state.dataIPShortCut->cAlphaArgs(1),
     507             :                                                                             DataLoopNode::NodeFluidType::Air,
     508             :                                                                             DataLoopNode::ConnectionType::Outlet,
     509             :                                                                             NodeInputManager::CompFluidStream::Primary,
     510             :                                                                             ObjectIsNotParent);
     511             :                 // Check if OA node is initialized in OutdoorAir:Node or OutdoorAir:Nodelist
     512           4 :                 CheckAndAddAirNodeNumber(state, PurchAir(PurchAirNum).OutdoorAirNodeNum, IsOANodeListed);
     513           4 :                 if ((!IsOANodeListed) && state.dataGlobal->DisplayExtraWarnings) {
     514           0 :                     ShowWarningError(state, format("{}{}=\"{} missing data", RoutineName, cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
     515           0 :                     ShowContinueError(
     516             :                         state,
     517           0 :                         format("{} does not appear in an OutdoorAir:NodeList or as an OutdoorAir:Node.", state.dataIPShortCut->cAlphaArgs(13)));
     518           0 :                     ShowContinueError(state, format("Adding OutdoorAir:Node={}", state.dataIPShortCut->cAlphaArgs(13)));
     519             :                 }
     520           4 :                 UniqueNodeError = false;
     521           4 :                 CheckUniqueNodeNames(state,
     522           4 :                                      state.dataIPShortCut->cAlphaFieldNames(13),
     523             :                                      UniqueNodeError,
     524           4 :                                      state.dataIPShortCut->cAlphaArgs(13),
     525           4 :                                      state.dataIPShortCut->cAlphaArgs(1));
     526           4 :                 if (UniqueNodeError) ErrorsFound = true;
     527             : 
     528             :                 // get Demand controlled ventilation type
     529           4 :                 if (Util::SameString(state.dataIPShortCut->cAlphaArgs(14), "None")) {
     530           3 :                     PurchAir(PurchAirNum).DCVType = DCV::None;
     531           1 :                 } else if (Util::SameString(state.dataIPShortCut->cAlphaArgs(14), "OccupancySchedule")) {
     532           1 :                     PurchAir(PurchAirNum).DCVType = DCV::OccupancySchedule;
     533           0 :                 } else if (Util::SameString(state.dataIPShortCut->cAlphaArgs(14), "CO2Setpoint")) {
     534           0 :                     if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
     535           0 :                         PurchAir(PurchAirNum).DCVType = DCV::CO2SetPoint;
     536             :                     } else {
     537           0 :                         PurchAir(PurchAirNum).DCVType = DCV::None;
     538           0 :                         ShowWarningError(state,
     539           0 :                                          format("{}{}=\"{} invalid data", RoutineName, cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
     540           0 :                         ShowContinueError(state,
     541           0 :                                           format("{}={} but CO2 simulation is not active.",
     542           0 :                                                  state.dataIPShortCut->cAlphaFieldNames(14),
     543           0 :                                                  state.dataIPShortCut->cAlphaArgs(14)));
     544           0 :                         ShowContinueError(state, format("Resetting {} to NoDCV", state.dataIPShortCut->cAlphaFieldNames(14)));
     545           0 :                         ShowContinueError(state,
     546             :                                           "To activate CO2 simulation, use ZoneAirContaminantBalance object and specify \"Carbon Dioxide "
     547             :                                           "Concentration\"=\"Yes\".");
     548             :                     }
     549             :                 } else {
     550           0 :                     ShowSevereError(state, format("{}{}=\"{} invalid data", RoutineName, cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
     551           0 :                     ShowContinueError(
     552           0 :                         state, format("Invalid-entry {}={}", state.dataIPShortCut->cAlphaFieldNames(14), state.dataIPShortCut->cAlphaArgs(14)));
     553           0 :                     ShowContinueError(state, "Valid entries are None, OccupancySchedule, or CO2Setpoint");
     554           0 :                     ErrorsFound = true;
     555             :                 }
     556             :                 // get Outdoor air economizer type
     557           4 :                 if (Util::SameString(state.dataIPShortCut->cAlphaArgs(15), "NoEconomizer")) {
     558           1 :                     PurchAir(PurchAirNum).EconomizerType = Econ::NoEconomizer;
     559           3 :                 } else if (Util::SameString(state.dataIPShortCut->cAlphaArgs(15), "DifferentialDryBulb")) {
     560           2 :                     PurchAir(PurchAirNum).EconomizerType = Econ::DifferentialDryBulb;
     561           1 :                 } else if (Util::SameString(state.dataIPShortCut->cAlphaArgs(15), "DifferentialEnthalpy")) {
     562           1 :                     PurchAir(PurchAirNum).EconomizerType = Econ::DifferentialEnthalpy;
     563             :                 } else {
     564           0 :                     ShowSevereError(state, format("{}{}=\"{} invalid data", RoutineName, cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
     565           0 :                     ShowContinueError(
     566           0 :                         state, format("Invalid-entry {}={}", state.dataIPShortCut->cAlphaFieldNames(15), state.dataIPShortCut->cAlphaArgs(15)));
     567           0 :                     ShowContinueError(state, "Valid entries are NoEconomizer, DifferentialDryBulb, or DifferentialEnthalpy");
     568           0 :                     ErrorsFound = true;
     569             :                 }
     570             :                 // get Outdoor air heat recovery type and effectiveness
     571           4 :                 if (Util::SameString(state.dataIPShortCut->cAlphaArgs(16), "None")) {
     572           2 :                     PurchAir(PurchAirNum).HtRecType = HeatRecovery::None;
     573           2 :                 } else if (Util::SameString(state.dataIPShortCut->cAlphaArgs(16), "Sensible")) {
     574           1 :                     PurchAir(PurchAirNum).HtRecType = HeatRecovery::Sensible;
     575           1 :                 } else if (Util::SameString(state.dataIPShortCut->cAlphaArgs(16), "Enthalpy")) {
     576           1 :                     PurchAir(PurchAirNum).HtRecType = HeatRecovery::Enthalpy;
     577             :                 } else {
     578           0 :                     ShowSevereError(state, format("{}{}=\"{} invalid data", RoutineName, cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
     579           0 :                     ShowContinueError(
     580           0 :                         state, format("Invalid-entry {}={}", state.dataIPShortCut->cAlphaFieldNames(16), state.dataIPShortCut->cAlphaArgs(16)));
     581           0 :                     ShowContinueError(state, "Valid entries are None, Sensible, or Enthalpy");
     582           0 :                     ErrorsFound = true;
     583             :                 }
     584             :             } else { // No outdoorair
     585         215 :                 PurchAir(PurchAirNum).DCVType = DCV::None;
     586         215 :                 PurchAir(PurchAirNum).EconomizerType = Econ::NoEconomizer;
     587         215 :                 PurchAir(PurchAirNum).HtRecType = HeatRecovery::None;
     588             :             }
     589             : 
     590         219 :             PurchAir(PurchAirNum).HtRecSenEff = state.dataIPShortCut->rNumericArgs(10);
     591         219 :             PurchAir(PurchAirNum).HtRecLatEff = state.dataIPShortCut->rNumericArgs(11);
     592             : 
     593        1310 :             for (CtrlZone = 1; CtrlZone <= state.dataGlobal->NumOfZones; ++CtrlZone) {
     594        1091 :                 if (!state.dataZoneEquip->ZoneEquipConfig(CtrlZone).IsControlled) continue;
     595        2103 :                 for (NodeNum = 1; NodeNum <= state.dataZoneEquip->ZoneEquipConfig(CtrlZone).NumInletNodes; ++NodeNum) {
     596        1040 :                     if (PurchAir(PurchAirNum).ZoneSupplyAirNodeNum == state.dataZoneEquip->ZoneEquipConfig(CtrlZone).InletNode(NodeNum)) {
     597         219 :                         PurchAir(PurchAirNum).ZonePtr = CtrlZone;
     598             :                     }
     599             :                 }
     600             :             }
     601             : 
     602         219 :             PurchAir(PurchAirNum).HVACSizingIndex = 0;
     603         219 :             if (!state.dataIPShortCut->lAlphaFieldBlanks(17)) {
     604           0 :                 PurchAir(PurchAirNum).HVACSizingIndex = Util::FindItemInList(state.dataIPShortCut->cAlphaArgs(17), state.dataSize->ZoneHVACSizing);
     605           0 :                 if (PurchAir(PurchAirNum).HVACSizingIndex == 0) {
     606           0 :                     ShowSevereError(state,
     607           0 :                                     format("{} = {} not found.", state.dataIPShortCut->cAlphaFieldNames(17), state.dataIPShortCut->cAlphaArgs(17)));
     608           0 :                     ShowContinueError(state, format("Occurs in {} = {}", cCurrentModuleObject, PurchAir(PurchAirNum).Name));
     609           0 :                     ErrorsFound = true;
     610             :                 }
     611             :             }
     612             : 
     613             :             // initialize the calculated and report values
     614         219 :             PurchAir(PurchAirNum).MaxHeatMassFlowRate = 0.0;
     615         219 :             PurchAir(PurchAirNum).MaxCoolMassFlowRate = 0.0;
     616         219 :             PurchAir(PurchAirNum).SenHeatEnergy = 0.0;
     617         219 :             PurchAir(PurchAirNum).LatHeatEnergy = 0.0;
     618         219 :             PurchAir(PurchAirNum).TotHeatEnergy = 0.0;
     619         219 :             PurchAir(PurchAirNum).SenCoolEnergy = 0.0;
     620         219 :             PurchAir(PurchAirNum).LatCoolEnergy = 0.0;
     621         219 :             PurchAir(PurchAirNum).TotCoolEnergy = 0.0;
     622         219 :             PurchAir(PurchAirNum).ZoneSenHeatEnergy = 0.0;
     623         219 :             PurchAir(PurchAirNum).ZoneLatHeatEnergy = 0.0;
     624         219 :             PurchAir(PurchAirNum).ZoneTotHeatEnergy = 0.0;
     625         219 :             PurchAir(PurchAirNum).ZoneSenCoolEnergy = 0.0;
     626         219 :             PurchAir(PurchAirNum).ZoneLatCoolEnergy = 0.0;
     627         219 :             PurchAir(PurchAirNum).ZoneTotCoolEnergy = 0.0;
     628         219 :             PurchAir(PurchAirNum).OASenHeatEnergy = 0.0;
     629         219 :             PurchAir(PurchAirNum).OALatHeatEnergy = 0.0;
     630         219 :             PurchAir(PurchAirNum).OATotHeatEnergy = 0.0;
     631         219 :             PurchAir(PurchAirNum).OASenCoolEnergy = 0.0;
     632         219 :             PurchAir(PurchAirNum).OALatCoolEnergy = 0.0;
     633         219 :             PurchAir(PurchAirNum).OATotCoolEnergy = 0.0;
     634         219 :             PurchAir(PurchAirNum).HtRecSenHeatEnergy = 0.0;
     635         219 :             PurchAir(PurchAirNum).HtRecLatHeatEnergy = 0.0;
     636         219 :             PurchAir(PurchAirNum).HtRecTotHeatEnergy = 0.0;
     637         219 :             PurchAir(PurchAirNum).HtRecSenCoolEnergy = 0.0;
     638         219 :             PurchAir(PurchAirNum).HtRecLatCoolEnergy = 0.0;
     639         219 :             PurchAir(PurchAirNum).HtRecTotCoolEnergy = 0.0;
     640         219 :             PurchAir(PurchAirNum).SenHeatRate = 0.0;
     641         219 :             PurchAir(PurchAirNum).LatHeatRate = 0.0;
     642         219 :             PurchAir(PurchAirNum).TotHeatRate = 0.0;
     643         219 :             PurchAir(PurchAirNum).SenCoolRate = 0.0;
     644         219 :             PurchAir(PurchAirNum).LatCoolRate = 0.0;
     645         219 :             PurchAir(PurchAirNum).TotCoolRate = 0.0;
     646         219 :             PurchAir(PurchAirNum).ZoneSenHeatRate = 0.0;
     647         219 :             PurchAir(PurchAirNum).ZoneLatHeatRate = 0.0;
     648         219 :             PurchAir(PurchAirNum).ZoneTotHeatRate = 0.0;
     649         219 :             PurchAir(PurchAirNum).ZoneSenCoolRate = 0.0;
     650         219 :             PurchAir(PurchAirNum).ZoneLatCoolRate = 0.0;
     651         219 :             PurchAir(PurchAirNum).ZoneTotCoolRate = 0.0;
     652         219 :             PurchAir(PurchAirNum).OASenHeatRate = 0.0;
     653         219 :             PurchAir(PurchAirNum).OALatHeatRate = 0.0;
     654         219 :             PurchAir(PurchAirNum).OATotHeatRate = 0.0;
     655         219 :             PurchAir(PurchAirNum).OASenCoolRate = 0.0;
     656         219 :             PurchAir(PurchAirNum).OALatCoolRate = 0.0;
     657         219 :             PurchAir(PurchAirNum).OATotCoolRate = 0.0;
     658         219 :             PurchAir(PurchAirNum).HtRecSenHeatRate = 0.0;
     659         219 :             PurchAir(PurchAirNum).HtRecLatHeatRate = 0.0;
     660         219 :             PurchAir(PurchAirNum).HtRecTotHeatRate = 0.0;
     661         219 :             PurchAir(PurchAirNum).HtRecSenCoolRate = 0.0;
     662         219 :             PurchAir(PurchAirNum).HtRecLatCoolRate = 0.0;
     663         219 :             PurchAir(PurchAirNum).HtRecTotCoolRate = 0.0;
     664             : 
     665         219 :             PurchAir(PurchAirNum).OutdoorAirMassFlowRate = 0.0;
     666         219 :             PurchAir(PurchAirNum).OutdoorAirVolFlowRateStdRho = 0.0;
     667         219 :             PurchAir(PurchAirNum).SupplyAirMassFlowRate = 0.0;
     668         219 :             PurchAir(PurchAirNum).SupplyAirVolFlowRateStdRho = 0.0;
     669             :         }
     670          78 :         EndUniqueNodeCheck(state, cCurrentModuleObject);
     671             :     }
     672             : 
     673         485 :     for (PurchAirNum = 1; PurchAirNum <= state.dataPurchasedAirMgr->NumPurchAir; ++PurchAirNum) {
     674             : 
     675             :         // Setup Output variables
     676             :         //    energy variables
     677         438 :         SetupOutputVariable(state,
     678             :                             "Zone Ideal Loads Supply Air Sensible Heating Energy",
     679             :                             Constant::Units::J,
     680         219 :                             PurchAir(PurchAirNum).SenHeatEnergy,
     681             :                             OutputProcessor::TimeStepType::System,
     682             :                             OutputProcessor::StoreType::Sum,
     683         219 :                             PurchAir(PurchAirNum).Name);
     684         438 :         SetupOutputVariable(state,
     685             :                             "Zone Ideal Loads Supply Air Latent Heating Energy",
     686             :                             Constant::Units::J,
     687         219 :                             PurchAir(PurchAirNum).LatHeatEnergy,
     688             :                             OutputProcessor::TimeStepType::System,
     689             :                             OutputProcessor::StoreType::Sum,
     690         219 :                             PurchAir(PurchAirNum).Name);
     691         438 :         SetupOutputVariable(state,
     692             :                             "Zone Ideal Loads Supply Air Total Heating Energy",
     693             :                             Constant::Units::J,
     694         219 :                             PurchAir(PurchAirNum).TotHeatEnergy,
     695             :                             OutputProcessor::TimeStepType::System,
     696             :                             OutputProcessor::StoreType::Sum,
     697         219 :                             PurchAir(PurchAirNum).Name,
     698             :                             Constant::eResource::DistrictHeatingWater,
     699             :                             OutputProcessor::Group::HVAC,
     700             :                             OutputProcessor::EndUseCat::Heating);
     701         438 :         SetupOutputVariable(state,
     702             :                             "Zone Ideal Loads Supply Air Sensible Cooling Energy",
     703             :                             Constant::Units::J,
     704         219 :                             PurchAir(PurchAirNum).SenCoolEnergy,
     705             :                             OutputProcessor::TimeStepType::System,
     706             :                             OutputProcessor::StoreType::Sum,
     707         219 :                             PurchAir(PurchAirNum).Name);
     708         438 :         SetupOutputVariable(state,
     709             :                             "Zone Ideal Loads Supply Air Latent Cooling Energy",
     710             :                             Constant::Units::J,
     711         219 :                             PurchAir(PurchAirNum).LatCoolEnergy,
     712             :                             OutputProcessor::TimeStepType::System,
     713             :                             OutputProcessor::StoreType::Sum,
     714         219 :                             PurchAir(PurchAirNum).Name);
     715         438 :         SetupOutputVariable(state,
     716             :                             "Zone Ideal Loads Supply Air Total Cooling Energy",
     717             :                             Constant::Units::J,
     718         219 :                             PurchAir(PurchAirNum).TotCoolEnergy,
     719             :                             OutputProcessor::TimeStepType::System,
     720             :                             OutputProcessor::StoreType::Sum,
     721         219 :                             PurchAir(PurchAirNum).Name,
     722             :                             Constant::eResource::DistrictCooling,
     723             :                             OutputProcessor::Group::HVAC,
     724             :                             OutputProcessor::EndUseCat::Cooling);
     725         438 :         SetupOutputVariable(state,
     726             :                             "Zone Ideal Loads Zone Sensible Heating Energy",
     727             :                             Constant::Units::J,
     728         219 :                             PurchAir(PurchAirNum).ZoneSenHeatEnergy,
     729             :                             OutputProcessor::TimeStepType::System,
     730             :                             OutputProcessor::StoreType::Sum,
     731         219 :                             PurchAir(PurchAirNum).Name);
     732         438 :         SetupOutputVariable(state,
     733             :                             "Zone Ideal Loads Zone Latent Heating Energy",
     734             :                             Constant::Units::J,
     735         219 :                             PurchAir(PurchAirNum).ZoneLatHeatEnergy,
     736             :                             OutputProcessor::TimeStepType::System,
     737             :                             OutputProcessor::StoreType::Sum,
     738         219 :                             PurchAir(PurchAirNum).Name);
     739         438 :         SetupOutputVariable(state,
     740             :                             "Zone Ideal Loads Zone Total Heating Energy",
     741             :                             Constant::Units::J,
     742         219 :                             PurchAir(PurchAirNum).ZoneTotHeatEnergy,
     743             :                             OutputProcessor::TimeStepType::System,
     744             :                             OutputProcessor::StoreType::Sum,
     745         219 :                             PurchAir(PurchAirNum).Name);
     746         438 :         SetupOutputVariable(state,
     747             :                             "Zone Ideal Loads Zone Sensible Cooling Energy",
     748             :                             Constant::Units::J,
     749         219 :                             PurchAir(PurchAirNum).ZoneSenCoolEnergy,
     750             :                             OutputProcessor::TimeStepType::System,
     751             :                             OutputProcessor::StoreType::Sum,
     752         219 :                             PurchAir(PurchAirNum).Name);
     753         438 :         SetupOutputVariable(state,
     754             :                             "Zone Ideal Loads Zone Latent Cooling Energy",
     755             :                             Constant::Units::J,
     756         219 :                             PurchAir(PurchAirNum).ZoneLatCoolEnergy,
     757             :                             OutputProcessor::TimeStepType::System,
     758             :                             OutputProcessor::StoreType::Sum,
     759         219 :                             PurchAir(PurchAirNum).Name);
     760         438 :         SetupOutputVariable(state,
     761             :                             "Zone Ideal Loads Zone Total Cooling Energy",
     762             :                             Constant::Units::J,
     763         219 :                             PurchAir(PurchAirNum).ZoneTotCoolEnergy,
     764             :                             OutputProcessor::TimeStepType::System,
     765             :                             OutputProcessor::StoreType::Sum,
     766         219 :                             PurchAir(PurchAirNum).Name);
     767         438 :         SetupOutputVariable(state,
     768             :                             "Zone Ideal Loads Outdoor Air Sensible Heating Energy",
     769             :                             Constant::Units::J,
     770         219 :                             PurchAir(PurchAirNum).OASenHeatEnergy,
     771             :                             OutputProcessor::TimeStepType::System,
     772             :                             OutputProcessor::StoreType::Sum,
     773         219 :                             PurchAir(PurchAirNum).Name);
     774         438 :         SetupOutputVariable(state,
     775             :                             "Zone Ideal Loads Outdoor Air Latent Heating Energy",
     776             :                             Constant::Units::J,
     777         219 :                             PurchAir(PurchAirNum).OALatHeatEnergy,
     778             :                             OutputProcessor::TimeStepType::System,
     779             :                             OutputProcessor::StoreType::Sum,
     780         219 :                             PurchAir(PurchAirNum).Name);
     781         438 :         SetupOutputVariable(state,
     782             :                             "Zone Ideal Loads Outdoor Air Total Heating Energy",
     783             :                             Constant::Units::J,
     784         219 :                             PurchAir(PurchAirNum).OATotHeatEnergy,
     785             :                             OutputProcessor::TimeStepType::System,
     786             :                             OutputProcessor::StoreType::Sum,
     787         219 :                             PurchAir(PurchAirNum).Name);
     788         438 :         SetupOutputVariable(state,
     789             :                             "Zone Ideal Loads Outdoor Air Sensible Cooling Energy",
     790             :                             Constant::Units::J,
     791         219 :                             PurchAir(PurchAirNum).OASenCoolEnergy,
     792             :                             OutputProcessor::TimeStepType::System,
     793             :                             OutputProcessor::StoreType::Sum,
     794         219 :                             PurchAir(PurchAirNum).Name);
     795         438 :         SetupOutputVariable(state,
     796             :                             "Zone Ideal Loads Outdoor Air Latent Cooling Energy",
     797             :                             Constant::Units::J,
     798         219 :                             PurchAir(PurchAirNum).OALatCoolEnergy,
     799             :                             OutputProcessor::TimeStepType::System,
     800             :                             OutputProcessor::StoreType::Sum,
     801         219 :                             PurchAir(PurchAirNum).Name);
     802         438 :         SetupOutputVariable(state,
     803             :                             "Zone Ideal Loads Outdoor Air Total Cooling Energy",
     804             :                             Constant::Units::J,
     805         219 :                             PurchAir(PurchAirNum).OATotCoolEnergy,
     806             :                             OutputProcessor::TimeStepType::System,
     807             :                             OutputProcessor::StoreType::Sum,
     808         219 :                             PurchAir(PurchAirNum).Name);
     809         438 :         SetupOutputVariable(state,
     810             :                             "Zone Ideal Loads Heat Recovery Sensible Heating Energy",
     811             :                             Constant::Units::J,
     812         219 :                             PurchAir(PurchAirNum).HtRecSenHeatEnergy,
     813             :                             OutputProcessor::TimeStepType::System,
     814             :                             OutputProcessor::StoreType::Sum,
     815         219 :                             PurchAir(PurchAirNum).Name);
     816         438 :         SetupOutputVariable(state,
     817             :                             "Zone Ideal Loads Heat Recovery Latent Heating Energy",
     818             :                             Constant::Units::J,
     819         219 :                             PurchAir(PurchAirNum).HtRecLatHeatEnergy,
     820             :                             OutputProcessor::TimeStepType::System,
     821             :                             OutputProcessor::StoreType::Sum,
     822         219 :                             PurchAir(PurchAirNum).Name);
     823         438 :         SetupOutputVariable(state,
     824             :                             "Zone Ideal Loads Heat Recovery Total Heating Energy",
     825             :                             Constant::Units::J,
     826         219 :                             PurchAir(PurchAirNum).HtRecTotHeatEnergy,
     827             :                             OutputProcessor::TimeStepType::System,
     828             :                             OutputProcessor::StoreType::Sum,
     829         219 :                             PurchAir(PurchAirNum).Name);
     830         438 :         SetupOutputVariable(state,
     831             :                             "Zone Ideal Loads Heat Recovery Sensible Cooling Energy",
     832             :                             Constant::Units::J,
     833         219 :                             PurchAir(PurchAirNum).HtRecSenCoolEnergy,
     834             :                             OutputProcessor::TimeStepType::System,
     835             :                             OutputProcessor::StoreType::Sum,
     836         219 :                             PurchAir(PurchAirNum).Name);
     837         438 :         SetupOutputVariable(state,
     838             :                             "Zone Ideal Loads Heat Recovery Latent Cooling Energy",
     839             :                             Constant::Units::J,
     840         219 :                             PurchAir(PurchAirNum).HtRecLatCoolEnergy,
     841             :                             OutputProcessor::TimeStepType::System,
     842             :                             OutputProcessor::StoreType::Sum,
     843         219 :                             PurchAir(PurchAirNum).Name);
     844         438 :         SetupOutputVariable(state,
     845             :                             "Zone Ideal Loads Heat Recovery Total Cooling Energy",
     846             :                             Constant::Units::J,
     847         219 :                             PurchAir(PurchAirNum).HtRecTotCoolEnergy,
     848             :                             OutputProcessor::TimeStepType::System,
     849             :                             OutputProcessor::StoreType::Sum,
     850         219 :                             PurchAir(PurchAirNum).Name);
     851             : 
     852             :         //    rate variables
     853         438 :         SetupOutputVariable(state,
     854             :                             "Zone Ideal Loads Supply Air Sensible Heating Rate",
     855             :                             Constant::Units::W,
     856         219 :                             PurchAir(PurchAirNum).SenHeatRate,
     857             :                             OutputProcessor::TimeStepType::System,
     858             :                             OutputProcessor::StoreType::Average,
     859         219 :                             PurchAir(PurchAirNum).Name);
     860         438 :         SetupOutputVariable(state,
     861             :                             "Zone Ideal Loads Supply Air Latent Heating Rate",
     862             :                             Constant::Units::W,
     863         219 :                             PurchAir(PurchAirNum).LatHeatRate,
     864             :                             OutputProcessor::TimeStepType::System,
     865             :                             OutputProcessor::StoreType::Average,
     866         219 :                             PurchAir(PurchAirNum).Name);
     867         438 :         SetupOutputVariable(state,
     868             :                             "Zone Ideal Loads Supply Air Total Heating Rate",
     869             :                             Constant::Units::W,
     870         219 :                             PurchAir(PurchAirNum).TotHeatRate,
     871             :                             OutputProcessor::TimeStepType::System,
     872             :                             OutputProcessor::StoreType::Average,
     873         219 :                             PurchAir(PurchAirNum).Name);
     874         438 :         SetupOutputVariable(state,
     875             :                             "Zone Ideal Loads Supply Air Sensible Cooling Rate",
     876             :                             Constant::Units::W,
     877         219 :                             PurchAir(PurchAirNum).SenCoolRate,
     878             :                             OutputProcessor::TimeStepType::System,
     879             :                             OutputProcessor::StoreType::Average,
     880         219 :                             PurchAir(PurchAirNum).Name);
     881         438 :         SetupOutputVariable(state,
     882             :                             "Zone Ideal Loads Supply Air Latent Cooling Rate",
     883             :                             Constant::Units::W,
     884         219 :                             PurchAir(PurchAirNum).LatCoolRate,
     885             :                             OutputProcessor::TimeStepType::System,
     886             :                             OutputProcessor::StoreType::Average,
     887         219 :                             PurchAir(PurchAirNum).Name);
     888         438 :         SetupOutputVariable(state,
     889             :                             "Zone Ideal Loads Supply Air Total Cooling Rate",
     890             :                             Constant::Units::W,
     891         219 :                             PurchAir(PurchAirNum).TotCoolRate,
     892             :                             OutputProcessor::TimeStepType::System,
     893             :                             OutputProcessor::StoreType::Average,
     894         219 :                             PurchAir(PurchAirNum).Name);
     895         438 :         SetupOutputVariable(state,
     896             :                             "Zone Ideal Loads Zone Sensible Heating Rate",
     897             :                             Constant::Units::W,
     898         219 :                             PurchAir(PurchAirNum).ZoneSenHeatRate,
     899             :                             OutputProcessor::TimeStepType::System,
     900             :                             OutputProcessor::StoreType::Average,
     901         219 :                             PurchAir(PurchAirNum).Name);
     902         438 :         SetupOutputVariable(state,
     903             :                             "Zone Ideal Loads Zone Latent Heating Rate",
     904             :                             Constant::Units::W,
     905         219 :                             PurchAir(PurchAirNum).ZoneLatHeatRate,
     906             :                             OutputProcessor::TimeStepType::System,
     907             :                             OutputProcessor::StoreType::Average,
     908         219 :                             PurchAir(PurchAirNum).Name);
     909         438 :         SetupOutputVariable(state,
     910             :                             "Zone Ideal Loads Zone Total Heating Rate",
     911             :                             Constant::Units::W,
     912         219 :                             PurchAir(PurchAirNum).ZoneTotHeatRate,
     913             :                             OutputProcessor::TimeStepType::System,
     914             :                             OutputProcessor::StoreType::Average,
     915         219 :                             PurchAir(PurchAirNum).Name);
     916         438 :         SetupOutputVariable(state,
     917             :                             "Zone Ideal Loads Zone Sensible Cooling Rate",
     918             :                             Constant::Units::W,
     919         219 :                             PurchAir(PurchAirNum).ZoneSenCoolRate,
     920             :                             OutputProcessor::TimeStepType::System,
     921             :                             OutputProcessor::StoreType::Average,
     922         219 :                             PurchAir(PurchAirNum).Name);
     923         438 :         SetupOutputVariable(state,
     924             :                             "Zone Ideal Loads Zone Latent Cooling Rate",
     925             :                             Constant::Units::W,
     926         219 :                             PurchAir(PurchAirNum).ZoneLatCoolRate,
     927             :                             OutputProcessor::TimeStepType::System,
     928             :                             OutputProcessor::StoreType::Average,
     929         219 :                             PurchAir(PurchAirNum).Name);
     930         438 :         SetupOutputVariable(state,
     931             :                             "Zone Ideal Loads Zone Total Cooling Rate",
     932             :                             Constant::Units::W,
     933         219 :                             PurchAir(PurchAirNum).ZoneTotCoolRate,
     934             :                             OutputProcessor::TimeStepType::System,
     935             :                             OutputProcessor::StoreType::Average,
     936         219 :                             PurchAir(PurchAirNum).Name);
     937         438 :         SetupOutputVariable(state,
     938             :                             "Zone Ideal Loads Outdoor Air Sensible Heating Rate",
     939             :                             Constant::Units::W,
     940         219 :                             PurchAir(PurchAirNum).OASenHeatRate,
     941             :                             OutputProcessor::TimeStepType::System,
     942             :                             OutputProcessor::StoreType::Average,
     943         219 :                             PurchAir(PurchAirNum).Name);
     944         438 :         SetupOutputVariable(state,
     945             :                             "Zone Ideal Loads Outdoor Air Latent Heating Rate",
     946             :                             Constant::Units::W,
     947         219 :                             PurchAir(PurchAirNum).OALatHeatRate,
     948             :                             OutputProcessor::TimeStepType::System,
     949             :                             OutputProcessor::StoreType::Average,
     950         219 :                             PurchAir(PurchAirNum).Name);
     951         438 :         SetupOutputVariable(state,
     952             :                             "Zone Ideal Loads Outdoor Air Total Heating Rate",
     953             :                             Constant::Units::W,
     954         219 :                             PurchAir(PurchAirNum).OATotHeatRate,
     955             :                             OutputProcessor::TimeStepType::System,
     956             :                             OutputProcessor::StoreType::Average,
     957         219 :                             PurchAir(PurchAirNum).Name);
     958         438 :         SetupOutputVariable(state,
     959             :                             "Zone Ideal Loads Outdoor Air Sensible Cooling Rate",
     960             :                             Constant::Units::W,
     961         219 :                             PurchAir(PurchAirNum).OASenCoolRate,
     962             :                             OutputProcessor::TimeStepType::System,
     963             :                             OutputProcessor::StoreType::Average,
     964         219 :                             PurchAir(PurchAirNum).Name);
     965         438 :         SetupOutputVariable(state,
     966             :                             "Zone Ideal Loads Outdoor Air Latent Cooling Rate",
     967             :                             Constant::Units::W,
     968         219 :                             PurchAir(PurchAirNum).OALatCoolRate,
     969             :                             OutputProcessor::TimeStepType::System,
     970             :                             OutputProcessor::StoreType::Average,
     971         219 :                             PurchAir(PurchAirNum).Name);
     972         438 :         SetupOutputVariable(state,
     973             :                             "Zone Ideal Loads Outdoor Air Total Cooling Rate",
     974             :                             Constant::Units::W,
     975         219 :                             PurchAir(PurchAirNum).OATotCoolRate,
     976             :                             OutputProcessor::TimeStepType::System,
     977             :                             OutputProcessor::StoreType::Average,
     978         219 :                             PurchAir(PurchAirNum).Name);
     979         438 :         SetupOutputVariable(state,
     980             :                             "Zone Ideal Loads Heat Recovery Sensible Heating Rate",
     981             :                             Constant::Units::W,
     982         219 :                             PurchAir(PurchAirNum).HtRecSenHeatRate,
     983             :                             OutputProcessor::TimeStepType::System,
     984             :                             OutputProcessor::StoreType::Average,
     985         219 :                             PurchAir(PurchAirNum).Name);
     986         438 :         SetupOutputVariable(state,
     987             :                             "Zone Ideal Loads Heat Recovery Latent Heating Rate",
     988             :                             Constant::Units::W,
     989         219 :                             PurchAir(PurchAirNum).HtRecLatHeatRate,
     990             :                             OutputProcessor::TimeStepType::System,
     991             :                             OutputProcessor::StoreType::Average,
     992         219 :                             PurchAir(PurchAirNum).Name);
     993         438 :         SetupOutputVariable(state,
     994             :                             "Zone Ideal Loads Heat Recovery Total Heating Rate",
     995             :                             Constant::Units::W,
     996         219 :                             PurchAir(PurchAirNum).HtRecTotHeatRate,
     997             :                             OutputProcessor::TimeStepType::System,
     998             :                             OutputProcessor::StoreType::Average,
     999         219 :                             PurchAir(PurchAirNum).Name);
    1000         438 :         SetupOutputVariable(state,
    1001             :                             "Zone Ideal Loads Heat Recovery Sensible Cooling Rate",
    1002             :                             Constant::Units::W,
    1003         219 :                             PurchAir(PurchAirNum).HtRecSenCoolRate,
    1004             :                             OutputProcessor::TimeStepType::System,
    1005             :                             OutputProcessor::StoreType::Average,
    1006         219 :                             PurchAir(PurchAirNum).Name);
    1007         438 :         SetupOutputVariable(state,
    1008             :                             "Zone Ideal Loads Heat Recovery Latent Cooling Rate",
    1009             :                             Constant::Units::W,
    1010         219 :                             PurchAir(PurchAirNum).HtRecLatCoolRate,
    1011             :                             OutputProcessor::TimeStepType::System,
    1012             :                             OutputProcessor::StoreType::Average,
    1013         219 :                             PurchAir(PurchAirNum).Name);
    1014         438 :         SetupOutputVariable(state,
    1015             :                             "Zone Ideal Loads Heat Recovery Total Cooling Rate",
    1016             :                             Constant::Units::W,
    1017         219 :                             PurchAir(PurchAirNum).HtRecTotCoolRate,
    1018             :                             OutputProcessor::TimeStepType::System,
    1019             :                             OutputProcessor::StoreType::Average,
    1020         219 :                             PurchAir(PurchAirNum).Name);
    1021             : 
    1022         438 :         SetupOutputVariable(state,
    1023             :                             "Zone Ideal Loads Economizer Active Time",
    1024             :                             Constant::Units::hr,
    1025         219 :                             PurchAir(PurchAirNum).TimeEconoActive,
    1026             :                             OutputProcessor::TimeStepType::System,
    1027             :                             OutputProcessor::StoreType::Sum,
    1028         219 :                             PurchAir(PurchAirNum).Name);
    1029         438 :         SetupOutputVariable(state,
    1030             :                             "Zone Ideal Loads Heat Recovery Active Time",
    1031             :                             Constant::Units::hr,
    1032         219 :                             PurchAir(PurchAirNum).TimeHtRecActive,
    1033             :                             OutputProcessor::TimeStepType::System,
    1034             :                             OutputProcessor::StoreType::Sum,
    1035         219 :                             PurchAir(PurchAirNum).Name);
    1036             : 
    1037         219 :         SetupOutputVariable(state,
    1038             :                             "Zone Ideal Loads Hybrid Ventilation Available Status",
    1039             :                             Constant::Units::None,
    1040         219 :                             (int &)PurchAir(PurchAirNum).availStatus,
    1041             :                             OutputProcessor::TimeStepType::System,
    1042             :                             OutputProcessor::StoreType::Average,
    1043         219 :                             PurchAir(PurchAirNum).Name);
    1044             : 
    1045             :         // air flows
    1046         438 :         SetupOutputVariable(state,
    1047             :                             "Zone Ideal Loads Outdoor Air Mass Flow Rate",
    1048             :                             Constant::Units::kg_s,
    1049         219 :                             PurchAir(PurchAirNum).OutdoorAirMassFlowRate,
    1050             :                             OutputProcessor::TimeStepType::System,
    1051             :                             OutputProcessor::StoreType::Average,
    1052         219 :                             PurchAir(PurchAirNum).Name);
    1053         438 :         SetupOutputVariable(state,
    1054             :                             "Zone Ideal Loads Outdoor Air Standard Density Volume Flow Rate",
    1055             :                             Constant::Units::m3_s,
    1056         219 :                             PurchAir(PurchAirNum).OutdoorAirVolFlowRateStdRho,
    1057             :                             OutputProcessor::TimeStepType::System,
    1058             :                             OutputProcessor::StoreType::Average,
    1059         219 :                             PurchAir(PurchAirNum).Name);
    1060         438 :         SetupOutputVariable(state,
    1061             :                             "Zone Ideal Loads Supply Air Mass Flow Rate",
    1062             :                             Constant::Units::kg_s,
    1063         219 :                             PurchAir(PurchAirNum).SupplyAirMassFlowRate,
    1064             :                             OutputProcessor::TimeStepType::System,
    1065             :                             OutputProcessor::StoreType::Average,
    1066         219 :                             PurchAir(PurchAirNum).Name);
    1067         438 :         SetupOutputVariable(state,
    1068             :                             "Zone Ideal Loads Supply Air Standard Density Volume Flow Rate",
    1069             :                             Constant::Units::m3_s,
    1070         219 :                             PurchAir(PurchAirNum).SupplyAirVolFlowRateStdRho,
    1071             :                             OutputProcessor::TimeStepType::System,
    1072             :                             OutputProcessor::StoreType::Average,
    1073         219 :                             PurchAir(PurchAirNum).Name);
    1074             : 
    1075             :         // Supply Air temperature
    1076         438 :         SetupOutputVariable(state,
    1077             :                             "Zone Ideal Loads Supply Air Temperature",
    1078             :                             Constant::Units::C,
    1079         219 :                             PurchAir(PurchAirNum).SupplyTemp,
    1080             :                             OutputProcessor::TimeStepType::System,
    1081             :                             OutputProcessor::StoreType::Average,
    1082         219 :                             PurchAir(PurchAirNum).Name);
    1083             :         // Supply Air Humidity Ratio
    1084         438 :         SetupOutputVariable(state,
    1085             :                             "Zone Ideal Loads Supply Air Humidity Ratio",
    1086             :                             Constant::Units::kgWater_kgDryAir,
    1087         219 :                             PurchAir(PurchAirNum).SupplyHumRat,
    1088             :                             OutputProcessor::TimeStepType::System,
    1089             :                             OutputProcessor::StoreType::Average,
    1090         219 :                             PurchAir(PurchAirNum).Name);
    1091             : 
    1092             :         // Mixed Air temperature
    1093         438 :         SetupOutputVariable(state,
    1094             :                             "Zone Ideal Loads Mixed Air Temperature",
    1095             :                             Constant::Units::C,
    1096         219 :                             PurchAir(PurchAirNum).MixedAirTemp,
    1097             :                             OutputProcessor::TimeStepType::System,
    1098             :                             OutputProcessor::StoreType::Average,
    1099         219 :                             PurchAir(PurchAirNum).Name);
    1100             :         // Mixed Air Humidity Ratio
    1101         438 :         SetupOutputVariable(state,
    1102             :                             "Zone Ideal Loads Mixed Air Humidity Ratio",
    1103             :                             Constant::Units::kgWater_kgDryAir,
    1104         219 :                             PurchAir(PurchAirNum).MixedAirHumRat,
    1105             :                             OutputProcessor::TimeStepType::System,
    1106             :                             OutputProcessor::StoreType::Average,
    1107         219 :                             PurchAir(PurchAirNum).Name);
    1108             : 
    1109         219 :         if (state.dataGlobal->AnyEnergyManagementSystemInModel) {
    1110          38 :             SetupEMSActuator(state,
    1111             :                              "Ideal Loads Air System",
    1112          19 :                              PurchAir(PurchAirNum).Name,
    1113             :                              "Air Mass Flow Rate",
    1114             :                              "[kg/s]",
    1115          19 :                              PurchAir(PurchAirNum).EMSOverrideMdotOn,
    1116          19 :                              PurchAir(PurchAirNum).EMSValueMassFlowRate);
    1117          38 :             SetupEMSActuator(state,
    1118             :                              "Ideal Loads Air System",
    1119          19 :                              PurchAir(PurchAirNum).Name,
    1120             :                              "Outdoor Air Mass Flow Rate",
    1121             :                              "[kg/s]",
    1122          19 :                              PurchAir(PurchAirNum).EMSOverrideOAMdotOn,
    1123          19 :                              PurchAir(PurchAirNum).EMSValueOAMassFlowRate);
    1124          38 :             SetupEMSActuator(state,
    1125             :                              "Ideal Loads Air System",
    1126          19 :                              PurchAir(PurchAirNum).Name,
    1127             :                              "Air Temperature",
    1128             :                              "[C]",
    1129          19 :                              PurchAir(PurchAirNum).EMSOverrideSupplyTempOn,
    1130          19 :                              PurchAir(PurchAirNum).EMSValueSupplyTemp);
    1131          38 :             SetupEMSActuator(state,
    1132             :                              "Ideal Loads Air System",
    1133          19 :                              PurchAir(PurchAirNum).Name,
    1134             :                              "Air Humidity Ratio",
    1135             :                              "[kgWater/kgDryAir]",
    1136          19 :                              PurchAir(PurchAirNum).EMSOverrideSupplyHumRatOn,
    1137          19 :                              PurchAir(PurchAirNum).EMSValueSupplyHumRat);
    1138             :         }
    1139             :     }
    1140             : 
    1141         266 :     if (ErrorsFound) {
    1142           0 :         ShowFatalError(state, format("{}Errors found in input. Preceding conditions cause termination.", RoutineName));
    1143             :     }
    1144         266 : }
    1145             : 
    1146     2076247 : void InitPurchasedAir(EnergyPlusData &state, int const PurchAirNum, int const ControlledZoneNum)
    1147             : {
    1148             : 
    1149             :     // SUBROUTINE INFORMATION:
    1150             :     //       AUTHOR         Russ Taylor
    1151             :     //       DATE WRITTEN   Nov 1997
    1152             : 
    1153             :     // PURPOSE OF THIS SUBROUTINE:
    1154             :     // Initialize the PurchAir data structure.
    1155             : 
    1156             :     // Using/Aliasing
    1157             :     using DataZoneEquipment::CheckZoneEquipmentList;
    1158             :     using General::FindNumberInList;
    1159             :     using ZonePlenum::GetReturnPlenumIndex;
    1160             :     using ZonePlenum::GetReturnPlenumName;
    1161             : 
    1162             :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    1163             :     int Loop;
    1164             :     bool UnitOn;        // simple checks for error
    1165             :     bool CoolOn;        // simple checks for error
    1166             :     bool HeatOn;        // simple checks for error
    1167             :     int SupplyNodeNum;  // Node number for ideal loads supply node
    1168             :     int ExhaustNodeNum; // Node number for ideal loads exhaust node
    1169             :     int NodeIndex;      // Array index of zone inlet or zone exhaust node that matches ideal loads node
    1170             :     bool UseReturnNode; // simple checks for error
    1171             : 
    1172     2076247 :     auto &PurchAir(state.dataPurchasedAirMgr->PurchAir);
    1173             : 
    1174             :     // Do the Begin Simulation initializations
    1175     2076247 :     if (state.dataPurchasedAirMgr->InitPurchasedAirMyOneTimeFlag) {
    1176          78 :         state.dataPurchasedAirMgr->InitPurchasedAirMyEnvrnFlag.allocate(state.dataPurchasedAirMgr->NumPurchAir);
    1177          78 :         state.dataPurchasedAirMgr->InitPurchasedAirMySizeFlag.allocate(state.dataPurchasedAirMgr->NumPurchAir);
    1178          78 :         state.dataPurchasedAirMgr->InitPurchasedAirOneTimeUnitInitsDone.allocate(state.dataPurchasedAirMgr->NumPurchAir);
    1179          78 :         state.dataPurchasedAirMgr->InitPurchasedAirMyEnvrnFlag = true;
    1180          78 :         state.dataPurchasedAirMgr->InitPurchasedAirMySizeFlag = true;
    1181          78 :         state.dataPurchasedAirMgr->InitPurchasedAirOneTimeUnitInitsDone = false;
    1182          78 :         state.dataPurchasedAirMgr->InitPurchasedAirMyOneTimeFlag = false;
    1183             :     }
    1184             : 
    1185             :     // need to check all units to see if they are on Zone Equipment List or issue warning
    1186     2076247 :     if (!state.dataPurchasedAirMgr->InitPurchasedAirZoneEquipmentListChecked && state.dataZoneEquip->ZoneEquipInputsFilled) {
    1187          78 :         state.dataPurchasedAirMgr->InitPurchasedAirZoneEquipmentListChecked = true;
    1188         297 :         for (Loop = 1; Loop <= state.dataPurchasedAirMgr->NumPurchAir; ++Loop) {
    1189             : 
    1190             :             // link with return plenum if used (i.e., PlenumExhaustAirNodeNum will be non-zero)
    1191         219 :             if (PurchAir(Loop).PlenumExhaustAirNodeNum > 0) {
    1192           5 :                 PurchAir(Loop).ReturnPlenumIndex = GetReturnPlenumIndex(state, PurchAir(Loop).PlenumExhaustAirNodeNum);
    1193           5 :                 if (PurchAir(Loop).ReturnPlenumIndex > 0) {
    1194           5 :                     GetReturnPlenumName(state, PurchAir(Loop).ReturnPlenumIndex, PurchAir(Loop).ReturnPlenumName);
    1195           5 :                     InitializePlenumArrays(state, Loop);
    1196             :                 } else {
    1197           0 :                     ShowSevereError(state,
    1198           0 :                                     format("InitPurchasedAir: {} = {} cannot find ZoneHVAC:ReturnPlenum.  It will not be simulated.",
    1199           0 :                                            PurchAir(Loop).cObjectName,
    1200           0 :                                            PurchAir(Loop).Name));
    1201             :                 }
    1202             :             }
    1203             : 
    1204         219 :             if (CheckZoneEquipmentList(state, PurchAir(Loop).cObjectName, PurchAir(Loop).Name)) continue;
    1205           0 :             ShowSevereError(state,
    1206           0 :                             format("InitPurchasedAir: {} = {} is not on any ZoneHVAC:EquipmentList.  It will not be simulated.",
    1207           0 :                                    PurchAir(Loop).cObjectName,
    1208           0 :                                    PurchAir(Loop).Name));
    1209             :         }
    1210             :     }
    1211             : 
    1212             :     // one time inits for each unit - links PurchAirNum with static input data from ControlledZoneNum and ActualZoneNum
    1213     2076247 :     if (!state.dataPurchasedAirMgr->InitPurchasedAirOneTimeUnitInitsDone(PurchAirNum)) {
    1214         219 :         state.dataPurchasedAirMgr->InitPurchasedAirOneTimeUnitInitsDone(PurchAirNum) = true;
    1215             : 
    1216             :         // Is the supply node really a zone inlet node?
    1217             :         // this check has to be done here because of SimPurchasedAir passing in ControlledZoneNum
    1218         219 :         SupplyNodeNum = PurchAir(PurchAirNum).ZoneSupplyAirNodeNum;
    1219         219 :         if (SupplyNodeNum > 0) {
    1220         219 :             NodeIndex = FindNumberInList(SupplyNodeNum,
    1221         219 :                                          state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).InletNode,
    1222         219 :                                          state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).NumInletNodes);
    1223         219 :             if (NodeIndex == 0) {
    1224           0 :                 ShowSevereError(state, format("InitPurchasedAir: In {} = {}", PurchAir(PurchAirNum).cObjectName, PurchAir(PurchAirNum).Name));
    1225           0 :                 ShowContinueError(state,
    1226           0 :                                   format("Zone Supply Air Node Name={} is not a zone inlet node.", state.dataLoopNodes->NodeID(SupplyNodeNum)));
    1227           0 :                 ShowContinueError(
    1228             :                     state,
    1229           0 :                     format("Check ZoneHVAC:EquipmentConnections for zone={}", state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).ZoneName));
    1230           0 :                 ShowFatalError(state, "Preceding condition causes termination.");
    1231             :             }
    1232             :         }
    1233             : 
    1234             :         // Set recirculation node number
    1235             :         // If exhaust node is specified, then recirculation is exhaust node, otherwise use zone return node
    1236             :         // this check has to be done here because of SimPurchasedAir passing in ControlledZoneNum
    1237         219 :         UseReturnNode = false;
    1238         219 :         if (PurchAir(PurchAirNum).ZoneExhaustAirNodeNum > 0) {
    1239           6 :             ExhaustNodeNum = PurchAir(PurchAirNum).ZoneExhaustAirNodeNum;
    1240           6 :             NodeIndex = FindNumberInList(ExhaustNodeNum,
    1241           6 :                                          state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).ExhaustNode,
    1242           6 :                                          state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).NumExhaustNodes);
    1243           6 :             if (NodeIndex == 0) {
    1244           0 :                 ShowSevereError(state, format("InitPurchasedAir: In {} = {}", PurchAir(PurchAirNum).cObjectName, PurchAir(PurchAirNum).Name));
    1245           0 :                 ShowContinueError(state,
    1246           0 :                                   format("Zone Exhaust Air Node Name={} is not a zone exhaust node.", state.dataLoopNodes->NodeID(ExhaustNodeNum)));
    1247           0 :                 ShowContinueError(
    1248             :                     state,
    1249           0 :                     format("Check ZoneHVAC:EquipmentConnections for zone={}", state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).ZoneName));
    1250           0 :                 ShowContinueError(state, "Zone return air node will be used for ideal loads recirculation air.");
    1251           0 :                 UseReturnNode = true;
    1252             :             } else {
    1253           6 :                 PurchAir(PurchAirNum).ZoneRecircAirNodeNum = PurchAir(PurchAirNum).ZoneExhaustAirNodeNum;
    1254             :             }
    1255             :         } else {
    1256         213 :             UseReturnNode = true;
    1257             :         }
    1258         219 :         if (UseReturnNode) {
    1259         213 :             if (state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).NumReturnNodes == 1) {
    1260         213 :                 PurchAir(PurchAirNum).ZoneRecircAirNodeNum = state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).ReturnNode(1);
    1261           0 :             } else if (state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).NumReturnNodes > 1) {
    1262           0 :                 ShowWarningError(state, format("InitPurchasedAir: In {} = {}", PurchAir(PurchAirNum).cObjectName, PurchAir(PurchAirNum).Name));
    1263           0 :                 ShowContinueError(state,
    1264             :                                   "No Zone Exhaust Air Node Name has been specified for this system and the zone has more than one Return Air Node.");
    1265           0 :                 ShowContinueError(state,
    1266           0 :                                   format("Using the first return air node ={}",
    1267           0 :                                          state.dataLoopNodes->NodeID(state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).ReturnNode(1))));
    1268             :             } else {
    1269           0 :                 ShowFatalError(state, format("InitPurchasedAir: In {} = {}", PurchAir(PurchAirNum).cObjectName, PurchAir(PurchAirNum).Name));
    1270           0 :                 ShowContinueError(
    1271             :                     state,
    1272             :                     " Invalid recirculation node. No exhaust or return node has been specified for this zone in ZoneHVAC:EquipmentConnections.");
    1273           0 :                 ShowFatalError(state, "Preceding condition causes termination.");
    1274             :             }
    1275             :         }
    1276             :         // If there is OA and economizer is active, then there must be a limit on cooling flow rate
    1277         219 :         if (PurchAir(PurchAirNum).OutdoorAir && (PurchAir(PurchAirNum).EconomizerType != Econ::NoEconomizer)) {
    1278           3 :             if ((PurchAir(PurchAirNum).CoolingLimit == LimitType::NoLimit) || (PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitCapacity)) {
    1279           0 :                 ShowSevereError(state, format("InitPurchasedAir: In {} = {}", PurchAir(PurchAirNum).cObjectName, PurchAir(PurchAirNum).Name));
    1280           0 :                 ShowContinueError(state, "There is outdoor air with economizer active but there is no limit on cooling air flow rate.");
    1281           0 :                 ShowContinueError(state,
    1282             :                                   "Cooling Limit must be set to LimitFlowRate or LimitFlowRateAndCapacity, and Maximum Cooling Air Flow Rate "
    1283             :                                   "must be set to a value or autosize.");
    1284           0 :                 ShowContinueError(state, "Simulation will proceed with no limit on outdoor air flow rate.");
    1285             :             }
    1286             :         }
    1287             :     }
    1288             : 
    1289     2076247 :     if (!state.dataGlobal->SysSizingCalc && state.dataPurchasedAirMgr->InitPurchasedAirMySizeFlag(PurchAirNum)) {
    1290             : 
    1291         219 :         SizePurchasedAir(state, PurchAirNum);
    1292             : 
    1293         219 :         state.dataPurchasedAirMgr->InitPurchasedAirMySizeFlag(PurchAirNum) = false;
    1294             :     }
    1295             : 
    1296             :     // Do the Begin Environment initializations
    1297     2076247 :     if (state.dataGlobal->BeginEnvrnFlag && state.dataPurchasedAirMgr->InitPurchasedAirMyEnvrnFlag(PurchAirNum)) {
    1298             : 
    1299        2258 :         if ((PurchAir(PurchAirNum).HeatingLimit == LimitType::LimitFlowRate) ||
    1300        1123 :             (PurchAir(PurchAirNum).HeatingLimit == LimitType::LimitFlowRateAndCapacity)) {
    1301          12 :             PurchAir(PurchAirNum).MaxHeatMassFlowRate = state.dataEnvrn->StdRhoAir * PurchAir(PurchAirNum).MaxHeatVolFlowRate;
    1302             :         } else {
    1303        1123 :             PurchAir(PurchAirNum).MaxHeatMassFlowRate = 0.0;
    1304             :         }
    1305        2246 :         if ((PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitFlowRate) ||
    1306        1111 :             (PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitFlowRateAndCapacity)) {
    1307          24 :             PurchAir(PurchAirNum).MaxCoolMassFlowRate = state.dataEnvrn->StdRhoAir * PurchAir(PurchAirNum).MaxCoolVolFlowRate;
    1308             :         } else {
    1309        1111 :             PurchAir(PurchAirNum).MaxCoolMassFlowRate = 0.0;
    1310             :         }
    1311        1135 :         state.dataPurchasedAirMgr->InitPurchasedAirMyEnvrnFlag(PurchAirNum) = false;
    1312             :     }
    1313             : 
    1314     2076247 :     if (!state.dataGlobal->BeginEnvrnFlag) {
    1315     2068326 :         state.dataPurchasedAirMgr->InitPurchasedAirMyEnvrnFlag(PurchAirNum) = true;
    1316             :     }
    1317             : 
    1318             :     // These initializations are done every iteration
    1319             :     // check that supply air temps can meet the zone thermostat setpoints
    1320     2076247 :     if (PurchAir(PurchAirNum).MinCoolSuppAirTemp > state.dataHeatBalFanSys->ZoneThermostatSetPointHi(ControlledZoneNum) &&
    1321     2076247 :         state.dataHeatBalFanSys->ZoneThermostatSetPointHi(ControlledZoneNum) != 0 && PurchAir(PurchAirNum).CoolingLimit == LimitType::NoLimit) {
    1322             :         // Check if the unit is scheduled off
    1323           0 :         UnitOn = true;
    1324             :         //        IF (PurchAir(PurchAirNum)%AvailSchedPtr > 0) THEN
    1325           0 :         if (GetCurrentScheduleValue(state, PurchAir(PurchAirNum).AvailSchedPtr) <= 0) {
    1326           0 :             UnitOn = false;
    1327             :         }
    1328             :         //        END IF
    1329             :         // Check if cooling available
    1330           0 :         CoolOn = true;
    1331             :         //        IF (PurchAir(PurchAirNum)%CoolSchedPtr > 0) THEN
    1332           0 :         if (GetCurrentScheduleValue(state, PurchAir(PurchAirNum).CoolSchedPtr) <= 0) {
    1333           0 :             CoolOn = false;
    1334             :         }
    1335             :         //        END IF
    1336           0 :         if (UnitOn && CoolOn) {
    1337           0 :             if (PurchAir(PurchAirNum).CoolErrIndex == 0) {
    1338           0 :                 ShowSevereError(state,
    1339           0 :                                 format("InitPurchasedAir: For {} = {} serving Zone {}",
    1340           0 :                                        PurchAir(PurchAirNum).cObjectName,
    1341           0 :                                        PurchAir(PurchAirNum).Name,
    1342           0 :                                        state.dataHeatBal->Zone(ControlledZoneNum).Name));
    1343           0 :                 ShowContinueError(state,
    1344           0 :                                   format("..the minimum supply air temperature for cooling [{:.2R}] is greater than the zone cooling mean air "
    1345             :                                          "temperature (MAT) setpoint [{:.2R}].",
    1346           0 :                                          PurchAir(PurchAirNum).MinCoolSuppAirTemp,
    1347           0 :                                          state.dataHeatBalFanSys->ZoneThermostatSetPointHi(ControlledZoneNum)));
    1348           0 :                 ShowContinueError(state, "..For operative and comfort thermostat controls, the MAT setpoint is computed.");
    1349           0 :                 ShowContinueError(state, "..This error may indicate that the mean radiant temperature or another comfort factor is too warm.");
    1350           0 :                 ShowContinueError(state, "Unit availability is nominally ON and Cooling availability is nominally ON.");
    1351           0 :                 ShowContinueError(state, format("Limit Cooling Capacity Type={}", cLimitType(PurchAir(PurchAirNum).CoolingLimit)));
    1352             :                 // could check for optemp control or comfort control here
    1353           0 :                 ShowContinueErrorTimeStamp(state, "");
    1354             :             }
    1355           0 :             ShowRecurringSevereErrorAtEnd(state,
    1356           0 :                                           "InitPurchasedAir: For " + PurchAir(PurchAirNum).cObjectName + " = " + PurchAir(PurchAirNum).Name +
    1357           0 :                                               " serving Zone " + state.dataHeatBal->Zone(ControlledZoneNum).Name +
    1358             :                                               ", the minimum supply air temperature for cooling error continues",
    1359           0 :                                           PurchAir(PurchAirNum).CoolErrIndex,
    1360           0 :                                           PurchAir(PurchAirNum).MinCoolSuppAirTemp,
    1361           0 :                                           PurchAir(PurchAirNum).MinCoolSuppAirTemp,
    1362             :                                           _,
    1363             :                                           "C",
    1364             :                                           "C");
    1365             :         }
    1366             :     }
    1367     2076247 :     if (PurchAir(PurchAirNum).MaxHeatSuppAirTemp < state.dataHeatBalFanSys->ZoneThermostatSetPointLo(ControlledZoneNum) &&
    1368     2076247 :         state.dataHeatBalFanSys->ZoneThermostatSetPointLo(ControlledZoneNum) != 0 && PurchAir(PurchAirNum).HeatingLimit == LimitType::NoLimit) {
    1369             :         // Check if the unit is scheduled off
    1370           0 :         UnitOn = true;
    1371             :         //        IF (PurchAir(PurchAirNum)%AvailSchedPtr > 0) THEN
    1372           0 :         if (GetCurrentScheduleValue(state, PurchAir(PurchAirNum).AvailSchedPtr) <= 0) {
    1373           0 :             UnitOn = false;
    1374             :         }
    1375             :         //        END IF
    1376             :         // Check if heating and cooling available
    1377           0 :         HeatOn = true;
    1378             :         //        IF (PurchAir(PurchAirNum)%HeatSchedPtr > 0) THEN
    1379           0 :         if (GetCurrentScheduleValue(state, PurchAir(PurchAirNum).HeatSchedPtr) <= 0) {
    1380           0 :             HeatOn = false;
    1381             :         }
    1382             :         //        END IF
    1383           0 :         if (UnitOn && HeatOn) {
    1384           0 :             if (PurchAir(PurchAirNum).HeatErrIndex == 0) {
    1385           0 :                 ShowSevereMessage(state,
    1386           0 :                                   format("InitPurchasedAir: For {} = {} serving Zone {}",
    1387           0 :                                          PurchAir(PurchAirNum).cObjectName,
    1388           0 :                                          PurchAir(PurchAirNum).Name,
    1389           0 :                                          state.dataHeatBal->Zone(ControlledZoneNum).Name));
    1390           0 :                 ShowContinueError(state,
    1391           0 :                                   format("..the maximum supply air temperature for heating [{:.2R}] is less than the zone mean air temperature "
    1392             :                                          "heating setpoint [{:.2R}].",
    1393           0 :                                          PurchAir(PurchAirNum).MaxHeatSuppAirTemp,
    1394           0 :                                          state.dataHeatBalFanSys->ZoneThermostatSetPointLo(ControlledZoneNum)));
    1395           0 :                 ShowContinueError(state, "..For operative and comfort thermostat controls, the MAT setpoint is computed.");
    1396           0 :                 ShowContinueError(state, "..This error may indicate that the mean radiant temperature or another comfort factor is too cold.");
    1397           0 :                 ShowContinueError(state, "Unit availability is nominally ON and Heating availability is nominally ON.");
    1398           0 :                 ShowContinueError(state, format("Limit Heating Capacity Type={}", cLimitType(PurchAir(PurchAirNum).HeatingLimit)));
    1399             :                 // could check for optemp control or comfort control here
    1400           0 :                 ShowContinueErrorTimeStamp(state, "");
    1401             :             }
    1402           0 :             ShowRecurringSevereErrorAtEnd(state,
    1403           0 :                                           "InitPurchasedAir: For " + PurchAir(PurchAirNum).cObjectName + " = " + PurchAir(PurchAirNum).Name +
    1404           0 :                                               " serving Zone " + state.dataHeatBal->Zone(ControlledZoneNum).Name +
    1405             :                                               ", maximum supply air temperature for heating error continues",
    1406           0 :                                           PurchAir(PurchAirNum).HeatErrIndex,
    1407           0 :                                           PurchAir(PurchAirNum).MaxHeatSuppAirTemp,
    1408           0 :                                           PurchAir(PurchAirNum).MaxHeatSuppAirTemp,
    1409             :                                           _,
    1410             :                                           "C",
    1411             :                                           "C");
    1412             :         }
    1413             :     }
    1414             :     //      IF (ErrorsFound .and. .not. WarmupFlag) THEN
    1415             :     //        CALL ShowFatalError(state, 'Preceding conditions cause termination.')
    1416             :     //      ENDIF
    1417     2076247 : }
    1418             : 
    1419         219 : void SizePurchasedAir(EnergyPlusData &state, int const PurchAirNum)
    1420             : {
    1421             : 
    1422             :     // SUBROUTINE INFORMATION:
    1423             :     //       AUTHOR         Fred Buhl
    1424             :     //       DATE WRITTEN   April 2003
    1425             :     //       MODIFIED       M. Witte, June 2011, add sizing for new capacity fields
    1426             :     //                      August 2013 Daeho Kang, add component sizing table entries
    1427             :     //       RE-ENGINEERED  na
    1428             : 
    1429             :     // PURPOSE OF THIS SUBROUTINE:
    1430             :     // This subroutine is for sizing Purchased Air Components for which flow rates have not been
    1431             :     // specified in the input.
    1432             : 
    1433             :     // METHODOLOGY EMPLOYED:
    1434             :     // Obtains flow rates from the zone sizing arrays.
    1435             : 
    1436             :     // Using/Aliasing
    1437             :     using namespace DataSizing;
    1438             :     using HVAC::CoolingCapacitySizing;
    1439             :     using HVAC::HeatingAirflowSizing;
    1440             :     using HVAC::HeatingCapacitySizing;
    1441             :     using Psychrometrics::CPCW;
    1442             :     using Psychrometrics::CPHW;
    1443             :     using Psychrometrics::PsyCpAirFnW;
    1444             :     using Psychrometrics::PsyHFnTdbW;
    1445             :     using Psychrometrics::RhoH2O;
    1446             : 
    1447             :     // SUBROUTINE PARAMETER DEFINITIONS:
    1448             :     static constexpr std::string_view RoutineName("SizePurchasedAir: "); // include trailing blank space
    1449             : 
    1450             :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    1451             :     bool IsAutoSize;               // Indicator to autosize
    1452             :     Real64 MaxHeatVolFlowRateDes;  // Autosized maximum heating air flow for reporting
    1453             :     Real64 MaxHeatVolFlowRateUser; // Hardsized maximum heating air flow for reporting
    1454             :     Real64 MaxCoolVolFlowRateDes;  // Autosized maximum cooling air flow for reporting
    1455             :     Real64 MaxCoolVolFlowRateUser; // Hardsized maximum cooling air flow for reporting
    1456             :     Real64 MaxHeatSensCapDes;      // Autosized maximum sensible heating capacity for reporting
    1457             :     Real64 MaxHeatSensCapUser;     // Hardsized maximum sensible heating capacity for reporting
    1458             :     Real64 MaxCoolTotCapDes;       // Autosized maximum sensible cooling capacity for reporting
    1459             :     Real64 MaxCoolTotCapUser;      // Hardsized maximum sensible cooling capacity for reporting
    1460         219 :     std::string CompName;          // component name
    1461         219 :     std::string CompType;          // component type
    1462         219 :     std::string SizingString;      // input field sizing description (e.g., Nominal Capacity)
    1463             :     Real64 TempSize;               // autosized value of coil input field
    1464         219 :     int FieldNum = 2;              // IDD numeric field number where input field description is found
    1465             :     int SizingMethod;       // Integer representation of sizing method name (e.g., CoolingAirflowSizing, HeatingAirflowSizing, CoolingCapacitySizing,
    1466             :                             // HeatingCapacitySizing, etc.)
    1467             :     bool PrintFlag;         // TRUE when sizing information is reported in the eio file
    1468             :     int zoneHVACIndex;      // index of zoneHVAC equipment sizing specification
    1469         219 :     int SAFMethod(0);       // supply air flow rate sizing method (SupplyAirFlowRate, FlowPerFloorArea, FractionOfAutosizedCoolingAirflow,
    1470             :                             // FractionOfAutosizedHeatingAirflow ...)
    1471         219 :     int CapSizingMethod(0); // capacity sizing methods (HeatingDesignCapacity, CapacityPerFloorArea, FractionOfAutosizedCoolingCapacity, and
    1472             :                             // FractionOfAutosizedHeatingCapacity )
    1473         219 :     Real64 CoolingAirVolFlowDes(0.0); // cooling supply air flow rate
    1474         219 :     Real64 HeatingAirVolFlowDes(0.0); // heating supply air flow rate
    1475             : 
    1476         219 :     auto &PurchAir(state.dataPurchasedAirMgr->PurchAir);
    1477         219 :     auto &ZoneEqSizing(state.dataSize->ZoneEqSizing);
    1478             : 
    1479         219 :     IsAutoSize = false;
    1480         219 :     MaxHeatVolFlowRateDes = 0.0;
    1481         219 :     MaxHeatVolFlowRateUser = 0.0;
    1482         219 :     MaxCoolVolFlowRateDes = 0.0;
    1483         219 :     MaxCoolVolFlowRateUser = 0.0;
    1484         219 :     MaxHeatSensCapDes = 0.0;
    1485         219 :     MaxHeatSensCapUser = 0.0;
    1486         219 :     MaxCoolTotCapDes = 0.0;
    1487         219 :     MaxCoolTotCapUser = 0.0;
    1488             : 
    1489         219 :     state.dataSize->ZoneHeatingOnlyFan = false;
    1490         219 :     state.dataSize->ZoneCoolingOnlyFan = false;
    1491         219 :     CompType = PurchAir(PurchAirNum).cObjectName;
    1492         219 :     CompName = PurchAir(PurchAirNum).Name;
    1493         219 :     bool ErrorsFound = false;
    1494             : 
    1495         219 :     if (state.dataSize->CurZoneEqNum > 0) {
    1496         219 :         if (PurchAir(PurchAirNum).HVACSizingIndex > 0) {
    1497           0 :             state.dataSize->DataZoneNumber = PurchAir(PurchAirNum).ZonePtr;
    1498           0 :             zoneHVACIndex = PurchAir(PurchAirNum).HVACSizingIndex;
    1499             : 
    1500           0 :             FieldNum = 5; // N5 , \field Maximum Heating Air Flow Rate
    1501           0 :             PrintFlag = true;
    1502           0 :             SizingString = state.dataPurchasedAirMgr->PurchAirNumericFields(PurchAirNum).FieldNames(FieldNum) + " [m3/s]";
    1503           0 :             if (state.dataSize->ZoneHVACSizing(zoneHVACIndex).HeatingSAFMethod > 0) {
    1504           0 :                 SizingMethod = HeatingAirflowSizing;
    1505           0 :                 state.dataSize->ZoneHeatingOnlyFan = true;
    1506           0 :                 SAFMethod = state.dataSize->ZoneHVACSizing(zoneHVACIndex).HeatingSAFMethod;
    1507           0 :                 ZoneEqSizing(state.dataSize->CurZoneEqNum).SizingMethod(SizingMethod) = SAFMethod;
    1508           0 :                 if (SAFMethod == SupplyAirFlowRate || SAFMethod == FlowPerFloorArea || SAFMethod == FractionOfAutosizedHeatingAirflow) {
    1509           0 :                     if (SAFMethod == SupplyAirFlowRate) {
    1510           0 :                         if ((state.dataSize->ZoneHVACSizing(zoneHVACIndex).MaxHeatAirVolFlow == AutoSize) &&
    1511           0 :                             ((PurchAir(PurchAirNum).HeatingLimit == LimitType::LimitFlowRate) ||
    1512           0 :                              (PurchAir(PurchAirNum).HeatingLimit == LimitType::LimitFlowRateAndCapacity))) {
    1513           0 :                             TempSize = state.dataSize->ZoneHVACSizing(zoneHVACIndex).MaxHeatAirVolFlow;
    1514           0 :                             HeatingAirFlowSizer sizingHeatingAirFlow;
    1515           0 :                             sizingHeatingAirFlow.overrideSizingString(SizingString);
    1516             :                             // sizingHeatingAirFlow.setHVACSizingIndexData(FanCoil(FanCoilNum).HVACSizingIndex);
    1517           0 :                             sizingHeatingAirFlow.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
    1518           0 :                             HeatingAirVolFlowDes = sizingHeatingAirFlow.size(state, TempSize, ErrorsFound);
    1519           0 :                         } else {
    1520           0 :                             if (state.dataSize->ZoneHVACSizing(zoneHVACIndex).MaxHeatAirVolFlow > 0.0) {
    1521           0 :                                 HeatingAirFlowSizer sizingHeatingAirFlow;
    1522           0 :                                 sizingHeatingAirFlow.overrideSizingString(SizingString);
    1523             :                                 // sizingHeatingAirFlow.setHVACSizingIndexData(FanCoil(FanCoilNum).HVACSizingIndex);
    1524           0 :                                 sizingHeatingAirFlow.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
    1525             :                                 HeatingAirVolFlowDes =
    1526           0 :                                     sizingHeatingAirFlow.size(state, state.dataSize->ZoneHVACSizing(zoneHVACIndex).MaxHeatAirVolFlow, ErrorsFound);
    1527           0 :                             }
    1528             :                         }
    1529           0 :                     } else if (SAFMethod == FlowPerFloorArea) {
    1530           0 :                         ZoneEqSizing(state.dataSize->CurZoneEqNum).SystemAirFlow = true;
    1531           0 :                         ZoneEqSizing(state.dataSize->CurZoneEqNum).AirVolFlow = state.dataSize->ZoneHVACSizing(zoneHVACIndex).MaxHeatAirVolFlow *
    1532           0 :                                                                                 state.dataHeatBal->Zone(state.dataSize->DataZoneNumber).FloorArea;
    1533           0 :                         TempSize = ZoneEqSizing(state.dataSize->CurZoneEqNum).AirVolFlow;
    1534           0 :                         state.dataSize->DataScalableSizingON = true;
    1535           0 :                         HeatingAirFlowSizer sizingHeatingAirFlow;
    1536           0 :                         sizingHeatingAirFlow.overrideSizingString(SizingString);
    1537             :                         // sizingHeatingAirFlow.setHVACSizingIndexData(FanCoil(FanCoilNum).HVACSizingIndex);
    1538           0 :                         sizingHeatingAirFlow.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
    1539           0 :                         HeatingAirVolFlowDes = sizingHeatingAirFlow.size(state, TempSize, ErrorsFound);
    1540           0 :                     } else if (SAFMethod == FractionOfAutosizedHeatingAirflow) {
    1541           0 :                         state.dataSize->DataFracOfAutosizedHeatingAirflow = state.dataSize->ZoneHVACSizing(zoneHVACIndex).MaxHeatAirVolFlow;
    1542           0 :                         if ((state.dataSize->ZoneHVACSizing(zoneHVACIndex).MaxHeatAirVolFlow == AutoSize) &&
    1543           0 :                             ((PurchAir(PurchAirNum).HeatingLimit == LimitType::LimitFlowRate) ||
    1544           0 :                              (PurchAir(PurchAirNum).HeatingLimit == LimitType::LimitFlowRateAndCapacity))) {
    1545           0 :                             TempSize = AutoSize;
    1546           0 :                             state.dataSize->DataScalableSizingON = true;
    1547           0 :                             HeatingAirFlowSizer sizingHeatingAirFlow;
    1548           0 :                             sizingHeatingAirFlow.overrideSizingString(SizingString);
    1549             :                             // sizingHeatingAirFlow.setHVACSizingIndexData(FanCoil(FanCoilNum).HVACSizingIndex);
    1550           0 :                             sizingHeatingAirFlow.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
    1551           0 :                             HeatingAirVolFlowDes = sizingHeatingAirFlow.size(state, TempSize, ErrorsFound);
    1552           0 :                         }
    1553             : 
    1554             :                     } else {
    1555             :                         // Invalid sizing method
    1556             :                     }
    1557           0 :                 } else if (SAFMethod == FlowPerHeatingCapacity) {
    1558           0 :                     SizingMethod = HeatingCapacitySizing;
    1559           0 :                     TempSize = AutoSize;
    1560           0 :                     PrintFlag = false;
    1561           0 :                     if ((state.dataSize->ZoneHVACSizing(zoneHVACIndex).MaxHeatAirVolFlow == AutoSize) &&
    1562           0 :                         ((PurchAir(PurchAirNum).HeatingLimit == LimitType::LimitFlowRate) ||
    1563           0 :                          (PurchAir(PurchAirNum).HeatingLimit == LimitType::LimitFlowRateAndCapacity))) {
    1564           0 :                         TempSize = AutoSize;
    1565           0 :                         state.dataSize->DataScalableSizingON = true;
    1566           0 :                         HeatingCapacitySizer sizerHeatingCapacity;
    1567           0 :                         sizerHeatingCapacity.overrideSizingString(SizingString);
    1568           0 :                         sizerHeatingCapacity.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
    1569           0 :                         state.dataSize->DataAutosizedHeatingCapacity = sizerHeatingCapacity.size(state, TempSize, ErrorsFound);
    1570           0 :                         state.dataSize->DataFlowPerHeatingCapacity = state.dataSize->ZoneHVACSizing(zoneHVACIndex).MaxHeatAirVolFlow;
    1571           0 :                         SizingMethod = HeatingAirflowSizing;
    1572           0 :                         PrintFlag = true;
    1573           0 :                         TempSize = AutoSize;
    1574           0 :                         HeatingAirFlowSizer sizingHeatingAirFlow;
    1575           0 :                         sizingHeatingAirFlow.overrideSizingString(SizingString);
    1576             :                         // sizingHeatingAirFlow.setHVACSizingIndexData(FanCoil(FanCoilNum).HVACSizingIndex);
    1577           0 :                         sizingHeatingAirFlow.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
    1578           0 :                         HeatingAirVolFlowDes = sizingHeatingAirFlow.size(state, TempSize, ErrorsFound);
    1579           0 :                     }
    1580             :                 }
    1581           0 :                 MaxHeatVolFlowRateDes = max(0.0, HeatingAirVolFlowDes);
    1582           0 :                 PurchAir(PurchAirNum).MaxHeatVolFlowRate = MaxHeatVolFlowRateDes;
    1583           0 :                 state.dataSize->ZoneHeatingOnlyFan = false;
    1584             : 
    1585           0 :                 CapSizingMethod = state.dataSize->ZoneHVACSizing(zoneHVACIndex).HeatingCapMethod;
    1586           0 :                 ZoneEqSizing(state.dataSize->CurZoneEqNum).CapSizingMethod = CapSizingMethod;
    1587           0 :                 if (CapSizingMethod == HeatingDesignCapacity || CapSizingMethod == CapacityPerFloorArea ||
    1588           0 :                     CapSizingMethod == FractionOfAutosizedHeatingCapacity) {
    1589           0 :                     if (CapSizingMethod == HeatingDesignCapacity) {
    1590           0 :                         if (state.dataSize->ZoneHVACSizing(zoneHVACIndex).ScaledHeatingCapacity > 0.0) {
    1591           0 :                             ZoneEqSizing(state.dataSize->CurZoneEqNum).HeatingCapacity = true;
    1592           0 :                             ZoneEqSizing(state.dataSize->CurZoneEqNum).DesHeatingLoad =
    1593           0 :                                 state.dataSize->ZoneHVACSizing(zoneHVACIndex).ScaledHeatingCapacity;
    1594             :                         }
    1595           0 :                         TempSize = state.dataSize->ZoneHVACSizing(zoneHVACIndex).ScaledHeatingCapacity;
    1596           0 :                     } else if (CapSizingMethod == CapacityPerFloorArea) {
    1597           0 :                         ZoneEqSizing(state.dataSize->CurZoneEqNum).HeatingCapacity = true;
    1598           0 :                         ZoneEqSizing(state.dataSize->CurZoneEqNum).DesHeatingLoad =
    1599           0 :                             state.dataSize->ZoneHVACSizing(zoneHVACIndex).ScaledHeatingCapacity *
    1600           0 :                             state.dataHeatBal->Zone(state.dataSize->DataZoneNumber).FloorArea;
    1601           0 :                         state.dataSize->DataScalableSizingON = true;
    1602           0 :                     } else if (CapSizingMethod == FractionOfAutosizedHeatingCapacity) {
    1603           0 :                         state.dataSize->DataFracOfAutosizedHeatingCapacity = state.dataSize->ZoneHVACSizing(zoneHVACIndex).ScaledHeatingCapacity;
    1604           0 :                         TempSize = AutoSize;
    1605             :                     }
    1606             :                 }
    1607           0 :                 SizingMethod = HeatingCapacitySizing;
    1608           0 :                 SizingString = "";
    1609           0 :                 state.dataSize->ZoneHeatingOnlyFan = true;
    1610           0 :                 PrintFlag = false;
    1611           0 :                 HeatingCapacitySizer sizerHeatingCapacity;
    1612           0 :                 sizerHeatingCapacity.overrideSizingString(SizingString);
    1613           0 :                 sizerHeatingCapacity.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
    1614           0 :                 MaxHeatSensCapDes = sizerHeatingCapacity.size(state, TempSize, ErrorsFound);
    1615           0 :                 state.dataSize->ZoneHeatingOnlyFan = false;
    1616           0 :                 if (MaxHeatSensCapDes < HVAC::SmallLoad) {
    1617           0 :                     MaxHeatSensCapDes = 0.0;
    1618             :                 }
    1619           0 :                 if (IsAutoSize) {
    1620           0 :                     PurchAir(PurchAirNum).MaxHeatSensCap = MaxHeatSensCapDes;
    1621           0 :                     BaseSizer::reportSizerOutput(state,
    1622           0 :                                                  PurchAir(PurchAirNum).cObjectName,
    1623           0 :                                                  PurchAir(PurchAirNum).Name,
    1624             :                                                  "Design Size Maximum Sensible Heating Capacity [W]",
    1625             :                                                  MaxHeatSensCapDes);
    1626             :                     // If there is OA, check if sizing calcs have OA>0, throw warning if not
    1627           0 :                     if ((PurchAir(PurchAirNum).OutdoorAir) && (state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).MinOA == 0.0)) {
    1628           0 :                         ShowWarningError(state,
    1629           0 :                                          format("InitPurchasedAir: In {} = {}", PurchAir(PurchAirNum).cObjectName, PurchAir(PurchAirNum).Name));
    1630           0 :                         ShowContinueError(state, "There is outdoor air specified in this object, but the design outdoor air flow rate for this ");
    1631           0 :                         ShowContinueError(state, "zone is zero. The Maximum Sensible Heating Capacity will be autosized for zero outdoor air flow. ");
    1632           0 :                         ShowContinueError(state,
    1633           0 :                                           format("Check the outdoor air specifications in the Sizing:Zone object for zone {}.",
    1634           0 :                                                  state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).ZoneName));
    1635             :                     }
    1636             :                 } else {
    1637           0 :                     if (PurchAir(PurchAirNum).MaxHeatSensCap > 0.0 && MaxHeatSensCapDes > 0.0) {
    1638           0 :                         MaxHeatSensCapUser = PurchAir(PurchAirNum).MaxHeatSensCap;
    1639           0 :                         BaseSizer::reportSizerOutput(state,
    1640           0 :                                                      PurchAir(PurchAirNum).cObjectName,
    1641           0 :                                                      PurchAir(PurchAirNum).Name,
    1642             :                                                      "Design Size Maximum Sensible Heating Capacity [W]",
    1643             :                                                      MaxHeatSensCapDes,
    1644             :                                                      "User-Specified Maximum Sensible Heating Capacity [W]",
    1645             :                                                      MaxHeatSensCapUser);
    1646           0 :                         if (state.dataGlobal->DisplayExtraWarnings) {
    1647           0 :                             if ((std::abs(MaxHeatSensCapDes - MaxHeatSensCapUser) / MaxHeatSensCapUser) > state.dataSize->AutoVsHardSizingThreshold) {
    1648           0 :                                 ShowMessage(state,
    1649           0 :                                             format("SizePurchasedAir: Potential issue with equipment sizing for {} {}",
    1650           0 :                                                    PurchAir(PurchAirNum).cObjectName,
    1651           0 :                                                    PurchAir(PurchAirNum).Name));
    1652           0 :                                 ShowContinueError(state,
    1653           0 :                                                   format("...User-Specified Maximum Sensible Heating Capacity of {:.2R} [W]", MaxHeatSensCapUser));
    1654           0 :                                 ShowContinueError(
    1655           0 :                                     state, format("...differs from Design Size Maximum Sensible Heating Capacity of {:.2R} [W]", MaxHeatSensCapDes));
    1656           0 :                                 ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
    1657           0 :                                 ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
    1658             :                             }
    1659             :                         }
    1660             :                     }
    1661             :                 }
    1662           0 :             }
    1663             : 
    1664           0 :             PrintFlag = true;
    1665           0 :             if (state.dataSize->ZoneHVACSizing(zoneHVACIndex).CoolingSAFMethod > 0) {
    1666           0 :                 state.dataSize->ZoneCoolingOnlyFan = true;
    1667           0 :                 SAFMethod = state.dataSize->ZoneHVACSizing(zoneHVACIndex).CoolingSAFMethod;
    1668           0 :                 ZoneEqSizing(state.dataSize->CurZoneEqNum).SizingMethod(SizingMethod) = SAFMethod;
    1669           0 :                 if (SAFMethod == SupplyAirFlowRate || SAFMethod == FlowPerFloorArea || SAFMethod == FractionOfAutosizedCoolingAirflow) {
    1670           0 :                     if (SAFMethod == SupplyAirFlowRate) {
    1671           0 :                         if ((state.dataSize->ZoneHVACSizing(zoneHVACIndex).MaxCoolAirVolFlow == AutoSize) &&
    1672           0 :                             ((PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitFlowRate) ||
    1673           0 :                              (PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitFlowRateAndCapacity) ||
    1674           0 :                              (PurchAir(PurchAirNum).OutdoorAir && PurchAir(PurchAirNum).EconomizerType != Econ::NoEconomizer))) {
    1675           0 :                             TempSize = state.dataSize->ZoneHVACSizing(zoneHVACIndex).MaxCoolAirVolFlow;
    1676           0 :                             CoolingAirFlowSizer sizingCoolingAirFlow;
    1677           0 :                             sizingCoolingAirFlow.overrideSizingString(SizingString);
    1678           0 :                             sizingCoolingAirFlow.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
    1679           0 :                             CoolingAirVolFlowDes = sizingCoolingAirFlow.size(state, TempSize, ErrorsFound);
    1680           0 :                         } else {
    1681           0 :                             if (state.dataSize->ZoneHVACSizing(zoneHVACIndex).MaxCoolAirVolFlow > 0.0) {
    1682           0 :                                 CoolingAirVolFlowDes = state.dataSize->ZoneHVACSizing(zoneHVACIndex).MaxCoolAirVolFlow;
    1683           0 :                                 CoolingAirFlowSizer sizingCoolingAirFlow;
    1684           0 :                                 sizingCoolingAirFlow.overrideSizingString(SizingString);
    1685           0 :                                 sizingCoolingAirFlow.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
    1686           0 :                                 CoolingAirVolFlowDes = sizingCoolingAirFlow.size(state, CoolingAirVolFlowDes, ErrorsFound);
    1687           0 :                             }
    1688             :                         }
    1689           0 :                     } else if (SAFMethod == FlowPerFloorArea) {
    1690           0 :                         ZoneEqSizing(state.dataSize->CurZoneEqNum).SystemAirFlow = true;
    1691           0 :                         ZoneEqSizing(state.dataSize->CurZoneEqNum).AirVolFlow = state.dataSize->ZoneHVACSizing(zoneHVACIndex).MaxCoolAirVolFlow *
    1692           0 :                                                                                 state.dataHeatBal->Zone(state.dataSize->DataZoneNumber).FloorArea;
    1693           0 :                         TempSize = ZoneEqSizing(state.dataSize->CurZoneEqNum).AirVolFlow;
    1694           0 :                         state.dataSize->DataScalableSizingON = true;
    1695           0 :                         CoolingAirFlowSizer sizingCoolingAirFlow;
    1696           0 :                         std::string stringOverride = "Maximum Cooling Air Flow Rate [m3/s]";
    1697           0 :                         if (state.dataGlobal->isEpJSON) stringOverride = "maximum_cooling_air_flow_rate [m3/s]";
    1698           0 :                         sizingCoolingAirFlow.overrideSizingString(stringOverride);
    1699             :                         // sizingCoolingAirFlow.setHVACSizingIndexData(FanCoil(FanCoilNum).HVACSizingIndex);
    1700           0 :                         sizingCoolingAirFlow.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
    1701           0 :                         CoolingAirVolFlowDes = sizingCoolingAirFlow.size(state, TempSize, ErrorsFound);
    1702           0 :                     } else if (SAFMethod == FractionOfAutosizedCoolingAirflow) {
    1703           0 :                         if ((state.dataSize->ZoneHVACSizing(zoneHVACIndex).MaxCoolAirVolFlow == AutoSize) &&
    1704           0 :                             ((PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitFlowRate) ||
    1705           0 :                              (PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitFlowRateAndCapacity) ||
    1706           0 :                              (PurchAir(PurchAirNum).OutdoorAir && PurchAir(PurchAirNum).EconomizerType != Econ::NoEconomizer))) {
    1707           0 :                             state.dataSize->DataFracOfAutosizedCoolingAirflow = state.dataSize->ZoneHVACSizing(zoneHVACIndex).MaxCoolAirVolFlow;
    1708           0 :                             TempSize = AutoSize;
    1709           0 :                             state.dataSize->DataScalableSizingON = true;
    1710           0 :                             CoolingAirFlowSizer sizingCoolingAirFlow;
    1711           0 :                             std::string stringOverride = "Maximum Cooling Air Flow Rate [m3/s]";
    1712           0 :                             if (state.dataGlobal->isEpJSON) stringOverride = "maximum_cooling_air_flow_rate [m3/s]";
    1713           0 :                             sizingCoolingAirFlow.overrideSizingString(stringOverride);
    1714             :                             // sizingCoolingAirFlow.setHVACSizingIndexData(FanCoil(FanCoilNum).HVACSizingIndex);
    1715           0 :                             sizingCoolingAirFlow.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
    1716           0 :                             CoolingAirVolFlowDes = sizingCoolingAirFlow.size(state, TempSize, ErrorsFound);
    1717           0 :                         }
    1718             :                     } else {
    1719             :                         // Invalid scalable sizing method
    1720             :                     }
    1721           0 :                 } else if (SAFMethod == FlowPerCoolingCapacity) {
    1722           0 :                     if ((state.dataSize->ZoneHVACSizing(zoneHVACIndex).MaxCoolAirVolFlow == AutoSize) &&
    1723           0 :                         ((PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitFlowRate) ||
    1724           0 :                          (PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitFlowRateAndCapacity) ||
    1725           0 :                          (PurchAir(PurchAirNum).OutdoorAir && PurchAir(PurchAirNum).EconomizerType != Econ::NoEconomizer))) {
    1726           0 :                         SizingMethod = CoolingCapacitySizing;
    1727           0 :                         TempSize = AutoSize;
    1728           0 :                         PrintFlag = false;
    1729           0 :                         CoolingCapacitySizer sizerCoolingCapacity;
    1730           0 :                         sizerCoolingCapacity.overrideSizingString(SizingString);
    1731           0 :                         sizerCoolingCapacity.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
    1732           0 :                         state.dataSize->DataAutosizedCoolingCapacity = sizerCoolingCapacity.size(state, TempSize, ErrorsFound);
    1733           0 :                         state.dataSize->DataFlowPerCoolingCapacity = state.dataSize->ZoneHVACSizing(zoneHVACIndex).MaxCoolAirVolFlow;
    1734           0 :                         PrintFlag = true;
    1735           0 :                         TempSize = AutoSize;
    1736           0 :                         state.dataSize->DataScalableSizingON = true;
    1737           0 :                         CoolingAirFlowSizer sizingCoolingAirFlow;
    1738           0 :                         std::string stringOverride = "Maximum Cooling Air Flow Rate [m3/s]";
    1739           0 :                         if (state.dataGlobal->isEpJSON) stringOverride = "maximum_cooling_air_flow_rate [m3/s]";
    1740           0 :                         sizingCoolingAirFlow.overrideSizingString(stringOverride);
    1741             :                         // sizingCoolingAirFlow.setHVACSizingIndexData(FanCoil(FanCoilNum).HVACSizingIndex);
    1742           0 :                         sizingCoolingAirFlow.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
    1743           0 :                         CoolingAirVolFlowDes = sizingCoolingAirFlow.size(state, TempSize, ErrorsFound);
    1744           0 :                     }
    1745             :                 }
    1746           0 :                 MaxCoolVolFlowRateDes = max(0.0, CoolingAirVolFlowDes);
    1747           0 :                 PurchAir(PurchAirNum).MaxCoolVolFlowRate = MaxCoolVolFlowRateDes;
    1748           0 :                 state.dataSize->ZoneCoolingOnlyFan = false;
    1749           0 :                 state.dataSize->DataScalableSizingON = false;
    1750             : 
    1751           0 :                 CapSizingMethod = state.dataSize->ZoneHVACSizing(zoneHVACIndex).CoolingCapMethod;
    1752           0 :                 ZoneEqSizing(state.dataSize->CurZoneEqNum).CapSizingMethod = CapSizingMethod;
    1753           0 :                 if (CapSizingMethod == CoolingDesignCapacity || CapSizingMethod == CapacityPerFloorArea ||
    1754           0 :                     CapSizingMethod == FractionOfAutosizedCoolingCapacity) {
    1755           0 :                     if (CapSizingMethod == CoolingDesignCapacity) {
    1756           0 :                         if (state.dataSize->ZoneHVACSizing(zoneHVACIndex).ScaledCoolingCapacity > 0.0) {
    1757           0 :                             ZoneEqSizing(state.dataSize->CurZoneEqNum).CoolingCapacity = true;
    1758           0 :                             ZoneEqSizing(state.dataSize->CurZoneEqNum).DesCoolingLoad =
    1759           0 :                                 state.dataSize->ZoneHVACSizing(zoneHVACIndex).ScaledCoolingCapacity;
    1760             :                         } else {
    1761           0 :                             state.dataSize->DataFlowUsedForSizing = state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).DesCoolMassFlow;
    1762             :                         }
    1763           0 :                         TempSize = state.dataSize->ZoneHVACSizing(zoneHVACIndex).ScaledCoolingCapacity;
    1764           0 :                     } else if (CapSizingMethod == CapacityPerFloorArea) {
    1765           0 :                         ZoneEqSizing(state.dataSize->CurZoneEqNum).CoolingCapacity = true;
    1766           0 :                         ZoneEqSizing(state.dataSize->CurZoneEqNum).DesCoolingLoad =
    1767           0 :                             state.dataSize->ZoneHVACSizing(zoneHVACIndex).ScaledCoolingCapacity *
    1768           0 :                             state.dataHeatBal->Zone(state.dataSize->DataZoneNumber).FloorArea;
    1769           0 :                         state.dataSize->DataScalableSizingON = true;
    1770           0 :                     } else if (CapSizingMethod == FractionOfAutosizedCoolingCapacity) {
    1771           0 :                         state.dataSize->DataFracOfAutosizedHeatingCapacity = state.dataSize->ZoneHVACSizing(zoneHVACIndex).ScaledCoolingCapacity;
    1772           0 :                         state.dataSize->DataFlowUsedForSizing = state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).DesCoolMassFlow;
    1773           0 :                         TempSize = AutoSize;
    1774             :                     }
    1775             :                 }
    1776           0 :                 SizingMethod = CoolingCapacitySizing;
    1777           0 :                 SizingString = "";
    1778           0 :                 state.dataSize->ZoneCoolingOnlyFan = true;
    1779           0 :                 PrintFlag = false;
    1780           0 :                 TempSize = PurchAir(PurchAirNum).MaxCoolTotCap;
    1781           0 :                 CoolingCapacitySizer sizerCoolingCapacity;
    1782           0 :                 sizerCoolingCapacity.overrideSizingString(SizingString);
    1783           0 :                 sizerCoolingCapacity.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
    1784           0 :                 MaxCoolTotCapDes = sizerCoolingCapacity.size(state, TempSize, ErrorsFound);
    1785           0 :                 state.dataSize->ZoneCoolingOnlyFan = false;
    1786           0 :                 if (MaxCoolTotCapDes < HVAC::SmallLoad) {
    1787           0 :                     MaxCoolTotCapDes = 0.0;
    1788             :                 }
    1789           0 :                 if (IsAutoSize) {
    1790           0 :                     PurchAir(PurchAirNum).MaxCoolTotCap = MaxCoolTotCapDes;
    1791           0 :                     BaseSizer::reportSizerOutput(state,
    1792           0 :                                                  PurchAir(PurchAirNum).cObjectName,
    1793           0 :                                                  PurchAir(PurchAirNum).Name,
    1794             :                                                  "Design Size Maximum Total Cooling Capacity [W]",
    1795             :                                                  MaxCoolTotCapDes);
    1796             :                     // If there is OA, check if sizing calcs have OA>0, throw warning if not
    1797           0 :                     if ((PurchAir(PurchAirNum).OutdoorAir) && (state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).MinOA == 0.0)) {
    1798           0 :                         ShowWarningError(state,
    1799           0 :                                          format("SizePurchasedAir: In {} = {}", PurchAir(PurchAirNum).cObjectName, PurchAir(PurchAirNum).Name));
    1800           0 :                         ShowContinueError(state, "There is outdoor air specified in this object, but the design outdoor air flow rate for this ");
    1801           0 :                         ShowContinueError(state, "zone is zero. The Maximum Total Cooling Capacity will be autosized for zero outdoor air flow. ");
    1802           0 :                         ShowContinueError(state,
    1803           0 :                                           format("Check the outdoor air specifications in the Sizing:Zone object for zone {}.",
    1804           0 :                                                  state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).ZoneName));
    1805             :                     }
    1806             :                 } else {
    1807           0 :                     if (PurchAir(PurchAirNum).MaxCoolTotCap > 0.0 && MaxCoolTotCapDes > 0.0) {
    1808           0 :                         MaxCoolTotCapUser = PurchAir(PurchAirNum).MaxCoolTotCap;
    1809           0 :                         BaseSizer::reportSizerOutput(state,
    1810           0 :                                                      PurchAir(PurchAirNum).cObjectName,
    1811           0 :                                                      PurchAir(PurchAirNum).Name,
    1812             :                                                      "Design Size Maximum Total Cooling Capacity [W]",
    1813             :                                                      MaxCoolTotCapDes,
    1814             :                                                      "User-Specified Maximum Total Cooling Capacity [W]",
    1815             :                                                      MaxCoolTotCapUser);
    1816           0 :                         if (state.dataGlobal->DisplayExtraWarnings) {
    1817           0 :                             if ((std::abs(MaxCoolTotCapDes - MaxCoolTotCapUser) / MaxCoolTotCapUser) > state.dataSize->AutoVsHardSizingThreshold) {
    1818           0 :                                 ShowMessage(state,
    1819           0 :                                             format("SizePurchasedAir: Potential issue with equipment sizing for {} {}",
    1820           0 :                                                    PurchAir(PurchAirNum).cObjectName,
    1821           0 :                                                    PurchAir(PurchAirNum).Name));
    1822           0 :                                 ShowContinueError(state, format("User-Specified Maximum Total Cooling Capacity of {:.2R} [W]", MaxCoolTotCapUser));
    1823           0 :                                 ShowContinueError(state,
    1824           0 :                                                   format("differs from Design Size Maximum Total Cooling Capacity of {:.2R} [W]", MaxCoolTotCapDes));
    1825           0 :                                 ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
    1826           0 :                                 ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
    1827             :                             }
    1828             :                         }
    1829             :                     }
    1830             :                 }
    1831           0 :             }
    1832             : 
    1833             :         } else {
    1834             :             // SizingString = "Maximum Heating Air Flow Rate [m3/s]";
    1835         219 :             SizingMethod = HeatingAirflowSizing;
    1836         219 :             FieldNum = 5;
    1837         219 :             SizingString = state.dataPurchasedAirMgr->PurchAirNumericFields(PurchAirNum).FieldNames(FieldNum) + " [m3/s]";
    1838         219 :             IsAutoSize = false;
    1839         219 :             PrintFlag = true;
    1840         404 :             if ((PurchAir(PurchAirNum).MaxHeatVolFlowRate == AutoSize) &&
    1841         185 :                 ((PurchAir(PurchAirNum).HeatingLimit == LimitType::LimitFlowRate) ||
    1842         183 :                  (PurchAir(PurchAirNum).HeatingLimit == LimitType::LimitFlowRateAndCapacity))) {
    1843           2 :                 IsAutoSize = true;
    1844             :             }
    1845         219 :             if (!IsAutoSize && !state.dataSize->ZoneSizingRunDone) { // Simulation continue
    1846         207 :                 if (PurchAir(PurchAirNum).MaxHeatVolFlowRate > 0.0) {
    1847           2 :                     HeatingAirFlowSizer sizingHeatingAirFlow;
    1848           2 :                     sizingHeatingAirFlow.overrideSizingString(SizingString);
    1849             :                     // sizingHeatingAirFlow.setHVACSizingIndexData(FanCoil(FanCoilNum).HVACSizingIndex);
    1850           2 :                     sizingHeatingAirFlow.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
    1851           4 :                     PurchAir(PurchAirNum).MaxHeatVolFlowRate =
    1852           2 :                         sizingHeatingAirFlow.size(state, PurchAir(PurchAirNum).MaxHeatVolFlowRate, ErrorsFound);
    1853           2 :                 }
    1854         207 :                 MaxHeatVolFlowRateDes = 0.0;
    1855             :             } else {
    1856          12 :                 state.dataSize->ZoneHeatingOnlyFan = true;
    1857          12 :                 TempSize = PurchAir(PurchAirNum).MaxHeatVolFlowRate;
    1858          12 :                 HeatingAirFlowSizer sizingHeatingAirFlow;
    1859          12 :                 sizingHeatingAirFlow.overrideSizingString(SizingString);
    1860             :                 // sizingHeatingAirFlow.setHVACSizingIndexData(FanCoil(FanCoilNum).HVACSizingIndex);
    1861          12 :                 sizingHeatingAirFlow.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
    1862          12 :                 MaxHeatVolFlowRateDes = sizingHeatingAirFlow.size(state, PurchAir(PurchAirNum).MaxHeatVolFlowRate, ErrorsFound);
    1863          12 :                 PurchAir(PurchAirNum).MaxHeatVolFlowRate = MaxHeatVolFlowRateDes;
    1864          12 :                 state.dataSize->ZoneHeatingOnlyFan = false;
    1865          12 :             }
    1866             : 
    1867         219 :             IsAutoSize = false;
    1868         219 :             SizingMethod = HeatingCapacitySizing;
    1869         219 :             FieldNum = 6; // N6, \field Maximum Sensible Heating Capacity
    1870         219 :             SizingString = state.dataPurchasedAirMgr->PurchAirNumericFields(PurchAirNum).FieldNames(FieldNum) + " [m3/s]";
    1871         219 :             if ((PurchAir(PurchAirNum).MaxHeatSensCap == AutoSize) && ((PurchAir(PurchAirNum).HeatingLimit == LimitType::LimitCapacity) ||
    1872           0 :                                                                        (PurchAir(PurchAirNum).HeatingLimit == LimitType::LimitFlowRateAndCapacity))) {
    1873           0 :                 IsAutoSize = true;
    1874             :             }
    1875         219 :             if (!IsAutoSize && !state.dataSize->ZoneSizingRunDone) { // Simulation continue
    1876         207 :                 if (PurchAir(PurchAirNum).MaxHeatSensCap > 0.0) {
    1877           0 :                     HeatingCapacitySizer sizerHeatingCapacity;
    1878           0 :                     sizerHeatingCapacity.overrideSizingString(SizingString);
    1879           0 :                     sizerHeatingCapacity.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
    1880           0 :                     MaxHeatSensCapDes = sizerHeatingCapacity.size(state, PurchAir(PurchAirNum).MaxHeatSensCap, ErrorsFound);
    1881           0 :                 }
    1882             :             } else {
    1883          12 :                 TempSize = PurchAir(PurchAirNum).MaxHeatSensCap;
    1884          12 :                 ZoneEqSizing(state.dataSize->CurZoneEqNum).OAVolFlow = state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).MinOA;
    1885          12 :                 state.dataSize->ZoneHeatingOnlyFan = true;
    1886          12 :                 PrintFlag = false;
    1887          12 :                 HeatingCapacitySizer sizerHeatingCapacity;
    1888          12 :                 sizerHeatingCapacity.overrideSizingString(SizingString);
    1889          12 :                 sizerHeatingCapacity.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
    1890          12 :                 MaxHeatSensCapDes = sizerHeatingCapacity.size(state, TempSize, ErrorsFound);
    1891          12 :                 state.dataSize->ZoneHeatingOnlyFan = false;
    1892          12 :             }
    1893         219 :             if (MaxHeatSensCapDes < HVAC::SmallLoad) {
    1894         219 :                 MaxHeatSensCapDes = 0.0;
    1895             :             }
    1896         219 :             if (IsAutoSize) {
    1897           0 :                 PurchAir(PurchAirNum).MaxHeatSensCap = MaxHeatSensCapDes;
    1898           0 :                 BaseSizer::reportSizerOutput(state,
    1899           0 :                                              PurchAir(PurchAirNum).cObjectName,
    1900           0 :                                              PurchAir(PurchAirNum).Name,
    1901             :                                              "Design Size Maximum Sensible Heating Capacity [W]",
    1902             :                                              MaxHeatSensCapDes);
    1903             :                 // If there is OA, check if sizing calcs have OA>0, throw warning if not
    1904           0 :                 if ((PurchAir(PurchAirNum).OutdoorAir) && (state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).MinOA == 0.0)) {
    1905           0 :                     ShowWarningError(state, format("InitPurchasedAir: In {} = {}", PurchAir(PurchAirNum).cObjectName, PurchAir(PurchAirNum).Name));
    1906           0 :                     ShowContinueError(state, "There is outdoor air specified in this object, but the design outdoor air flow rate for this ");
    1907           0 :                     ShowContinueError(state, "zone is zero. The Maximum Sensible Heating Capacity will be autosized for zero outdoor air flow. ");
    1908           0 :                     ShowContinueError(state,
    1909           0 :                                       format("Check the outdoor air specifications in the Sizing:Zone object for zone {}.",
    1910           0 :                                              state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).ZoneName));
    1911             :                 }
    1912             :             } else {
    1913         219 :                 if (PurchAir(PurchAirNum).MaxHeatSensCap > 0.0 && MaxHeatSensCapDes > 0.0) {
    1914           0 :                     MaxHeatSensCapUser = PurchAir(PurchAirNum).MaxHeatSensCap;
    1915           0 :                     BaseSizer::reportSizerOutput(state,
    1916           0 :                                                  PurchAir(PurchAirNum).cObjectName,
    1917           0 :                                                  PurchAir(PurchAirNum).Name,
    1918             :                                                  "Design Size Maximum Sensible Heating Capacity [W]",
    1919             :                                                  MaxHeatSensCapDes,
    1920             :                                                  "User-Specified Maximum Sensible Heating Capacity [W]",
    1921             :                                                  MaxHeatSensCapUser);
    1922           0 :                     if (state.dataGlobal->DisplayExtraWarnings) {
    1923           0 :                         if ((std::abs(MaxHeatSensCapDes - MaxHeatSensCapUser) / MaxHeatSensCapUser) > state.dataSize->AutoVsHardSizingThreshold) {
    1924           0 :                             ShowMessage(state,
    1925           0 :                                         format("SizePurchasedAir: Potential issue with equipment sizing for {} {}",
    1926           0 :                                                PurchAir(PurchAirNum).cObjectName,
    1927           0 :                                                PurchAir(PurchAirNum).Name));
    1928           0 :                             ShowContinueError(state, format("...User-Specified Maximum Sensible Heating Capacity of {:.2R} [W]", MaxHeatSensCapUser));
    1929           0 :                             ShowContinueError(
    1930           0 :                                 state, format("...differs from Design Size Maximum Sensible Heating Capacity of {:.2R} [W]", MaxHeatSensCapDes));
    1931           0 :                             ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
    1932           0 :                             ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
    1933             :                         }
    1934             :                     }
    1935             :                 }
    1936             :             }
    1937             : 
    1938         219 :             PrintFlag = true;
    1939         219 :             IsAutoSize = false;
    1940         402 :             if ((PurchAir(PurchAirNum).MaxCoolVolFlowRate == AutoSize) &&
    1941         183 :                 ((PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitFlowRate) ||
    1942         179 :                  (PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitFlowRateAndCapacity) ||
    1943         179 :                  (PurchAir(PurchAirNum).OutdoorAir && PurchAir(PurchAirNum).EconomizerType != Econ::NoEconomizer))) {
    1944           4 :                 IsAutoSize = true;
    1945             :             }
    1946         219 :             if (!IsAutoSize && !state.dataSize->ZoneSizingRunDone) { // Simulation continue
    1947         207 :                 if (PurchAir(PurchAirNum).MaxCoolVolFlowRate > 0.0) {
    1948           2 :                     CoolingAirFlowSizer sizingCoolingAirFlow;
    1949           2 :                     std::string stringOverride = "Maximum Cooling Air Flow Rate [m3/s]";
    1950           2 :                     if (state.dataGlobal->isEpJSON) stringOverride = "maximum_cooling_air_flow_rate [m3/s]";
    1951           2 :                     sizingCoolingAirFlow.overrideSizingString(stringOverride);
    1952             :                     // sizingCoolingAirFlow.setHVACSizingIndexData(FanCoil(FanCoilNum).HVACSizingIndex);
    1953           2 :                     sizingCoolingAirFlow.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
    1954           4 :                     PurchAir(PurchAirNum).MaxCoolVolFlowRate =
    1955           2 :                         sizingCoolingAirFlow.size(state, PurchAir(PurchAirNum).MaxCoolVolFlowRate, ErrorsFound);
    1956           2 :                 }
    1957             :             } else {
    1958          12 :                 state.dataSize->ZoneCoolingOnlyFan = true;
    1959          12 :                 TempSize = PurchAir(PurchAirNum).MaxCoolVolFlowRate;
    1960          12 :                 CoolingAirFlowSizer sizingCoolingAirFlow;
    1961          12 :                 std::string stringOverride = "Maximum Cooling Air Flow Rate [m3/s]";
    1962          12 :                 if (state.dataGlobal->isEpJSON) stringOverride = "maximum_cooling_air_flow_rate [m3/s]";
    1963          12 :                 sizingCoolingAirFlow.overrideSizingString(stringOverride);
    1964             :                 // sizingCoolingAirFlow.setHVACSizingIndexData(FanCoil(FanCoilNum).HVACSizingIndex);
    1965          12 :                 sizingCoolingAirFlow.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
    1966          12 :                 MaxCoolVolFlowRateDes = sizingCoolingAirFlow.size(state, TempSize, ErrorsFound);
    1967          12 :                 PurchAir(PurchAirNum).MaxCoolVolFlowRate = MaxCoolVolFlowRateDes;
    1968          12 :                 state.dataSize->ZoneCoolingOnlyFan = false;
    1969          12 :             }
    1970             : 
    1971         219 :             IsAutoSize = false;
    1972         219 :             SizingMethod = CoolingCapacitySizing;
    1973         219 :             FieldNum = 8; // N8, \field Maximum Total Cooling Capacity
    1974         219 :             SizingString = state.dataPurchasedAirMgr->PurchAirNumericFields(PurchAirNum).FieldNames(FieldNum) + " [m3/s]";
    1975         219 :             if ((PurchAir(PurchAirNum).MaxCoolTotCap == AutoSize) && ((PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitCapacity) ||
    1976           0 :                                                                       (PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitFlowRateAndCapacity))) {
    1977           0 :                 IsAutoSize = true;
    1978             :             }
    1979         219 :             if (!IsAutoSize && !state.dataSize->ZoneSizingRunDone) { // Simulation continue
    1980         207 :                 if (PurchAir(PurchAirNum).MaxCoolTotCap > 0.0) {
    1981           0 :                     CoolingCapacitySizer sizerCoolingCapacity;
    1982           0 :                     sizerCoolingCapacity.overrideSizingString(SizingString);
    1983           0 :                     sizerCoolingCapacity.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
    1984           0 :                     PurchAir(PurchAirNum).MaxCoolTotCap = sizerCoolingCapacity.size(state, PurchAir(PurchAirNum).MaxCoolTotCap, ErrorsFound);
    1985           0 :                 }
    1986             :             } else {
    1987          12 :                 state.dataSize->ZoneCoolingOnlyFan = true;
    1988          12 :                 ZoneEqSizing(state.dataSize->CurZoneEqNum).OAVolFlow = state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).MinOA;
    1989          12 :                 PrintFlag = false;
    1990          12 :                 TempSize = PurchAir(PurchAirNum).MaxCoolTotCap;
    1991          12 :                 CoolingCapacitySizer sizerCoolingCapacity;
    1992          12 :                 sizerCoolingCapacity.overrideSizingString(SizingString);
    1993          12 :                 sizerCoolingCapacity.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
    1994          12 :                 MaxCoolTotCapDes = sizerCoolingCapacity.size(state, TempSize, ErrorsFound);
    1995          12 :                 state.dataSize->ZoneCoolingOnlyFan = false;
    1996          12 :             }
    1997         219 :             if (MaxCoolTotCapDes < HVAC::SmallLoad) {
    1998         219 :                 MaxCoolTotCapDes = 0.0;
    1999             :             }
    2000         219 :             if (IsAutoSize) {
    2001           0 :                 PurchAir(PurchAirNum).MaxCoolTotCap = MaxCoolTotCapDes;
    2002           0 :                 BaseSizer::reportSizerOutput(state,
    2003           0 :                                              PurchAir(PurchAirNum).cObjectName,
    2004           0 :                                              PurchAir(PurchAirNum).Name,
    2005             :                                              "Design Size Maximum Total Cooling Capacity [W]",
    2006             :                                              MaxCoolTotCapDes);
    2007             :                 // If there is OA, check if sizing calcs have OA>0, throw warning if not
    2008           0 :                 if ((PurchAir(PurchAirNum).OutdoorAir) && (state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).MinOA == 0.0)) {
    2009           0 :                     ShowWarningError(state, format("SizePurchasedAir: In {} = {}", PurchAir(PurchAirNum).cObjectName, PurchAir(PurchAirNum).Name));
    2010           0 :                     ShowContinueError(state, "There is outdoor air specified in this object, but the design outdoor air flow rate for this ");
    2011           0 :                     ShowContinueError(state, "zone is zero. The Maximum Total Cooling Capacity will be autosized for zero outdoor air flow. ");
    2012           0 :                     ShowContinueError(state,
    2013           0 :                                       format("Check the outdoor air specifications in the Sizing:Zone object for zone {}.",
    2014           0 :                                              state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).ZoneName));
    2015             :                 }
    2016             :             } else {
    2017         219 :                 if (PurchAir(PurchAirNum).MaxCoolTotCap > 0.0 && MaxCoolTotCapDes > 0.0) {
    2018           0 :                     MaxCoolTotCapUser = PurchAir(PurchAirNum).MaxCoolTotCap;
    2019           0 :                     BaseSizer::reportSizerOutput(state,
    2020           0 :                                                  PurchAir(PurchAirNum).cObjectName,
    2021           0 :                                                  PurchAir(PurchAirNum).Name,
    2022             :                                                  "Design Size Maximum Total Cooling Capacity [W]",
    2023             :                                                  MaxCoolTotCapDes,
    2024             :                                                  "User-Specified Maximum Total Cooling Capacity [W]",
    2025             :                                                  MaxCoolTotCapUser);
    2026           0 :                     if (state.dataGlobal->DisplayExtraWarnings) {
    2027           0 :                         if ((std::abs(MaxCoolTotCapDes - MaxCoolTotCapUser) / MaxCoolTotCapUser) > state.dataSize->AutoVsHardSizingThreshold) {
    2028           0 :                             ShowMessage(state,
    2029           0 :                                         format("SizePurchasedAir: Potential issue with equipment sizing for {} {}",
    2030           0 :                                                PurchAir(PurchAirNum).cObjectName,
    2031           0 :                                                PurchAir(PurchAirNum).Name));
    2032           0 :                             ShowContinueError(state, format("User-Specified Maximum Total Cooling Capacity of {:.2R} [W]", MaxCoolTotCapUser));
    2033           0 :                             ShowContinueError(state,
    2034           0 :                                               format("differs from Design Size Maximum Total Cooling Capacity of {:.2R} [W]", MaxCoolTotCapDes));
    2035           0 :                             ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
    2036           0 :                             ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
    2037             :                         }
    2038             :                     }
    2039             :                 }
    2040             :             }
    2041             :         }
    2042             :     }
    2043             : 
    2044             :     //      IF (PurchAir(PurchAirNum)%OutdoorAir .AND. PurchAir(PurchAirNum)%OutsideAirVolFlowRate == AutoSize) THEN
    2045             :     //        IF (CurZoneEqNum > 0) THEN
    2046             :     //          CALL CheckZoneSizing(TRIM(PurchAir(PurchAirNum)%cObjectName), PurchAir(PurchAirNum)%Name)
    2047             :     //          PurchAir(PurchAirNum)%OutsideAirVolFlowRate = FinalZoneSizing(CurZoneEqNum)%MinOA
    2048             :     //          IF (PurchAir(PurchAirNum)%OutsideAirVolFlowRate < SmallAirVolFlow) THEN
    2049             :     //            PurchAir(PurchAirNum)%OutsideAirVolFlowRate = 0.0
    2050             :     //          END IF
    2051             :     //          CALL BaseSizer::reportSizerOutput(TRIM(PurchAir(PurchAirNum)%cObjectName), PurchAir(PurchAirNum)%Name, &
    2052             :     //                              'Outdoor Air Flow Rate [m3/s]', PurchAir(PurchAirNum)%OutsideAirVolFlowRate )
    2053             :     //        END IF
    2054             :     //      END IF
    2055         219 : }
    2056             : 
    2057     2076247 : void CalcPurchAirLoads(EnergyPlusData &state,
    2058             :                        int const PurchAirNum,
    2059             :                        Real64 &SysOutputProvided,   // Sensible output provided [W] cooling = negative
    2060             :                        Real64 &MoistOutputProvided, // Moisture output provided [kg/s] dehumidification = negative
    2061             :                        int const ControlledZoneNum)
    2062             : {
    2063             : 
    2064             :     // SUBROUTINE INFORMATION:
    2065             :     //       AUTHOR         Russ Taylor
    2066             :     //       DATE WRITTEN   Nov 1997
    2067             :     //       MODIFIED       Shirey, Aug 2009 (LatOutputProvided - now MoistOutputProvided)
    2068             :     //                      M. Witte June 2011, add new features including DCV, economizer, dehumidification
    2069             :     //                          and humidification,
    2070             :     //                      July 2012, Chandan Sharma - FSEC: Added hybrid ventilation manager
    2071             :     //       RE-ENGINEERED  na
    2072             : 
    2073             :     // SUBROUTINE PARAMETER DEFINITIONS:
    2074             :     static constexpr std::string_view RoutineName("CalcPurchAirLoads");
    2075             : 
    2076             :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    2077             :     int InNodeNum; // Ideal loads supply node to zone
    2078             :     //         INTEGER   :: ExhNodeNum        ! Ideal loads exhaust node from zone
    2079             :     int ZoneNodeNum;                   // Zone air node
    2080             :     int OANodeNum;                     // Outdoor air inlet node
    2081             :     int RecircNodeNum;                 // Return air or zone exhaust node
    2082             :     OpMode OperatingMode;              // current operating mode, Off, Heat, Cool, or DeadBand
    2083             :     Real64 SupplyMassFlowRate;         // System supply air mass flow rate [kg/s]
    2084             :     Real64 SupplyMassFlowRateForHumid; // System supply air mass flow rate required to meet humdification load [kg/s]
    2085             :     Real64 SupplyMassFlowRateForDehum; // System supply air mass flow rate required to meet dehumidification load [kg/s]
    2086             :     Real64 SupplyMassFlowRateForCool;  // System supply air mass flow rate required to meet sensible cooling load[kg/s]
    2087             :     Real64 SupplyMassFlowRateForHeat;  // System supply air mass flow rate required to meet sensible heating load[kg/s]
    2088             :     Real64 SupplyHumRatForHumid;       // Supply air humidity ratio require to meet the humidification load [kgWater/kgDryAir]
    2089             :     Real64 SupplyHumRatForDehum;       // Supply air humidity ratio require to meet the dehumidification load [kgWater/kgDryAir]
    2090             :     Real64 OAMassFlowRate;             // Outdoor air mass flow rate [kg/s]
    2091             :     Real64 OAVolFlowRate;              // Outdoor air volume flow rate at standard density [m3/s]
    2092             :     Real64 MinOASensOutput;            // Minimum Outdoor air sensible output [W], <0 means OA is cooler than zone air
    2093             :     Real64 MinOALatOutput;             // Minimum Outdoor air moisture load [kg/s]
    2094             :     Real64 SensOutput;                 // Sensible output [W] (psitive means heating, negative means cooling)
    2095             :     Real64 HeatSensOutput;             // Heating sensible output [W]
    2096             :     Real64 CoolSensOutput;             // Cooling sensible output [W] (positive value menas cooling)
    2097             :     Real64 LatOutput;                  // Latent output [W] (positive value means hudmification, negative means dehumidification)
    2098             :     Real64 CoolLatOutput;              // Cooling latent output [W] (positive value means dehumidification)
    2099             :     Real64 CoolTotOutput;              // Cooling total output [W] (positive value means cooling)
    2100             :     Real64 DeltaT;                     // Delta temperature - reused in multiple places
    2101             :     Real64 DeltaHumRat;                // Delta humidity ratio - reused in multiple places
    2102             :     Real64 QZnHeatSP;                  // Load required to meet heating setpoint [W] (>0 is a heating load)
    2103             :     Real64 QZnCoolSP;                  // Load required to meet cooling setpoint [W] (<0 is a cooling load)
    2104             :     Real64 MdotZnHumidSP;              // Load required to meet humidifying setpoint [kgWater/s] (>0 = a humidify load)
    2105             :     Real64 MdotZnDehumidSP;            // Load required to meet dehumidifying setpoint [kgWater/s] (<0 = a dehumidify load)
    2106             :     bool UnitOn;
    2107             :     bool HeatOn;             // Flag for heating and humidification availbility schedule, true if heating is on
    2108             :     bool CoolOn;             // Flag for cooling and dehumidification availbility schedule, true if cooling is on
    2109             :     bool EconoOn;            // Flag for economizer operation, true if economizer is on
    2110             :     Real64 SupplyHumRatOrig; // Supply inlet to zone humidity ratio before saturation check [kgWater/kgDryAir]
    2111             :     Real64 SupplyHumRatSat;  // Supply inlet to zone humidity ratio saturation at SupplyTemp [kgWater/kgDryAir]
    2112             :     Real64 SupplyEnthalpy;   // Supply inlet to zone enthalpy [J/kg]
    2113             :     Real64 MixedAirEnthalpy; // Mixed air enthalpy [J/kg]
    2114             :     Real64 CpAir;            // Specific heat [J/kg-C] reused in multiple places
    2115             :     //         REAL(r64) :: SpecHumOut   ! Specific humidity ratio of outlet air (kg moisture / kg moist air)
    2116             :     //         REAL(r64) :: SpecHumIn    ! Specific humidity ratio of inlet [zone] air (kg moisture / kg moist air)
    2117             : 
    2118     2076247 :     auto &PurchAir(state.dataPurchasedAirMgr->PurchAir);
    2119             : 
    2120             :     // Sign convention: SysOutputProvided <0 Supply air is heated on entering zone (zone is cooled)
    2121             :     //                  SysOutputProvided >0 Supply air is cooled on entering zone (zone is heated)
    2122     2076247 :     InNodeNum = PurchAir(PurchAirNum).ZoneSupplyAirNodeNum;
    2123     2076247 :     ZoneNodeNum = state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).ZoneNode;
    2124     2076247 :     OANodeNum = PurchAir(PurchAirNum).OutdoorAirNodeNum;
    2125     2076247 :     RecircNodeNum = PurchAir(PurchAirNum).ZoneRecircAirNodeNum;
    2126     2076247 :     SupplyMassFlowRate = 0.0;
    2127     2076247 :     OAMassFlowRate = 0.0;
    2128     2076247 :     PurchAir(PurchAirNum).MinOAMassFlowRate = 0.0;
    2129     2076247 :     PurchAir(PurchAirNum).TimeEconoActive = 0.0;
    2130     2076247 :     PurchAir(PurchAirNum).TimeHtRecActive = 0.0;
    2131     2076247 :     SysOutputProvided = 0.0;
    2132     2076247 :     MoistOutputProvided = 0.0;
    2133     2076247 :     CoolSensOutput = 0.0;
    2134     2076247 :     CoolLatOutput = 0.0;
    2135     2076247 :     CoolTotOutput = 0.0;
    2136     2076247 :     HeatSensOutput = 0.0;
    2137     2076247 :     LatOutput = 0.0;
    2138             : 
    2139             :     // default unit to ON
    2140     2076247 :     UnitOn = true;
    2141     2076247 :     EconoOn = false;
    2142             :     // get current zone requirements
    2143     2076247 :     QZnHeatSP = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ControlledZoneNum).RemainingOutputReqToHeatSP;
    2144     2076247 :     QZnCoolSP = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ControlledZoneNum).RemainingOutputReqToCoolSP;
    2145             : 
    2146     2076247 :     if (allocated(state.dataAvail->ZoneComp)) {
    2147     2076235 :         auto &availMgr = state.dataAvail->ZoneComp(DataZoneEquipment::ZoneEquipType::PurchasedAir).ZoneCompAvailMgrs(PurchAirNum);
    2148     2076235 :         availMgr.ZoneNum = ControlledZoneNum;
    2149     2076235 :         PurchAir(PurchAirNum).availStatus = availMgr.availStatus;
    2150             :         // Check if the hybrid ventilation availability manager is turning the unit off
    2151     2076235 :         if (PurchAir(PurchAirNum).availStatus == Avail::Status::ForceOff) {
    2152           0 :             UnitOn = false;
    2153             :         }
    2154             :     }
    2155             : 
    2156             :     // Check if the unit is scheduled off
    2157             :     //         IF (PurchAir(PurchAirNum)%AvailSchedPtr > 0) THEN
    2158     2076247 :     if (GetCurrentScheduleValue(state, PurchAir(PurchAirNum).AvailSchedPtr) <= 0) {
    2159           0 :         UnitOn = false;
    2160             :     }
    2161             :     //         END IF
    2162             :     // Check if heating and cooling available
    2163     2076247 :     HeatOn = true;
    2164             :     //         IF (PurchAir(PurchAirNum)%HeatSchedPtr > 0) THEN
    2165     2076247 :     if (GetCurrentScheduleValue(state, PurchAir(PurchAirNum).HeatSchedPtr) <= 0) {
    2166           0 :         HeatOn = false;
    2167             :     }
    2168             :     //         END IF
    2169     2076247 :     CoolOn = true;
    2170             :     //         IF (PurchAir(PurchAirNum)%CoolSchedPtr > 0) THEN
    2171     2076247 :     if (GetCurrentScheduleValue(state, PurchAir(PurchAirNum).CoolSchedPtr) <= 0) {
    2172        8425 :         CoolOn = false;
    2173             :     }
    2174             :     //         END IF
    2175             : 
    2176     2076247 :     if (UnitOn) {
    2177     2076247 :         auto &thisZoneHB = state.dataZoneTempPredictorCorrector->zoneHeatBalance(ControlledZoneNum);
    2178             :         // Calculate current minimum outdoor air flow rate based on design OA specifications and DCV or CO2 control
    2179     2076247 :         CalcPurchAirMinOAMassFlow(state, PurchAirNum, ControlledZoneNum, OAMassFlowRate);
    2180             : 
    2181             :         // EMS override point  Purch air outdoor air massflow rate.....
    2182     2076247 :         if (PurchAir(PurchAirNum).EMSOverrideOAMdotOn) {
    2183           0 :             OAMassFlowRate = PurchAir(PurchAirNum).EMSValueOAMassFlowRate;
    2184             :         }
    2185             : 
    2186             :         // Calculate minimum outdoor air sensible and latent load
    2187     2076247 :         if (PurchAir(PurchAirNum).OutdoorAir) {
    2188       14788 :             CpAir = PsyCpAirFnW(state.dataLoopNodes->Node(OANodeNum).HumRat);
    2189       14788 :             MinOASensOutput = OAMassFlowRate * CpAir * (state.dataLoopNodes->Node(OANodeNum).Temp - state.dataLoopNodes->Node(ZoneNodeNum).Temp);
    2190       14788 :             MinOALatOutput = OAMassFlowRate * (state.dataLoopNodes->Node(OANodeNum).HumRat - state.dataLoopNodes->Node(ZoneNodeNum).HumRat);
    2191             :         } else {
    2192     2061459 :             MinOASensOutput = 0.0;
    2193     2061459 :             MinOALatOutput = 0.0;
    2194             :         }
    2195     2076247 :         SupplyMassFlowRate = OAMassFlowRate;
    2196             : 
    2197             :         // Check if cooling of the supply air stream is required
    2198             : 
    2199             :         // Cooling operation
    2200     2076247 :         if ((MinOASensOutput >= QZnCoolSP) && (state.dataHeatBalFanSys->TempControlType(ControlledZoneNum) != HVAC::ThermostatType::SingleHeating)) {
    2201      540317 :             OperatingMode = OpMode::Cool;
    2202             :             // Calculate supply mass flow, temp and humidity with the following constraints:
    2203             :             //  Min cooling supply temp
    2204             :             //  Max total cooling capacity
    2205             :             //  Max cooling airflow
    2206             :             //  Min cooling supply humrat  (and Max heating supply humrat)
    2207             :             //  Min OA mass flow rate
    2208             : 
    2209             :             // Check if OA flow rate greater than max cooling airflow limit
    2210      540317 :             if (((PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitFlowRate) ||
    2211      552738 :                  (PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitFlowRateAndCapacity)) &&
    2212       12421 :                 (OAMassFlowRate > PurchAir(PurchAirNum).MaxCoolMassFlowRate)) {
    2213           0 :                 OAVolFlowRate = OAMassFlowRate / state.dataEnvrn->StdRhoAir;
    2214           0 :                 if (PurchAir(PurchAirNum).OAFlowMaxCoolOutputError < 1) {
    2215           0 :                     ++PurchAir(PurchAirNum).OAFlowMaxCoolOutputError;
    2216           0 :                     ShowWarningError(state,
    2217           0 :                                      format("{} \"{}\" Requested outdoor air flow rate = {:.5T} [m3/s] exceeds limit.",
    2218           0 :                                             PurchAir(PurchAirNum).cObjectName,
    2219           0 :                                             PurchAir(PurchAirNum).Name,
    2220             :                                             OAVolFlowRate));
    2221           0 :                     ShowContinueError(
    2222             :                         state,
    2223           0 :                         format(" Will be reduced to the Maximum Cooling Air Flow Rate = {:.5T} [m3/s]", PurchAir(PurchAirNum).MaxCoolVolFlowRate));
    2224           0 :                     ShowContinueErrorTimeStamp(state, "");
    2225             :                 } else {
    2226           0 :                     ShowRecurringWarningErrorAtEnd(
    2227             :                         state,
    2228           0 :                         PurchAir(PurchAirNum).cObjectName + " \"" + PurchAir(PurchAirNum).Name +
    2229             :                             "\" Requested outdoor air flow rate [m3/s] reduced to Maximum Cooling Air Flow Rate warning continues...",
    2230           0 :                         PurchAir(PurchAirNum).OAFlowMaxCoolOutputIndex,
    2231             :                         OAVolFlowRate);
    2232             :                 }
    2233           0 :                 OAMassFlowRate = PurchAir(PurchAirNum).MaxCoolMassFlowRate;
    2234             : 
    2235             :             } else {
    2236             :                 // Model economizer
    2237      540317 :                 if (PurchAir(PurchAirNum).EconomizerType != Econ::NoEconomizer) {
    2238        5122 :                     if (((PurchAir(PurchAirNum).EconomizerType == Econ::DifferentialDryBulb) &&
    2239       10060 :                          (state.dataLoopNodes->Node(OANodeNum).Temp < state.dataLoopNodes->Node(PurchAir(PurchAirNum).ZoneRecircAirNodeNum).Temp)) ||
    2240        4938 :                         ((PurchAir(PurchAirNum).EconomizerType == Econ::DifferentialEnthalpy) &&
    2241        1702 :                          (state.dataLoopNodes->Node(OANodeNum).Enthalpy <
    2242        1702 :                           state.dataLoopNodes->Node(PurchAir(PurchAirNum).ZoneRecircAirNodeNum).Enthalpy))) {
    2243             : 
    2244             :                         // Calculate supply MassFlowRate based on sensible load but limit to Max Cooling Supply Air Flow Rate if specified
    2245         184 :                         CpAir = PsyCpAirFnW(thisZoneHB.airHumRat);
    2246         184 :                         DeltaT = (state.dataLoopNodes->Node(OANodeNum).Temp - state.dataLoopNodes->Node(ZoneNodeNum).Temp);
    2247         184 :                         if (DeltaT < -HVAC::SmallTempDiff) {
    2248         184 :                             SupplyMassFlowRate = QZnCoolSP / CpAir / DeltaT;
    2249         184 :                             if (((PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitFlowRate) ||
    2250         368 :                                  (PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitFlowRateAndCapacity)) &&
    2251         184 :                                 (PurchAir(PurchAirNum).MaxCoolMassFlowRate > 0.0)) {
    2252         184 :                                 SupplyMassFlowRate = min(max(SupplyMassFlowRate, 0.0), PurchAir(PurchAirNum).MaxCoolMassFlowRate);
    2253             :                             }
    2254         184 :                             if (SupplyMassFlowRate > OAMassFlowRate) {
    2255         184 :                                 EconoOn = true;
    2256         184 :                                 OAMassFlowRate = SupplyMassFlowRate;
    2257         184 :                                 PurchAir(PurchAirNum).TimeEconoActive = state.dataHVACGlobal->TimeStepSys;
    2258             :                             }
    2259             :                         }
    2260             :                     }
    2261             :                 }
    2262             :             }
    2263             : 
    2264             :             // Determine supply mass flow rate
    2265             :             // Mass flow rate to meet sensible load, at Minimum Cooling Supply Air Temperature
    2266      540317 :             SupplyMassFlowRateForCool = 0.0;
    2267      540317 :             if (CoolOn) {
    2268      535856 :                 CpAir = PsyCpAirFnW(thisZoneHB.airHumRat);
    2269      535856 :                 DeltaT = (PurchAir(PurchAirNum).MinCoolSuppAirTemp - state.dataLoopNodes->Node(ZoneNodeNum).Temp);
    2270      535856 :                 if (DeltaT < -HVAC::SmallTempDiff) {
    2271      534980 :                     SupplyMassFlowRateForCool = QZnCoolSP / CpAir / DeltaT;
    2272             :                 }
    2273             :             }
    2274             : 
    2275             :             // Mass flow rate to meet dehumidification load, if applicable, at Minimum Cooling Supply Humidity Ratio
    2276      540317 :             SupplyMassFlowRateForDehum = 0.0;
    2277      540317 :             if (CoolOn) {
    2278      535856 :                 if (PurchAir(PurchAirNum).DehumidCtrlType == HumControl::Humidistat) {
    2279       11636 :                     MdotZnDehumidSP = state.dataZoneEnergyDemand->ZoneSysMoistureDemand(ControlledZoneNum).RemainingOutputReqToDehumidSP;
    2280       11636 :                     DeltaHumRat = (PurchAir(PurchAirNum).MinCoolSuppAirHumRat - state.dataLoopNodes->Node(ZoneNodeNum).HumRat);
    2281       11636 :                     if ((DeltaHumRat < -SmallDeltaHumRat) && (MdotZnDehumidSP < 0.0)) {
    2282         188 :                         SupplyMassFlowRateForDehum = MdotZnDehumidSP / DeltaHumRat;
    2283             :                     }
    2284             :                 }
    2285             :             }
    2286             : 
    2287             :             // Mass flow rate to meet humidification load, if applicable, at Maximum Heating Supply Humidity Ratio
    2288             :             // This section is the cooling section, so humidification should activate only if humidification control = humidistat
    2289             :             //   and if dehumidification control = humidistat or none
    2290      540317 :             SupplyMassFlowRateForHumid = 0.0;
    2291      540317 :             if (HeatOn) {
    2292      540317 :                 if (PurchAir(PurchAirNum).HumidCtrlType == HumControl::Humidistat) {
    2293        4994 :                     if ((PurchAir(PurchAirNum).DehumidCtrlType == HumControl::Humidistat) ||
    2294        1646 :                         (PurchAir(PurchAirNum).DehumidCtrlType == HumControl::None)) {
    2295        1702 :                         MdotZnHumidSP = state.dataZoneEnergyDemand->ZoneSysMoistureDemand(ControlledZoneNum).RemainingOutputReqToHumidSP;
    2296        1702 :                         DeltaHumRat = (PurchAir(PurchAirNum).MaxHeatSuppAirHumRat - state.dataLoopNodes->Node(ZoneNodeNum).HumRat);
    2297        1702 :                         if ((DeltaHumRat > SmallDeltaHumRat) && (MdotZnHumidSP > 0.0)) {
    2298           0 :                             SupplyMassFlowRateForHumid = MdotZnHumidSP / DeltaHumRat;
    2299             :                         }
    2300             :                     }
    2301             :                 }
    2302             :             }
    2303             : 
    2304             :             // If cooling capacity is limited to zero, SupplyMassFlowRate* should be set to zero
    2305      540317 :             if (((PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitCapacity) ||
    2306      540317 :                  (PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitFlowRateAndCapacity)) &&
    2307           0 :                 (PurchAir(PurchAirNum).MaxCoolTotCap == 0)) {
    2308           0 :                 SupplyMassFlowRateForCool = 0;
    2309           0 :                 SupplyMassFlowRateForDehum = 0;
    2310           0 :                 SupplyMassFlowRateForHumid = 0;
    2311             :             }
    2312             : 
    2313             :             // Supply mass flow is greatest of these, but limit to cooling max flow rate, if applicable
    2314      540317 :             SupplyMassFlowRate = max(0.0, OAMassFlowRate, SupplyMassFlowRateForCool, SupplyMassFlowRateForDehum, SupplyMassFlowRateForHumid);
    2315             :             // EMS override point  Purch air massflow rate..... but only if unit is on, i.e. SupplyMassFlowRate>0.0
    2316      540317 :             if (PurchAir(PurchAirNum).EMSOverrideMdotOn) {
    2317       79816 :                 SupplyMassFlowRate = PurchAir(PurchAirNum).EMSValueMassFlowRate;
    2318       79816 :                 OAMassFlowRate = min(OAMassFlowRate, SupplyMassFlowRate);
    2319             :             }
    2320      540317 :             if (((PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitFlowRate) ||
    2321      552738 :                  (PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitFlowRateAndCapacity)) &&
    2322       12421 :                 (PurchAir(PurchAirNum).MaxCoolMassFlowRate > 0.0)) {
    2323       12420 :                 SupplyMassFlowRate = min(SupplyMassFlowRate, PurchAir(PurchAirNum).MaxCoolMassFlowRate);
    2324             :             }
    2325             : 
    2326      540317 :             if (SupplyMassFlowRate <= HVAC::VerySmallMassFlow) SupplyMassFlowRate = 0.0;
    2327             : 
    2328             :             // Calculate mixed air conditions
    2329      540317 :             CalcPurchAirMixedAir(state,
    2330             :                                  PurchAirNum,
    2331             :                                  OAMassFlowRate,
    2332             :                                  SupplyMassFlowRate,
    2333      540317 :                                  PurchAir(PurchAirNum).MixedAirTemp,
    2334      540317 :                                  PurchAir(PurchAirNum).MixedAirHumRat,
    2335             :                                  MixedAirEnthalpy,
    2336             :                                  OperatingMode);
    2337             : 
    2338             :             // Calculate supply air conditions using final massflow rate, imposing capacity limits if specified
    2339             :             // If capacity limits are exceeded, keep massflow rate where it is and adjust supply temp
    2340             :             // In general, in the cooling section, don't let SupplyTemp be set to something that results in heating
    2341      540317 :             if (SupplyMassFlowRate > 0.0) {
    2342             :                 // Calculate supply temp at SupplyMassFlowRate and recheck limit on Minimum Cooling Supply Air Temperature
    2343      534980 :                 CpAir = PsyCpAirFnW(thisZoneHB.airHumRat);
    2344      534980 :                 PurchAir(PurchAirNum).SupplyTemp = QZnCoolSP / (CpAir * SupplyMassFlowRate) + state.dataLoopNodes->Node(ZoneNodeNum).Temp;
    2345      534980 :                 PurchAir(PurchAirNum).SupplyTemp = max(PurchAir(PurchAirNum).SupplyTemp, PurchAir(PurchAirNum).MinCoolSuppAirTemp);
    2346             :                 // This is the cooling mode, so SupplyTemp can't be more than MixedAirTemp
    2347      534980 :                 PurchAir(PurchAirNum).SupplyTemp = min(PurchAir(PurchAirNum).SupplyTemp, PurchAir(PurchAirNum).MixedAirTemp);
    2348      534980 :                 PurchAir(PurchAirNum).SupplyHumRat = PurchAir(PurchAirNum).MixedAirHumRat;
    2349      534980 :                 SupplyEnthalpy = PsyHFnTdbW(PurchAir(PurchAirNum).SupplyTemp, PurchAir(PurchAirNum).SupplyHumRat);
    2350             : 
    2351             :                 // Check sensible load vs max total cooling capacity, if specified, and adjust supply temp before applying humidity controls
    2352             :                 // Will check again later, too
    2353     1069960 :                 if ((PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitCapacity) ||
    2354      534980 :                     (PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitFlowRateAndCapacity)) {
    2355           0 :                     CpAir = PsyCpAirFnW(PurchAir(PurchAirNum).MixedAirHumRat);
    2356           0 :                     CoolSensOutput = SupplyMassFlowRate * (MixedAirEnthalpy - SupplyEnthalpy);
    2357           0 :                     if (CoolSensOutput >= PurchAir(PurchAirNum).MaxCoolTotCap) {
    2358           0 :                         CoolSensOutput = PurchAir(PurchAirNum).MaxCoolTotCap;
    2359           0 :                         SupplyEnthalpy = MixedAirEnthalpy - CoolSensOutput / SupplyMassFlowRate;
    2360           0 :                         PurchAir(PurchAirNum).SupplyTemp = PsyTdbFnHW(SupplyEnthalpy, PurchAir(PurchAirNum).SupplyHumRat);
    2361             :                         // This is the cooling mode, so SupplyTemp can't be more than MixedAirTemp
    2362           0 :                         PurchAir(PurchAirNum).SupplyTemp = min(PurchAir(PurchAirNum).SupplyTemp, PurchAir(PurchAirNum).MixedAirTemp);
    2363             :                     } // Capacity limit exceeded
    2364             :                 }
    2365             : 
    2366             :                 // Set supply humidity ratio for cooling/dehumidification
    2367      534980 :                 PurchAir(PurchAirNum).SupplyHumRat = PurchAir(PurchAirNum).MixedAirHumRat;
    2368      534980 :                 switch (PurchAir(PurchAirNum).DehumidCtrlType) {
    2369          30 :                 case HumControl::None: {
    2370          30 :                     PurchAir(PurchAirNum).SupplyHumRat = PurchAir(PurchAirNum).MixedAirHumRat; // Unnecessary line?
    2371          30 :                 } break;
    2372       35627 :                 case HumControl::ConstantSensibleHeatRatio: {
    2373             :                     // SHR = CoolSensOutput/CoolTotOutput
    2374             :                     // CoolTotOutput = CoolSensOutput/SHR
    2375       35627 :                     CpAir = PsyCpAirFnW(PurchAir(PurchAirNum).MixedAirHumRat);
    2376       35627 :                     CoolSensOutput = SupplyMassFlowRate * CpAir * (PurchAir(PurchAirNum).MixedAirTemp - PurchAir(PurchAirNum).SupplyTemp);
    2377       35627 :                     CoolTotOutput = CoolSensOutput / PurchAir(PurchAirNum).CoolSHR;
    2378       35627 :                     SupplyEnthalpy = MixedAirEnthalpy - CoolTotOutput / SupplyMassFlowRate;
    2379             :                     //  Limit for overdrying (avoid Pysch errors which occur if SupplyEnthalpy is too low for SupplyTemp)
    2380       35627 :                     SupplyEnthalpy = max(SupplyEnthalpy, PsyHFnTdbW(PurchAir(PurchAirNum).SupplyTemp, 0.00001));
    2381       35627 :                     PurchAir(PurchAirNum).SupplyHumRat =
    2382       35627 :                         min(PurchAir(PurchAirNum).SupplyHumRat, PsyWFnTdbH(state, PurchAir(PurchAirNum).SupplyTemp, SupplyEnthalpy, RoutineName));
    2383             :                     // Apply min cooling humidity ratio limit
    2384       35627 :                     PurchAir(PurchAirNum).SupplyHumRat = max(PurchAir(PurchAirNum).SupplyHumRat, PurchAir(PurchAirNum).MinCoolSuppAirHumRat);
    2385             :                     // But don't let it be higher than incoming MixedAirHumRat
    2386       35627 :                     PurchAir(PurchAirNum).SupplyHumRat = min(PurchAir(PurchAirNum).SupplyHumRat, PurchAir(PurchAirNum).MixedAirHumRat);
    2387       35627 :                 } break;
    2388       11636 :                 case HumControl::Humidistat: {
    2389       11636 :                     MdotZnDehumidSP = state.dataZoneEnergyDemand->ZoneSysMoistureDemand(ControlledZoneNum).RemainingOutputReqToDehumidSP;
    2390       11636 :                     SupplyHumRatForDehum = MdotZnDehumidSP / SupplyMassFlowRate + state.dataLoopNodes->Node(ZoneNodeNum).HumRat;
    2391       11636 :                     SupplyHumRatForDehum = max(SupplyHumRatForDehum, PurchAir(PurchAirNum).MinCoolSuppAirHumRat);
    2392       11636 :                     PurchAir(PurchAirNum).SupplyHumRat = min(PurchAir(PurchAirNum).MixedAirHumRat, SupplyHumRatForDehum);
    2393       11636 :                 } break;
    2394      487687 :                 case HumControl::ConstantSupplyHumidityRatio: {
    2395      487687 :                     PurchAir(PurchAirNum).SupplyHumRat = PurchAir(PurchAirNum).MinCoolSuppAirHumRat;
    2396      487687 :                 } break;
    2397           0 :                 default: {
    2398           0 :                     PurchAir(PurchAirNum).SupplyHumRat = PurchAir(PurchAirNum).MixedAirHumRat;
    2399           0 :                 } break;
    2400             :                 }
    2401             : 
    2402             :                 // Check supply humidity ratio for humidification (SupplyHumRatForHum should always be < SupplyHumRatForDehum)
    2403             :                 // This section is the cooling section, so humidification should activate only if humidification control = humidistat
    2404             :                 //   and if dehumidification control = humidistat or none
    2405      534980 :                 if (HeatOn) {
    2406      534980 :                     if (PurchAir(PurchAirNum).HumidCtrlType == HumControl::Humidistat) {
    2407        4994 :                         if ((PurchAir(PurchAirNum).DehumidCtrlType == HumControl::Humidistat) ||
    2408        1646 :                             (PurchAir(PurchAirNum).DehumidCtrlType == HumControl::None)) {
    2409        1702 :                             MdotZnHumidSP = state.dataZoneEnergyDemand->ZoneSysMoistureDemand(ControlledZoneNum).RemainingOutputReqToHumidSP;
    2410        1702 :                             SupplyHumRatForHumid = MdotZnHumidSP / SupplyMassFlowRate + state.dataLoopNodes->Node(ZoneNodeNum).HumRat;
    2411        1702 :                             SupplyHumRatForHumid = min(SupplyHumRatForHumid, PurchAir(PurchAirNum).MaxHeatSuppAirHumRat);
    2412        1702 :                             PurchAir(PurchAirNum).SupplyHumRat = max(PurchAir(PurchAirNum).SupplyHumRat, SupplyHumRatForHumid);
    2413             :                         }
    2414             :                     }
    2415             :                 }
    2416             : 
    2417             :                 //   Limit supply humidity ratio to saturation at supply outlet temp
    2418             : 
    2419      534980 :                 SupplyHumRatOrig = PurchAir(PurchAirNum).SupplyHumRat;
    2420      534980 :                 SupplyHumRatSat = PsyWFnTdbRhPb(state, PurchAir(PurchAirNum).SupplyTemp, 1.0, state.dataEnvrn->OutBaroPress, RoutineName);
    2421      534980 :                 PurchAir(PurchAirNum).SupplyHumRat = min(SupplyHumRatOrig, SupplyHumRatSat);
    2422      534980 :                 SupplyEnthalpy = PsyHFnTdbW(PurchAir(PurchAirNum).SupplyTemp, PurchAir(PurchAirNum).SupplyHumRat);
    2423             : 
    2424             :                 // Check max total Cooling capacity, if specified
    2425     1069960 :                 if ((PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitCapacity) ||
    2426      534980 :                     (PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitFlowRateAndCapacity)) {
    2427             :                     // If dehumidifying, compare total cooling to the limit
    2428           0 :                     if (PurchAir(PurchAirNum).SupplyHumRat < PurchAir(PurchAirNum).MixedAirHumRat) { // Dehumidifying
    2429           0 :                         CoolTotOutput = SupplyMassFlowRate * (MixedAirEnthalpy - SupplyEnthalpy);
    2430           0 :                         if ((CoolTotOutput) > PurchAir(PurchAirNum).MaxCoolTotCap) {
    2431           0 :                             CoolTotOutput = PurchAir(PurchAirNum).MaxCoolTotCap;
    2432           0 :                             SupplyEnthalpy = MixedAirEnthalpy - CoolTotOutput / SupplyMassFlowRate;
    2433             :                             // Adjust output based on dehumidification control type
    2434           0 :                             switch (PurchAir(PurchAirNum).DehumidCtrlType) {
    2435           0 :                             case HumControl::ConstantSensibleHeatRatio: {
    2436             :                                 // Adjust both supply temp and humidity ratio to maintain SHR
    2437             :                                 // SHR = CoolSensOutput/CoolTotOutput
    2438             :                                 // CoolSensOutput = SHR*CoolTotOutput
    2439           0 :                                 CpAir = PsyCpAirFnW(PurchAir(PurchAirNum).MixedAirHumRat);
    2440           0 :                                 CoolSensOutput = CoolTotOutput * PurchAir(PurchAirNum).CoolSHR;
    2441           0 :                                 PurchAir(PurchAirNum).SupplyTemp = PurchAir(PurchAirNum).MixedAirTemp - CoolSensOutput / (CpAir * SupplyMassFlowRate);
    2442             :                                 // This is the cooling mode, so SupplyTemp can't be more than MixedAirTemp
    2443           0 :                                 PurchAir(PurchAirNum).SupplyTemp = min(PurchAir(PurchAirNum).SupplyTemp, PurchAir(PurchAirNum).MixedAirTemp);
    2444             :                                 //  Limit for overdrying (avoid Pysch errors which occur if SupplyEnthalpy is too low for SupplyTemp)
    2445           0 :                                 SupplyEnthalpy = max(SupplyEnthalpy, PsyHFnTdbW(PurchAir(PurchAirNum).SupplyTemp, 0.00001));
    2446           0 :                                 PurchAir(PurchAirNum).SupplyHumRat = PsyWFnTdbH(state, PurchAir(PurchAirNum).SupplyTemp, SupplyEnthalpy, RoutineName);
    2447           0 :                             } break;
    2448           0 :                             case HumControl::Humidistat: {
    2449             :                                 // Keep supply temp and adjust humidity ratio to reduce load
    2450           0 :                                 PurchAir(PurchAirNum).SupplyHumRat = PsyWFnTdbH(state, PurchAir(PurchAirNum).SupplyTemp, SupplyEnthalpy, RoutineName);
    2451           0 :                             } break;
    2452           0 :                             case HumControl::None:
    2453             :                             case HumControl::ConstantSupplyHumidityRatio: {
    2454             :                                 // Keep humidity ratio and adjust supply temp
    2455             :                                 // Check if latent output exceeds capacity
    2456           0 :                                 CpAir = PsyCpAirFnW(PurchAir(PurchAirNum).MixedAirHumRat);
    2457           0 :                                 CoolSensOutput = SupplyMassFlowRate * CpAir * (PurchAir(PurchAirNum).MixedAirTemp - PurchAir(PurchAirNum).SupplyTemp);
    2458           0 :                                 CoolLatOutput = CoolTotOutput - CoolSensOutput;
    2459           0 :                                 if (CoolLatOutput >= PurchAir(PurchAirNum).MaxCoolTotCap) {
    2460           0 :                                     PurchAir(PurchAirNum).SupplyTemp = PurchAir(PurchAirNum).MixedAirTemp;
    2461           0 :                                     PurchAir(PurchAirNum).SupplyHumRat =
    2462           0 :                                         PsyWFnTdbH(state, PurchAir(PurchAirNum).SupplyTemp, SupplyEnthalpy, RoutineName);
    2463           0 :                                     CoolLatOutput = PurchAir(PurchAirNum).MaxCoolTotCap;
    2464             :                                 } else {
    2465           0 :                                     PurchAir(PurchAirNum).SupplyTemp = PsyTdbFnHW(SupplyEnthalpy, PurchAir(PurchAirNum).SupplyHumRat);
    2466             :                                     // This is the cooling mode, so SupplyTemp can't be more than MixedAirTemp
    2467           0 :                                     PurchAir(PurchAirNum).SupplyTemp = min(PurchAir(PurchAirNum).SupplyTemp, PurchAir(PurchAirNum).MixedAirTemp);
    2468             :                                 }
    2469           0 :                             } break;
    2470           0 :                             default:
    2471           0 :                                 break;
    2472             :                             }
    2473             :                             // Limit supply humidity ratio to saturation at supply outlet temp
    2474             :                             // If saturation exceeded, then honor capacity limit and set to dew point at supplyenthalpy
    2475             : 
    2476           0 :                             SupplyHumRatOrig = PurchAir(PurchAirNum).SupplyHumRat;
    2477           0 :                             SupplyHumRatSat = PsyWFnTdbRhPb(state, PurchAir(PurchAirNum).SupplyTemp, 1.0, state.dataEnvrn->OutBaroPress, RoutineName);
    2478           0 :                             if (SupplyHumRatSat < SupplyHumRatOrig) {
    2479           0 :                                 PurchAir(PurchAirNum).SupplyTemp = PsyTsatFnHPb(state, SupplyEnthalpy, state.dataEnvrn->OutBaroPress, RoutineName);
    2480             : 
    2481             :                                 // This is the cooling mode, so SupplyTemp can't be more than MixedAirTemp
    2482           0 :                                 PurchAir(PurchAirNum).SupplyTemp = min(PurchAir(PurchAirNum).SupplyTemp, PurchAir(PurchAirNum).MixedAirTemp);
    2483           0 :                                 PurchAir(PurchAirNum).SupplyHumRat = PsyWFnTdbH(state, PurchAir(PurchAirNum).SupplyTemp, SupplyEnthalpy, RoutineName);
    2484           0 :                                 SupplyEnthalpy = PsyHFnTdbW(PurchAir(PurchAirNum).SupplyTemp, PurchAir(PurchAirNum).SupplyHumRat);
    2485             :                                 // CpAir = PsyCpAirFnW(MixedAirHumRat)
    2486             :                                 // CoolSensOutput = SupplyMassFlowRate * CpAir * (MixedAirTemp - SupplyTemp)
    2487             :                                 // CoolTotOutput = SupplyMassFlowRate * (MixedAirEnthalpy - SupplyEnthalpy)
    2488             :                             }
    2489             :                         }    // Capacity limit exceeded
    2490             :                     } else { // Not dehumidifying
    2491             :                         // If not dehumidifying, compare sensible cooling to the limit
    2492             :                         // This section will only increase supply temp, so no need to recheck for super-saturation
    2493           0 :                         CpAir = PsyCpAirFnW(PurchAir(PurchAirNum).MixedAirHumRat);
    2494           0 :                         CoolSensOutput = SupplyMassFlowRate * CpAir * (PurchAir(PurchAirNum).MixedAirTemp - PurchAir(PurchAirNum).SupplyTemp);
    2495           0 :                         if (CoolSensOutput >= PurchAir(PurchAirNum).MaxCoolTotCap) {
    2496           0 :                             CoolSensOutput = PurchAir(PurchAirNum).MaxCoolTotCap;
    2497           0 :                             PurchAir(PurchAirNum).SupplyTemp = PurchAir(PurchAirNum).MixedAirTemp - CoolSensOutput / (SupplyMassFlowRate * CpAir);
    2498             :                         } // Capacity limit exceeded
    2499             :                     }     // Dehumidifying or not
    2500             :                 }         // Capacity limit active
    2501             : 
    2502             :             } else { // SupplyMassFlowRate is zero
    2503        5337 :                 SupplyEnthalpy = MixedAirEnthalpy;
    2504        5337 :                 PurchAir(PurchAirNum).SupplyHumRat = PurchAir(PurchAirNum).MixedAirHumRat;
    2505        5337 :                 PurchAir(PurchAirNum).SupplyTemp = PurchAir(PurchAirNum).MixedAirTemp;
    2506        5337 :                 CoolSensOutput = 0.0;
    2507        5337 :                 CoolTotOutput = 0.0;
    2508             :             }
    2509             :             // Heating or no-load operation
    2510             :         } else { // Heating or no-load case
    2511     2680373 :             if ((MinOASensOutput < QZnHeatSP) &&
    2512     1144443 :                 (state.dataHeatBalFanSys->TempControlType(ControlledZoneNum) != HVAC::ThermostatType::SingleCooling)) {
    2513      759612 :                 OperatingMode = OpMode::Heat;
    2514             :             } else { // DeadBand mode shuts off heat recovery and economizer
    2515      776318 :                 OperatingMode = OpMode::DeadBand;
    2516             :             }
    2517             :             // Calculate supply mass flow, temp and humidity with the following constraints:
    2518             :             //  Max heating supply temp
    2519             :             //  Max sensible heating capacity
    2520             :             //  Max heating airflow
    2521             :             //  Max heating supply humrat (and Min cooling supply humrat)
    2522             :             //  Min OA mass flow rate
    2523             : 
    2524             :             // Check if OA flow rate greater than max heating airflow limit
    2525     1535930 :             if (((PurchAir(PurchAirNum).HeatingLimit == LimitType::LimitFlowRate) ||
    2526     1544737 :                  (PurchAir(PurchAirNum).HeatingLimit == LimitType::LimitFlowRateAndCapacity)) &&
    2527        8807 :                 (OAMassFlowRate > PurchAir(PurchAirNum).MaxHeatMassFlowRate)) {
    2528           0 :                 OAVolFlowRate = OAMassFlowRate / state.dataEnvrn->StdRhoAir;
    2529           0 :                 if (PurchAir(PurchAirNum).OAFlowMaxHeatOutputError < 1) {
    2530           0 :                     ++PurchAir(PurchAirNum).OAFlowMaxHeatOutputError;
    2531           0 :                     ShowWarningError(state,
    2532           0 :                                      format("{} \"{}\" Requested outdoor air flow rate = {:.5T} [m3/s] exceeds limit.",
    2533           0 :                                             PurchAir(PurchAirNum).cObjectName,
    2534           0 :                                             PurchAir(PurchAirNum).Name,
    2535             :                                             OAVolFlowRate));
    2536           0 :                     ShowContinueError(
    2537             :                         state,
    2538           0 :                         format(" Will be reduced to the Maximum Heating Air Flow Rate = {:.5T} [m3/s]", PurchAir(PurchAirNum).MaxHeatVolFlowRate));
    2539           0 :                     ShowContinueErrorTimeStamp(state, "");
    2540             :                 } else {
    2541           0 :                     ShowRecurringWarningErrorAtEnd(
    2542             :                         state,
    2543           0 :                         PurchAir(PurchAirNum).cObjectName + " \"" + PurchAir(PurchAirNum).Name +
    2544             :                             "\" Requested outdoor air flow rate [m3/s] reduced to Maximum Heating Air Flow Rate warning continues...",
    2545           0 :                         PurchAir(PurchAirNum).OAFlowMaxHeatOutputIndex,
    2546             :                         OAVolFlowRate);
    2547             :                 }
    2548           0 :                 OAMassFlowRate = PurchAir(PurchAirNum).MaxHeatMassFlowRate;
    2549             :             }
    2550             : 
    2551     1535930 :             SupplyMassFlowRate = OAMassFlowRate;
    2552             : 
    2553             :             // Determine supply mass flow rate
    2554             :             // Mass flow rate to meet sensible load, at Minimum Cooling Supply Air Temperature
    2555     1535930 :             SupplyMassFlowRateForHeat = 0.0;
    2556     1535930 :             if ((HeatOn) && (OperatingMode == OpMode::Heat)) {
    2557      759612 :                 CpAir = PsyCpAirFnW(thisZoneHB.airHumRat);
    2558      759612 :                 DeltaT = (PurchAir(PurchAirNum).MaxHeatSuppAirTemp - state.dataLoopNodes->Node(ZoneNodeNum).Temp);
    2559      759612 :                 if (DeltaT > HVAC::SmallTempDiff) {
    2560      759612 :                     SupplyMassFlowRateForHeat = QZnHeatSP / CpAir / DeltaT;
    2561             :                 }
    2562             :             }
    2563             : 
    2564             :             // Mass flow rate to meet dehumidification load, if applicable, at Minimum Cooling Supply Humidity Ratio
    2565             :             // This section is the heating/deadband section, so dehumidification should activate
    2566             :             //   only if dehumidification control = humidistat
    2567             :             //   and if humidification control = humidistat or none or if operating in deadband mode
    2568     1535930 :             SupplyMassFlowRateForDehum = 0.0;
    2569     1535930 :             if (CoolOn) {
    2570     1531966 :                 if (PurchAir(PurchAirNum).DehumidCtrlType == HumControl::Humidistat) {
    2571        8956 :                     if ((PurchAir(PurchAirNum).HumidCtrlType == HumControl::Humidistat) ||
    2572        8956 :                         (PurchAir(PurchAirNum).HumidCtrlType == HumControl::None) || (OperatingMode == OpMode::DeadBand)) {
    2573        8956 :                         MdotZnDehumidSP = state.dataZoneEnergyDemand->ZoneSysMoistureDemand(ControlledZoneNum).RemainingOutputReqToDehumidSP;
    2574        8956 :                         DeltaHumRat = (PurchAir(PurchAirNum).MinCoolSuppAirHumRat - state.dataLoopNodes->Node(ZoneNodeNum).HumRat);
    2575        8956 :                         if ((DeltaHumRat < -SmallDeltaHumRat) && (MdotZnDehumidSP < 0.0)) {
    2576         447 :                             SupplyMassFlowRateForDehum = MdotZnDehumidSP / DeltaHumRat;
    2577             :                         }
    2578             :                     }
    2579             :                 }
    2580             :             }
    2581             : 
    2582             :             // Mass flow rate to meet humidification load, if applicable, at Maximum Heating Supply Humidity Ratio
    2583     1535930 :             SupplyMassFlowRateForHumid = 0.0;
    2584     1535930 :             if (HeatOn) {
    2585     1535930 :                 if (PurchAir(PurchAirNum).HumidCtrlType == HumControl::Humidistat) {
    2586        4046 :                     MdotZnHumidSP = state.dataZoneEnergyDemand->ZoneSysMoistureDemand(ControlledZoneNum).RemainingOutputReqToHumidSP;
    2587        4046 :                     DeltaHumRat = (PurchAir(PurchAirNum).MaxHeatSuppAirHumRat - state.dataLoopNodes->Node(ZoneNodeNum).HumRat);
    2588        4046 :                     if ((DeltaHumRat > SmallDeltaHumRat) && (MdotZnHumidSP > 0.0)) {
    2589        2810 :                         SupplyMassFlowRateForHumid = MdotZnHumidSP / DeltaHumRat;
    2590             :                     }
    2591             :                 }
    2592             :             }
    2593             : 
    2594             :             // If heating capacity is limited to zero, SupplyMassFlowRate* should be set to zero
    2595     1535930 :             if (((PurchAir(PurchAirNum).HeatingLimit == LimitType::LimitCapacity) ||
    2596     1535930 :                  (PurchAir(PurchAirNum).HeatingLimit == LimitType::LimitFlowRateAndCapacity)) &&
    2597           0 :                 (PurchAir(PurchAirNum).MaxHeatSensCap == 0)) {
    2598           0 :                 SupplyMassFlowRateForHeat = 0;
    2599           0 :                 SupplyMassFlowRateForDehum = 0;
    2600           0 :                 SupplyMassFlowRateForHumid = 0;
    2601             :             }
    2602             : 
    2603             :             // Supply mass flow is greatest of these, but limit to heating max flow rate, if applicable
    2604     1535930 :             SupplyMassFlowRate = max(0.0, OAMassFlowRate, SupplyMassFlowRateForHeat, SupplyMassFlowRateForDehum, SupplyMassFlowRateForHumid);
    2605             :             // EMS override point  Purch air massflow rate..... but only if unit is on, i.e. SupplyMassFlowRate>0.0
    2606     1535930 :             if (PurchAir(PurchAirNum).EMSOverrideMdotOn) {
    2607      162170 :                 SupplyMassFlowRate = PurchAir(PurchAirNum).EMSValueMassFlowRate;
    2608      162170 :                 OAMassFlowRate = min(OAMassFlowRate, SupplyMassFlowRate);
    2609             :             }
    2610     1535930 :             if (((PurchAir(PurchAirNum).HeatingLimit == LimitType::LimitFlowRate) ||
    2611     1544737 :                  (PurchAir(PurchAirNum).HeatingLimit == LimitType::LimitFlowRateAndCapacity)) &&
    2612        8807 :                 (PurchAir(PurchAirNum).MaxHeatMassFlowRate > 0.0)) {
    2613        8806 :                 SupplyMassFlowRate = min(SupplyMassFlowRate, PurchAir(PurchAirNum).MaxHeatMassFlowRate);
    2614             :             }
    2615             : 
    2616     1535930 :             if (SupplyMassFlowRate <= HVAC::VerySmallMassFlow) SupplyMassFlowRate = 0.0;
    2617             : 
    2618             :             // Calculate mixed air conditions
    2619     1535930 :             CalcPurchAirMixedAir(state,
    2620             :                                  PurchAirNum,
    2621             :                                  OAMassFlowRate,
    2622             :                                  SupplyMassFlowRate,
    2623     1535930 :                                  PurchAir(PurchAirNum).MixedAirTemp,
    2624     1535930 :                                  PurchAir(PurchAirNum).MixedAirHumRat,
    2625             :                                  MixedAirEnthalpy,
    2626             :                                  OperatingMode);
    2627             : 
    2628             :             // Calculate supply air conditions using final massflow rate, imposing capacity limits if specified
    2629             :             // If capacity limits are exceeded, keep massflow rate where it is and adjust supply temp
    2630     1535930 :             if (SupplyMassFlowRate > 0.0) {
    2631      813748 :                 if ((HeatOn) && (OperatingMode == OpMode::Heat)) {
    2632             :                     // Calculate supply temp at SupplyMassFlowRate and check limit on Maximum Heating Supply Air Temperature
    2633      759612 :                     CpAir = PsyCpAirFnW(thisZoneHB.airHumRat);
    2634      759612 :                     PurchAir(PurchAirNum).SupplyTemp = QZnHeatSP / (CpAir * SupplyMassFlowRate) + state.dataLoopNodes->Node(ZoneNodeNum).Temp;
    2635      759612 :                     PurchAir(PurchAirNum).SupplyTemp = min(PurchAir(PurchAirNum).SupplyTemp, PurchAir(PurchAirNum).MaxHeatSuppAirTemp);
    2636             :                     // This is the heating mode, so SupplyTemp can't be less than MixedAirTemp
    2637      759612 :                     PurchAir(PurchAirNum).SupplyTemp = max(PurchAir(PurchAirNum).SupplyTemp, PurchAir(PurchAirNum).MixedAirTemp);
    2638             :                     // Check max heating capacity, if specified
    2639     1519224 :                     if ((PurchAir(PurchAirNum).HeatingLimit == LimitType::LimitCapacity) ||
    2640      759612 :                         (PurchAir(PurchAirNum).HeatingLimit == LimitType::LimitFlowRateAndCapacity)) {
    2641           0 :                         CpAir = PsyCpAirFnW(PurchAir(PurchAirNum).MixedAirHumRat);
    2642           0 :                         HeatSensOutput = SupplyMassFlowRate * CpAir * (PurchAir(PurchAirNum).SupplyTemp - PurchAir(PurchAirNum).MixedAirTemp);
    2643           0 :                         if (HeatSensOutput > PurchAir(PurchAirNum).MaxHeatSensCap) {
    2644           0 :                             PurchAir(PurchAirNum).SupplyTemp =
    2645           0 :                                 PurchAir(PurchAirNum).MaxHeatSensCap / (SupplyMassFlowRate * CpAir) + PurchAir(PurchAirNum).MixedAirTemp;
    2646           0 :                             HeatSensOutput = PurchAir(PurchAirNum).MaxHeatSensCap;
    2647             :                         }
    2648             :                     }
    2649             :                 } else { // Heat is off or operating mode is deadband (i.e. don't do any heating)
    2650       54136 :                     PurchAir(PurchAirNum).SupplyTemp = PurchAir(PurchAirNum).MixedAirTemp;
    2651             :                 }
    2652             : 
    2653             :                 // Set supply humidity ratio first for heating/humidification
    2654      813748 :                 PurchAir(PurchAirNum).SupplyHumRat = PurchAir(PurchAirNum).MixedAirHumRat;
    2655      813748 :                 switch (PurchAir(PurchAirNum).HumidCtrlType) {
    2656       55841 :                 case HumControl::None: {
    2657       55841 :                     PurchAir(PurchAirNum).SupplyHumRat = PurchAir(PurchAirNum).MixedAirHumRat;
    2658       55841 :                 } break;
    2659        3910 :                 case HumControl::Humidistat: {
    2660        3910 :                     MdotZnHumidSP = state.dataZoneEnergyDemand->ZoneSysMoistureDemand(ControlledZoneNum).RemainingOutputReqToHumidSP;
    2661        3910 :                     SupplyHumRatForHumid = MdotZnHumidSP / SupplyMassFlowRate + state.dataLoopNodes->Node(ZoneNodeNum).HumRat;
    2662        3910 :                     SupplyHumRatForHumid = min(SupplyHumRatForHumid, PurchAir(PurchAirNum).MaxHeatSuppAirHumRat);
    2663        3910 :                     PurchAir(PurchAirNum).SupplyHumRat = max(PurchAir(PurchAirNum).SupplyHumRat, SupplyHumRatForHumid);
    2664        3910 :                 } break;
    2665      753997 :                 case HumControl::ConstantSupplyHumidityRatio: {
    2666      753997 :                     if (OperatingMode == OpMode::Heat) {
    2667             :                         // If this results in dehumidification, must check cooling capacity limit
    2668      701971 :                         if (PurchAir(PurchAirNum).MixedAirHumRat > PurchAir(PurchAirNum).MaxHeatSuppAirHumRat) {
    2669      141778 :                             if ((PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitCapacity) ||
    2670       70889 :                                 (PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitFlowRateAndCapacity)) {
    2671           0 :                                 PurchAir(PurchAirNum).SupplyHumRat = PurchAir(PurchAirNum).MaxHeatSuppAirHumRat;
    2672           0 :                                 SupplyEnthalpy = PsyHFnTdbW(PurchAir(PurchAirNum).SupplyTemp, PurchAir(PurchAirNum).SupplyHumRat);
    2673           0 :                                 CoolTotOutput = SupplyMassFlowRate * (MixedAirEnthalpy - SupplyEnthalpy);
    2674           0 :                                 CpAir = PsyCpAirFnW(PurchAir(PurchAirNum).MixedAirHumRat);
    2675           0 :                                 CoolSensOutput = SupplyMassFlowRate * CpAir * (PurchAir(PurchAirNum).MixedAirTemp - PurchAir(PurchAirNum).SupplyTemp);
    2676           0 :                                 CoolLatOutput = CoolTotOutput - CoolSensOutput;
    2677           0 :                                 if (CoolLatOutput >= PurchAir(PurchAirNum).MaxCoolTotCap) {
    2678           0 :                                     CoolLatOutput = PurchAir(PurchAirNum).MaxCoolTotCap;
    2679           0 :                                     CoolTotOutput = CoolSensOutput + CoolLatOutput;
    2680           0 :                                     SupplyEnthalpy = MixedAirEnthalpy - CoolTotOutput / SupplyMassFlowRate;
    2681           0 :                                     PurchAir(PurchAirNum).SupplyHumRat =
    2682           0 :                                         PsyWFnTdbH(state, PurchAir(PurchAirNum).SupplyTemp, SupplyEnthalpy, RoutineName);
    2683             :                                 }
    2684             :                             } else {
    2685       70889 :                                 PurchAir(PurchAirNum).SupplyHumRat = PurchAir(PurchAirNum).MaxHeatSuppAirHumRat;
    2686             :                             }
    2687             :                         } else {
    2688      631082 :                             PurchAir(PurchAirNum).SupplyHumRat = PurchAir(PurchAirNum).MaxHeatSuppAirHumRat;
    2689             :                         }
    2690             :                     } else {
    2691       52026 :                         PurchAir(PurchAirNum).SupplyHumRat = PurchAir(PurchAirNum).MixedAirHumRat;
    2692             :                     }
    2693      753997 :                 } break;
    2694           0 :                 default: {
    2695           0 :                     PurchAir(PurchAirNum).SupplyHumRat = PurchAir(PurchAirNum).MixedAirHumRat;
    2696           0 :                 } break;
    2697             :                 }
    2698      813748 :                 SupplyEnthalpy = PsyHFnTdbW(PurchAir(PurchAirNum).SupplyTemp, PurchAir(PurchAirNum).SupplyHumRat);
    2699             : 
    2700             :                 // Check supply humidity ratio for dehumidification (SupplyHumRatForHumid should always be < SupplyHumRatForDehum)
    2701             :                 // This section is the heating/deadband section, so dehumidification should activate
    2702             :                 //   only if dehumidification control = humidistat
    2703             :                 //   and if humidification control = humidistat or none or if operating in deadband mode
    2704      813748 :                 if (CoolOn) {
    2705      809848 :                     if (PurchAir(PurchAirNum).DehumidCtrlType == HumControl::Humidistat) {
    2706        8831 :                         if ((PurchAir(PurchAirNum).HumidCtrlType == HumControl::Humidistat) ||
    2707        8831 :                             (PurchAir(PurchAirNum).HumidCtrlType == HumControl::None) || (OperatingMode == OpMode::DeadBand)) {
    2708        8831 :                             MdotZnDehumidSP = state.dataZoneEnergyDemand->ZoneSysMoistureDemand(ControlledZoneNum).RemainingOutputReqToDehumidSP;
    2709        8831 :                             SupplyHumRatForDehum = MdotZnDehumidSP / SupplyMassFlowRate + state.dataLoopNodes->Node(ZoneNodeNum).HumRat;
    2710        8831 :                             SupplyHumRatForDehum = max(SupplyHumRatForDehum, PurchAir(PurchAirNum).MinCoolSuppAirHumRat);
    2711        8831 :                             PurchAir(PurchAirNum).SupplyHumRat = min(PurchAir(PurchAirNum).SupplyHumRat, SupplyHumRatForDehum);
    2712        8831 :                             SupplyEnthalpy = PsyHFnTdbW(PurchAir(PurchAirNum).SupplyTemp, PurchAir(PurchAirNum).SupplyHumRat);
    2713        8831 :                             if (PurchAir(PurchAirNum).SupplyHumRat < PurchAir(PurchAirNum).MixedAirHumRat) {
    2714             :                                 // At this point, the system is heating or deadband but dehumidifying, check max cooling cap limit
    2715         447 :                                 CpAir = PsyCpAirFnW(PurchAir(PurchAirNum).MixedAirHumRat);
    2716         447 :                                 SensOutput = SupplyMassFlowRate * CpAir * (PurchAir(PurchAirNum).SupplyTemp - PurchAir(PurchAirNum).MixedAirTemp);
    2717         447 :                                 LatOutput = SupplyMassFlowRate * (SupplyEnthalpy - MixedAirEnthalpy) - SensOutput;
    2718         894 :                                 if ((PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitCapacity) ||
    2719         447 :                                     (PurchAir(PurchAirNum).CoolingLimit == LimitType::LimitFlowRateAndCapacity)) {
    2720           0 :                                     if (LatOutput > PurchAir(PurchAirNum).MaxCoolTotCap) {
    2721           0 :                                         LatOutput = PurchAir(PurchAirNum).MaxCoolTotCap;
    2722           0 :                                         SupplyEnthalpy = MixedAirEnthalpy + (LatOutput + SensOutput) / SupplyMassFlowRate;
    2723           0 :                                         PurchAir(PurchAirNum).SupplyHumRat =
    2724           0 :                                             PsyWFnTdbH(state, PurchAir(PurchAirNum).SupplyTemp, SupplyEnthalpy, RoutineName);
    2725             :                                     }
    2726             :                                 }
    2727             :                             }
    2728             :                         }
    2729             :                     }
    2730             :                 }
    2731             : 
    2732             :                 //   Limit supply humidity ratio to saturation at supply outlet temp
    2733             : 
    2734      813748 :                 SupplyHumRatOrig = PurchAir(PurchAirNum).SupplyHumRat;
    2735      813748 :                 PurchAir(PurchAirNum).SupplyHumRat =
    2736      813748 :                     min(PurchAir(PurchAirNum).SupplyHumRat,
    2737      813748 :                         PsyWFnTdbRhPb(state, PurchAir(PurchAirNum).SupplyTemp, 1.0, state.dataEnvrn->OutBaroPress, RoutineName));
    2738      813748 :                 SupplyEnthalpy = PsyHFnTdbW(PurchAir(PurchAirNum).SupplyTemp, PurchAir(PurchAirNum).SupplyHumRat);
    2739             : 
    2740             :             } else { // SupplyMassFlowRate is zero
    2741      722182 :                 SupplyEnthalpy = MixedAirEnthalpy;
    2742      722182 :                 PurchAir(PurchAirNum).SupplyHumRat = PurchAir(PurchAirNum).MixedAirHumRat;
    2743      722182 :                 PurchAir(PurchAirNum).SupplyTemp = PurchAir(PurchAirNum).MixedAirTemp;
    2744      722182 :                 HeatSensOutput = 0.0;
    2745             :             }
    2746             : 
    2747             :         } // Cooling or heating required
    2748             : 
    2749     2076247 :         if (SupplyMassFlowRate > 0.0) {
    2750             :             // EMS override point  Purch air supply temp and humidty ratio ..... but only if unit is on, SupplyMassFlowRate>0.0
    2751     1348728 :             if (PurchAir(PurchAirNum).EMSOverrideSupplyTempOn) {
    2752      241986 :                 PurchAir(PurchAirNum).SupplyTemp = PurchAir(PurchAirNum).EMSValueSupplyTemp;
    2753             :             }
    2754     1348728 :             if (PurchAir(PurchAirNum).EMSOverrideSupplyHumRatOn) {
    2755      241986 :                 PurchAir(PurchAirNum).SupplyHumRat = PurchAir(PurchAirNum).EMSValueSupplyHumRat;
    2756             :             }
    2757     1348728 :             SupplyEnthalpy = PsyHFnTdbW(PurchAir(PurchAirNum).SupplyTemp, PurchAir(PurchAirNum).SupplyHumRat);
    2758             : 
    2759             :             // compute coil loads
    2760     1436543 :             if ((PurchAir(PurchAirNum).SupplyHumRat == PurchAir(PurchAirNum).MixedAirHumRat) &&
    2761       87815 :                 (PurchAir(PurchAirNum).SupplyTemp == PurchAir(PurchAirNum).MixedAirTemp)) {
    2762             :                 // If no change in humrat or temp, then set loads to zero
    2763        1715 :                 PurchAir(PurchAirNum).SenCoilLoad = 0.0;
    2764        1715 :                 PurchAir(PurchAirNum).LatCoilLoad = 0.0;
    2765     1433113 :             } else if ((PurchAir(PurchAirNum).SupplyHumRat == PurchAir(PurchAirNum).MixedAirHumRat) &&
    2766       86100 :                        (PurchAir(PurchAirNum).SupplyTemp != PurchAir(PurchAirNum).MixedAirTemp)) {
    2767             :                 // If no change in humrat, then set latent load to zero and use enthalpies to calculate sensible load
    2768       86100 :                 PurchAir(PurchAirNum).SenCoilLoad = SupplyMassFlowRate * (SupplyEnthalpy - MixedAirEnthalpy);
    2769       86100 :                 PurchAir(PurchAirNum).LatCoilLoad = 0.0;
    2770             :             } else {
    2771     1260913 :                 CpAir = PsyCpAirFnW(PurchAir(PurchAirNum).MixedAirHumRat);
    2772     2521826 :                 PurchAir(PurchAirNum).SenCoilLoad =
    2773     1260913 :                     SupplyMassFlowRate * CpAir * (PurchAir(PurchAirNum).SupplyTemp - PurchAir(PurchAirNum).MixedAirTemp);
    2774     1260913 :                 PurchAir(PurchAirNum).LatCoilLoad = SupplyMassFlowRate * (SupplyEnthalpy - MixedAirEnthalpy) - PurchAir(PurchAirNum).SenCoilLoad;
    2775             :             }
    2776             : 
    2777             :             // Apply heating and cooling availability schedules to sensible load
    2778     1348728 :             if (((PurchAir(PurchAirNum).SenCoilLoad > 0.0) && !HeatOn) || ((PurchAir(PurchAirNum).SenCoilLoad < 0.0) && !CoolOn)) {
    2779             :                 // Coil is off
    2780           0 :                 PurchAir(PurchAirNum).SenCoilLoad = 0.0;
    2781           0 :                 PurchAir(PurchAirNum).SupplyTemp = PurchAir(PurchAirNum).MixedAirTemp;
    2782             :             }
    2783             : 
    2784             :             // Apply heating and cooling availability schedules to latent load
    2785     1348728 :             if (((PurchAir(PurchAirNum).LatCoilLoad > 0.0) && !HeatOn) || ((PurchAir(PurchAirNum).LatCoilLoad < 0.0) && !CoolOn)) {
    2786             :                 // Coil is off
    2787         307 :                 PurchAir(PurchAirNum).LatCoilLoad = 0.0;
    2788         307 :                 PurchAir(PurchAirNum).SupplyHumRat = PurchAir(PurchAirNum).MixedAirHumRat;
    2789             :             }
    2790             : 
    2791             :             // Double-check if saturation exceeded, then thow warning, shouldn't happen here, don't reset, just warn
    2792             : 
    2793     1348728 :             SupplyHumRatOrig = PurchAir(PurchAirNum).SupplyHumRat;
    2794     1348728 :             SupplyHumRatSat = PsyWFnTdbRhPb(state, PurchAir(PurchAirNum).SupplyTemp, 1.0, state.dataEnvrn->OutBaroPress, RoutineName);
    2795             : 
    2796     1348728 :             DeltaHumRat = SupplyHumRatOrig - SupplyHumRatSat;
    2797     1348728 :             if (DeltaHumRat > SmallDeltaHumRat) {
    2798           0 :                 if (PurchAir(PurchAirNum).SaturationOutputError < 1) {
    2799           0 :                     ++PurchAir(PurchAirNum).SaturationOutputError;
    2800           0 :                     ShowWarningError(state,
    2801           0 :                                      format("{} \"{}\" Supply humidity ratio = {:.5T} exceeds saturation limit {:.5T} [kgWater/kgDryAir]",
    2802           0 :                                             PurchAir(PurchAirNum).cObjectName,
    2803           0 :                                             PurchAir(PurchAirNum).Name,
    2804             :                                             SupplyHumRatOrig,
    2805             :                                             SupplyHumRatSat));
    2806           0 :                     ShowContinueError(state, " Simulation continuing . . . ");
    2807           0 :                     ShowContinueErrorTimeStamp(state, "");
    2808             :                 } else {
    2809           0 :                     ShowRecurringWarningErrorAtEnd(
    2810             :                         state,
    2811           0 :                         PurchAir(PurchAirNum).cObjectName + " \"" + PurchAir(PurchAirNum).Name +
    2812             :                             "\" Supply humidity ratio exceeds saturation limit warning continues, delta max/min [kgWater/kgDryAir]...",
    2813           0 :                         PurchAir(PurchAirNum).SaturationOutputIndex,
    2814             :                         DeltaHumRat,
    2815             :                         DeltaHumRat);
    2816             :                 }
    2817             :             }
    2818             : 
    2819     1348728 :             SupplyEnthalpy = PsyHFnTdbW(PurchAir(PurchAirNum).SupplyTemp, PurchAir(PurchAirNum).SupplyHumRat);
    2820             : 
    2821     1348728 :             CpAir = PsyCpAirFnW(thisZoneHB.airHumRat);
    2822     1348728 :             SysOutputProvided = SupplyMassFlowRate * CpAir * (PurchAir(PurchAirNum).SupplyTemp - state.dataLoopNodes->Node(ZoneNodeNum).Temp);
    2823     1348728 :             MoistOutputProvided =
    2824     1348728 :                 SupplyMassFlowRate * (PurchAir(PurchAirNum).SupplyHumRat - state.dataLoopNodes->Node(ZoneNodeNum).HumRat); // Latent rate, kg/s
    2825             : 
    2826     1348728 :             PurchAir(PurchAirNum).SenOutputToZone = SysOutputProvided;
    2827     2697456 :             PurchAir(PurchAirNum).LatOutputToZone =
    2828     1348728 :                 SupplyMassFlowRate * (SupplyEnthalpy - state.dataLoopNodes->Node(ZoneNodeNum).Enthalpy) - PurchAir(PurchAirNum).SenOutputToZone;
    2829             : 
    2830     1348728 :             CpAir = PsyCpAirFnW(thisZoneHB.airHumRat);
    2831     1348728 :             if (PurchAir(PurchAirNum).OutdoorAir) {
    2832       29304 :                 PurchAir(PurchAirNum).OASenOutput =
    2833       14652 :                     OAMassFlowRate * CpAir * (state.dataLoopNodes->Node(OANodeNum).Temp - state.dataLoopNodes->Node(ZoneNodeNum).Temp);
    2834       14652 :                 PurchAir(PurchAirNum).OALatOutput =
    2835       14652 :                     OAMassFlowRate * (state.dataLoopNodes->Node(OANodeNum).Enthalpy - state.dataLoopNodes->Node(ZoneNodeNum).Enthalpy) -
    2836       14652 :                     PurchAir(PurchAirNum).OASenOutput;
    2837             :             } else {
    2838     1334076 :                 PurchAir(PurchAirNum).OASenOutput = 0.0;
    2839     1334076 :                 PurchAir(PurchAirNum).OALatOutput = 0.0;
    2840             :             }
    2841     1348728 :             if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
    2842      133236 :                 if (PurchAir(PurchAirNum).OutdoorAir) {
    2843           0 :                     state.dataLoopNodes->Node(InNodeNum).CO2 = ((SupplyMassFlowRate - OAMassFlowRate) * state.dataLoopNodes->Node(RecircNodeNum).CO2 +
    2844           0 :                                                                 OAMassFlowRate * state.dataLoopNodes->Node(OANodeNum).CO2) /
    2845             :                                                                SupplyMassFlowRate;
    2846             :                 } else {
    2847      133236 :                     state.dataLoopNodes->Node(InNodeNum).CO2 = state.dataLoopNodes->Node(RecircNodeNum).CO2;
    2848             :                 }
    2849             :             }
    2850     1348728 :             if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
    2851      117952 :                 if (PurchAir(PurchAirNum).OutdoorAir) {
    2852           0 :                     state.dataLoopNodes->Node(InNodeNum).GenContam =
    2853           0 :                         ((SupplyMassFlowRate - OAMassFlowRate) * state.dataLoopNodes->Node(RecircNodeNum).GenContam +
    2854           0 :                          OAMassFlowRate * state.dataLoopNodes->Node(OANodeNum).GenContam) /
    2855             :                         SupplyMassFlowRate;
    2856             :                 } else {
    2857      117952 :                     state.dataLoopNodes->Node(InNodeNum).GenContam = state.dataLoopNodes->Node(RecircNodeNum).GenContam;
    2858             :                 }
    2859             :             }
    2860             :         } else { // SupplyMassFlowRate = 0.0
    2861      727519 :             SysOutputProvided = 0.0;
    2862      727519 :             MoistOutputProvided = 0.0;
    2863             : 
    2864      727519 :             PurchAir(PurchAirNum).SenOutputToZone = 0.0;
    2865      727519 :             PurchAir(PurchAirNum).LatOutputToZone = 0.0;
    2866      727519 :             PurchAir(PurchAirNum).SenCoilLoad = 0.0;
    2867      727519 :             PurchAir(PurchAirNum).LatCoilLoad = 0.0;
    2868      727519 :             PurchAir(PurchAirNum).OASenOutput = 0.0;
    2869      727519 :             PurchAir(PurchAirNum).OALatOutput = 0.0;
    2870             : 
    2871      727519 :             PurchAir(PurchAirNum).MixedAirTemp = state.dataLoopNodes->Node(RecircNodeNum).Temp;
    2872      727519 :             PurchAir(PurchAirNum).MixedAirHumRat = state.dataLoopNodes->Node(RecircNodeNum).HumRat;
    2873      727519 :             if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
    2874             : 
    2875       47732 :                 state.dataLoopNodes->Node(InNodeNum).CO2 = state.dataLoopNodes->Node(ZoneNodeNum).CO2;
    2876             :             }
    2877      727519 :             if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
    2878       24552 :                 state.dataLoopNodes->Node(InNodeNum).GenContam = state.dataLoopNodes->Node(ZoneNodeNum).GenContam;
    2879             :             }
    2880             :         }
    2881             : 
    2882     2076247 :         state.dataLoopNodes->Node(InNodeNum).Temp = PurchAir(PurchAirNum).SupplyTemp;
    2883     2076247 :         state.dataLoopNodes->Node(InNodeNum).HumRat = PurchAir(PurchAirNum).SupplyHumRat;
    2884     2076247 :         state.dataLoopNodes->Node(InNodeNum).Enthalpy = SupplyEnthalpy;
    2885     2076247 :         state.dataLoopNodes->Node(InNodeNum).MassFlowRate = SupplyMassFlowRate;
    2886     2076247 :         if (PurchAir(PurchAirNum).OutdoorAir) state.dataLoopNodes->Node(OANodeNum).MassFlowRate = OAMassFlowRate;
    2887             : 
    2888             :     } else { // purchased air OFF
    2889             : 
    2890           0 :         SysOutputProvided = 0.0;
    2891           0 :         MoistOutputProvided = 0.0;
    2892           0 :         SupplyMassFlowRate = 0.0;
    2893           0 :         OAMassFlowRate = 0.0;
    2894           0 :         state.dataLoopNodes->Node(InNodeNum).Temp = state.dataLoopNodes->Node(ZoneNodeNum).Temp;
    2895           0 :         state.dataLoopNodes->Node(InNodeNum).HumRat = state.dataLoopNodes->Node(ZoneNodeNum).HumRat;
    2896           0 :         state.dataLoopNodes->Node(InNodeNum).Enthalpy = state.dataLoopNodes->Node(ZoneNodeNum).Enthalpy;
    2897           0 :         if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
    2898           0 :             state.dataLoopNodes->Node(InNodeNum).CO2 = state.dataLoopNodes->Node(ZoneNodeNum).CO2;
    2899             :         }
    2900           0 :         if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
    2901           0 :             state.dataLoopNodes->Node(InNodeNum).GenContam = state.dataLoopNodes->Node(ZoneNodeNum).GenContam;
    2902             :         }
    2903             : 
    2904           0 :         state.dataLoopNodes->Node(InNodeNum).MassFlowRate = 0.0;
    2905           0 :         if (PurchAir(PurchAirNum).OutdoorAir) state.dataLoopNodes->Node(OANodeNum).MassFlowRate = 0.0;
    2906           0 :         PurchAir(PurchAirNum).SenHeatRate = 0.0;
    2907           0 :         PurchAir(PurchAirNum).SenCoolRate = 0.0;
    2908           0 :         PurchAir(PurchAirNum).TotCoolRate = 0.0;
    2909             : 
    2910           0 :         PurchAir(PurchAirNum).SenOutputToZone = 0.0;
    2911           0 :         PurchAir(PurchAirNum).LatOutputToZone = 0.0;
    2912           0 :         PurchAir(PurchAirNum).SenCoilLoad = 0.0;
    2913           0 :         PurchAir(PurchAirNum).LatCoilLoad = 0.0;
    2914           0 :         PurchAir(PurchAirNum).OASenOutput = 0.0;
    2915           0 :         PurchAir(PurchAirNum).OALatOutput = 0.0;
    2916           0 :         PurchAir(PurchAirNum).MixedAirTemp = state.dataLoopNodes->Node(RecircNodeNum).Temp;
    2917           0 :         PurchAir(PurchAirNum).MixedAirHumRat = state.dataLoopNodes->Node(RecircNodeNum).HumRat;
    2918           0 :         PurchAir(PurchAirNum).SupplyTemp = state.dataLoopNodes->Node(InNodeNum).Temp;
    2919           0 :         PurchAir(PurchAirNum).SupplyHumRat = state.dataLoopNodes->Node(InNodeNum).HumRat;
    2920             :     }
    2921             : 
    2922     2076247 :     PurchAir(PurchAirNum).OutdoorAirMassFlowRate = OAMassFlowRate;
    2923     2076247 :     PurchAir(PurchAirNum).OutdoorAirVolFlowRateStdRho = OAMassFlowRate / state.dataEnvrn->StdRhoAir;
    2924     2076247 :     PurchAir(PurchAirNum).SupplyAirMassFlowRate = SupplyMassFlowRate;
    2925             : 
    2926     2076247 :     PurchAir(PurchAirNum).SupplyAirVolFlowRateStdRho = SupplyMassFlowRate / state.dataEnvrn->StdRhoAir;
    2927             : 
    2928     2076247 :     if (PurchAir(PurchAirNum).PlenumExhaustAirNodeNum > 0) {
    2929       15075 :         state.dataLoopNodes->Node(PurchAir(PurchAirNum).PlenumExhaustAirNodeNum).MassFlowRate = SupplyMassFlowRate;
    2930             :     }
    2931     2076247 :     state.dataLoopNodes->Node(RecircNodeNum).MassFlowRate = SupplyMassFlowRate;
    2932     2076247 : }
    2933             : 
    2934     2076247 : void CalcPurchAirMinOAMassFlow(EnergyPlusData &state,
    2935             :                                int const PurchAirNum, // index to ideal loads unit
    2936             :                                int const ZoneNum,     // index to zone
    2937             :                                Real64 &OAMassFlowRate // outside air mass flow rate [kg/s] from volume flow using std density
    2938             : )
    2939             : {
    2940             : 
    2941             :     // SUBROUTINE INFORMATION:
    2942             :     //       AUTHOR         M. Witte (GARD)
    2943             :     //       DATE WRITTEN   Jun 2011 (taken from HVACSingleDuctSystem.cc and adapted for Ideal Loads System)
    2944             :     //       MODIFIED       na
    2945             :     //       RE-ENGINEERED  na
    2946             : 
    2947             :     // PURPOSE OF THIS SUBROUTINE:
    2948             :     // Calculates the amount of outside air required based on optional user input.
    2949             :     // Zone multipliers have been applied in GetInput.
    2950             : 
    2951             :     // METHODOLOGY EMPLOYED:
    2952             :     // User input defines method used to calculate OA.
    2953             : 
    2954             :     // FUNCTION PARAMETER DEFINITIONS:
    2955     2076247 :     bool constexpr UseMinOASchFlag(true); // Always use min OA schedule in calculations.
    2956             : 
    2957             :     // FUNCTION LOCAL VARIABLE DECLARATIONS:
    2958             :     bool UseOccSchFlag;      // TRUE = use actual occupancy, FALSE = use total zone people
    2959             :     Real64 OAVolumeFlowRate; // outside air flow rate (m3/s)
    2960             : 
    2961     2076247 :     auto &PurchAir(state.dataPurchasedAirMgr->PurchAir);
    2962             : 
    2963     2076247 :     if (PurchAir(PurchAirNum).OutdoorAir) {
    2964             : 
    2965       14788 :         if (PurchAir(PurchAirNum).DCVType == DCV::OccupancySchedule) {
    2966        3697 :             UseOccSchFlag = true;
    2967             :         } else {
    2968       11091 :             UseOccSchFlag = false;
    2969             :         }
    2970             :         OAVolumeFlowRate =
    2971       14788 :             DataSizing::calcDesignSpecificationOutdoorAir(state, PurchAir(PurchAirNum).OARequirementsPtr, ZoneNum, UseOccSchFlag, UseMinOASchFlag);
    2972       14788 :         OAMassFlowRate = OAVolumeFlowRate * state.dataEnvrn->StdRhoAir;
    2973             : 
    2974             :         // If DCV with CO2SetPoint then check required OA flow to meet CO2 setpoint
    2975       14788 :         if (PurchAir(PurchAirNum).DCVType == DCV::CO2SetPoint) {
    2976           0 :             OAMassFlowRate = max(OAMassFlowRate, state.dataContaminantBalance->ZoneSysContDemand(ZoneNum).OutputRequiredToCO2SP);
    2977             :         }
    2978             : 
    2979       14788 :         if (OAMassFlowRate <= HVAC::VerySmallMassFlow) OAMassFlowRate = 0.0;
    2980             : 
    2981             :     } else { // No outdoor air
    2982     2061459 :         OAMassFlowRate = 0.0;
    2983             :     }
    2984     2076247 :     PurchAir(PurchAirNum).MinOAMassFlowRate = OAMassFlowRate;
    2985     2076247 : }
    2986             : 
    2987     2076247 : void CalcPurchAirMixedAir(EnergyPlusData &state,
    2988             :                           int const PurchAirNum,           // index to ideal loads unit
    2989             :                           Real64 const OAMassFlowRate,     // outside air mass flow rate [kg/s]
    2990             :                           Real64 const SupplyMassFlowRate, // supply air mass flow rate [kg/s]
    2991             :                           Real64 &MixedAirTemp,            // Mixed air dry bulb temperature [C]
    2992             :                           Real64 &MixedAirHumRat,          // Mixed air humidity ratio [kgWater/kgDryAir]
    2993             :                           Real64 &MixedAirEnthalpy,        // Mixed air enthalpy [J/kg]
    2994             :                           OpMode const OperatingMode       // current operating mode, Off, Heating, Cooling, or DeadBand
    2995             : )
    2996             : {
    2997             : 
    2998             :     // SUBROUTINE INFORMATION:
    2999             :     //       AUTHOR         M. Witte (GARD)
    3000             :     //       DATE WRITTEN   Sep 2011
    3001             :     //       MODIFIED       na
    3002             :     //       RE-ENGINEERED  na
    3003             : 
    3004             :     // PURPOSE OF THIS SUBROUTINE:
    3005             :     // Calculates the mixed air conditions, accounting for heat recovery.
    3006             : 
    3007             :     // SUBROUTINE PARAMETER DEFINITIONS:
    3008             :     static constexpr std::string_view RoutineName("CalcPurchAirMixedAir");
    3009             : 
    3010             :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    3011             :     int RecircNodeNum;           // Zone return air node
    3012             :     int OANodeNum;               // Outdoor air inlet node
    3013             :     Real64 RecircTemp;           // Recirculated air from zone dry bulb temperature [C]
    3014             :     Real64 RecircHumRat;         // Recirculated air from zone humidity ratio [kgWater/kgDryAir]
    3015             :     Real64 RecircEnthalpy;       // Recirculated air from zone enthalpy [J/kg]
    3016             :     Real64 RecircMassFlowRate;   // Recirculated air mass flow rate [kg/s]
    3017             :     Real64 OAInletTemp;          // Outdoor air inlet dry bulb temperature [C]
    3018             :     Real64 OAInletHumRat;        // Outdoor air inlet humidity ratio [kgWater/kgDryAir]
    3019             :     Real64 OAInletEnthalpy;      // Outdoor air inlet enthalpy [J/kg]
    3020             :     Real64 OAAfterHtRecTemp;     // Outdoor air after heat recovery to mixing box dry bulb temperature [C]
    3021             :     Real64 OAAfterHtRecHumRat;   // Outdoor air after heat recovery to mixing box humidity ratio [kgWater/kgDryAir]
    3022             :     Real64 OAAfterHtRecEnthalpy; // Outdoor air after heat recovery to mixing box enthalpy [J/kg]
    3023             :     bool HeatRecOn;
    3024             :     Real64 CpAir; // Specific heat [J/kg-C] reused in multiple places
    3025             : 
    3026     2076247 :     auto &PurchAir(state.dataPurchasedAirMgr->PurchAir);
    3027             : 
    3028             :     // Initializations
    3029     2076247 :     OANodeNum = PurchAir(PurchAirNum).OutdoorAirNodeNum;
    3030     2076247 :     RecircNodeNum = PurchAir(PurchAirNum).ZoneRecircAirNodeNum;
    3031             : 
    3032     2076247 :     RecircMassFlowRate = 0.0;
    3033     2076247 :     RecircTemp = state.dataLoopNodes->Node(RecircNodeNum).Temp;
    3034     2076247 :     RecircHumRat = state.dataLoopNodes->Node(RecircNodeNum).HumRat;
    3035     2076247 :     RecircEnthalpy = state.dataLoopNodes->Node(RecircNodeNum).Enthalpy;
    3036     2076247 :     if (PurchAir(PurchAirNum).OutdoorAir) {
    3037       14788 :         OAInletTemp = state.dataLoopNodes->Node(OANodeNum).Temp;
    3038       14788 :         OAInletHumRat = state.dataLoopNodes->Node(OANodeNum).HumRat;
    3039       14788 :         OAInletEnthalpy = state.dataLoopNodes->Node(OANodeNum).Enthalpy;
    3040       14788 :         OAAfterHtRecTemp = OAInletTemp;
    3041       14788 :         OAAfterHtRecHumRat = OAInletHumRat;
    3042       14788 :         OAAfterHtRecEnthalpy = OAInletEnthalpy;
    3043             :     } else {
    3044     2061459 :         OAInletTemp = 0.0;
    3045     2061459 :         OAInletHumRat = 0.0;
    3046     2061459 :         OAInletEnthalpy = 0.0;
    3047     2061459 :         OAAfterHtRecTemp = OAInletTemp;
    3048     2061459 :         OAAfterHtRecHumRat = OAInletHumRat;
    3049     2061459 :         OAAfterHtRecEnthalpy = OAInletEnthalpy;
    3050             :     }
    3051     2076247 :     HeatRecOn = false;
    3052             : 
    3053     2076247 :     if (PurchAir(PurchAirNum).OutdoorAir && (OAMassFlowRate > 0.0)) {
    3054             :         // Determine if heat recovery is beneficial
    3055       12513 :         if (PurchAir(PurchAirNum).HtRecType == HeatRecovery::Sensible) {
    3056        3683 :             if ((OperatingMode == OpMode::Heat) && (RecircTemp > OAInletTemp)) HeatRecOn = true;
    3057        3683 :             if ((OperatingMode == OpMode::Cool) && (RecircTemp < OAInletTemp)) HeatRecOn = true;
    3058             :         }
    3059       12513 :         if (PurchAir(PurchAirNum).HtRecType == HeatRecovery::Enthalpy) {
    3060        1436 :             if ((OperatingMode == OpMode::Heat) && (RecircEnthalpy > OAInletEnthalpy)) HeatRecOn = true;
    3061        1436 :             if ((OperatingMode == OpMode::Cool) && (RecircEnthalpy < OAInletEnthalpy)) HeatRecOn = true;
    3062             :         }
    3063             :         // Calculate heat recovery if active
    3064       12513 :         if (HeatRecOn) {
    3065        4472 :             PurchAir(PurchAirNum).TimeHtRecActive = state.dataHVACGlobal->TimeStepSys;
    3066        4472 :             OAAfterHtRecTemp = OAInletTemp + PurchAir(PurchAirNum).HtRecSenEff * (RecircTemp - OAInletTemp);
    3067        4472 :             if (PurchAir(PurchAirNum).HtRecType == HeatRecovery::Enthalpy)
    3068        1436 :                 OAAfterHtRecHumRat = OAInletHumRat + PurchAir(PurchAirNum).HtRecLatEff * (RecircHumRat - OAInletHumRat);
    3069        4472 :             OAAfterHtRecEnthalpy = PsyHFnTdbW(OAAfterHtRecTemp, OAAfterHtRecHumRat);
    3070             :             //   Check for saturation in supply outlet and reset temp, then humidity ratio at constant enthalpy
    3071        4472 :             if (PsyTsatFnHPb(state, OAAfterHtRecEnthalpy, state.dataEnvrn->OutBaroPress, RoutineName) > OAAfterHtRecTemp) {
    3072           0 :                 OAAfterHtRecTemp = PsyTsatFnHPb(state, OAAfterHtRecEnthalpy, state.dataEnvrn->OutBaroPress, RoutineName);
    3073           0 :                 OAAfterHtRecHumRat = PsyWFnTdbH(state, OAAfterHtRecTemp, OAAfterHtRecEnthalpy, RoutineName);
    3074             :             }
    3075             :         }
    3076             : 
    3077       12513 :         if (SupplyMassFlowRate > OAMassFlowRate) {
    3078        4914 :             RecircMassFlowRate = SupplyMassFlowRate - OAMassFlowRate;
    3079        4914 :             MixedAirEnthalpy =
    3080        4914 :                 (RecircMassFlowRate * state.dataLoopNodes->Node(RecircNodeNum).Enthalpy + OAMassFlowRate * OAAfterHtRecEnthalpy) / SupplyMassFlowRate;
    3081        4914 :             MixedAirHumRat =
    3082        4914 :                 (RecircMassFlowRate * state.dataLoopNodes->Node(RecircNodeNum).HumRat + OAMassFlowRate * OAAfterHtRecHumRat) / SupplyMassFlowRate;
    3083             :             // Mixed air temperature is calculated from the mixed air enthalpy and humidity ratio.
    3084        4914 :             MixedAirTemp = PsyTdbFnHW(MixedAirEnthalpy, MixedAirHumRat);
    3085             :         } else {
    3086        7599 :             RecircMassFlowRate = 0.0;
    3087        7599 :             MixedAirEnthalpy = OAAfterHtRecEnthalpy;
    3088        7599 :             MixedAirHumRat = OAAfterHtRecHumRat;
    3089        7599 :             MixedAirTemp = OAAfterHtRecTemp;
    3090             :         }
    3091             : 
    3092             :         // Calculate OA and heat recovery sensible and latent rates
    3093       12513 :         CpAir = PsyCpAirFnW(OAInletHumRat);
    3094       12513 :         PurchAir(PurchAirNum).HtRecSenOutput = OAMassFlowRate * CpAir * (OAAfterHtRecTemp - OAInletTemp);
    3095       12513 :         PurchAir(PurchAirNum).HtRecLatOutput = OAMassFlowRate * (OAAfterHtRecEnthalpy - OAInletEnthalpy) - PurchAir(PurchAirNum).HtRecSenOutput;
    3096             : 
    3097             :     } else { // No outdoor air
    3098     2063734 :         RecircMassFlowRate = SupplyMassFlowRate;
    3099     2063734 :         MixedAirTemp = RecircTemp;
    3100     2063734 :         MixedAirHumRat = RecircHumRat;
    3101     2063734 :         MixedAirEnthalpy = RecircEnthalpy;
    3102     2063734 :         PurchAir(PurchAirNum).HtRecSenOutput = 0.0;
    3103     2063734 :         PurchAir(PurchAirNum).HtRecLatOutput = 0.0;
    3104             :     }
    3105     2076247 : }
    3106             : 
    3107     2076247 : void UpdatePurchasedAir(EnergyPlusData &state, int const PurchAirNum, bool const FirstHVACIteration)
    3108             : {
    3109             : 
    3110             :     // SUBROUTINE INFORMATION:
    3111             :     //       AUTHOR         M. J. Witte
    3112             :     //       DATE WRITTEN   Sep 2011
    3113             :     //       MODIFIED       R. Raustad, July 2017, added return plenum
    3114             :     //       RE-ENGINEERED  na
    3115             : 
    3116             :     // PURPOSE OF THIS SUBROUTINE:
    3117             :     // Update node data for Ideal Loads (purchased air) system
    3118             : 
    3119             :     // USE STATEMENTS:
    3120             :     using ZonePlenum::SimAirZonePlenum;
    3121             : 
    3122             :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    3123             :     // na
    3124             :     bool FirstCall;
    3125             :     bool SupPathInletChanged;
    3126             : 
    3127     2076247 :     FirstCall = true;            // just used to avoid redundant calulations
    3128     2076247 :     SupPathInletChanged = false; // don't care if something changes
    3129             : 
    3130     2076247 :     auto &PurchAir(state.dataPurchasedAirMgr->PurchAir);
    3131             : 
    3132     2076247 :     if (PurchAir(PurchAirNum).ReturnPlenumIndex > 0) {
    3133             : 
    3134             :         // if connected to a return plenum, set the flag that this ideal loads air system was simulated
    3135       15075 :         state.dataPurchasedAirMgr->PurchAirPlenumArrays(PurchAir(PurchAirNum).ReturnPlenumIndex)
    3136       15075 :             .IsSimulated(PurchAir(PurchAirNum).PurchAirArrayIndex) = true;
    3137             : 
    3138             :         // if all ideal loads air systems connected to the same plenum have been simulated, simulate the zone air plenum
    3139       15075 :         if (all(state.dataPurchasedAirMgr->PurchAirPlenumArrays(PurchAir(PurchAirNum).ReturnPlenumIndex).IsSimulated)) {
    3140        6030 :             SimAirZonePlenum(state,
    3141        3015 :                              PurchAir(PurchAirNum).ReturnPlenumName,
    3142             :                              DataZoneEquipment::AirLoopHVACZone::ReturnPlenum,
    3143        3015 :                              PurchAir(PurchAirNum).ReturnPlenumIndex,
    3144             :                              FirstHVACIteration,
    3145             :                              FirstCall,
    3146             :                              SupPathInletChanged);
    3147             :             // reset this plenums flags for next iteration
    3148        3015 :             state.dataPurchasedAirMgr->PurchAirPlenumArrays(PurchAir(PurchAirNum).ReturnPlenumIndex).IsSimulated = false;
    3149             :         }
    3150             :     }
    3151     2076247 : }
    3152             : 
    3153     2076247 : void ReportPurchasedAir(EnergyPlusData &state, int const PurchAirNum)
    3154             : {
    3155             : 
    3156             :     // SUBROUTINE INFORMATION:
    3157             :     //       AUTHOR         Russ Taylor
    3158             :     //       DATE WRITTEN   Nov 1997
    3159             :     //       MODIFIED       na
    3160             :     //       RE-ENGINEERED  na
    3161             : 
    3162             :     // PURPOSE OF THIS SUBROUTINE:
    3163             :     // Calculate values of report variables, if necessary.
    3164             : 
    3165             :     // Using/Aliasing
    3166     2076247 :     Real64 TimeStepSysSec = state.dataHVACGlobal->TimeStepSysSec;
    3167             : 
    3168     2076247 :     auto &PurchAir(state.dataPurchasedAirMgr->PurchAir);
    3169             : 
    3170             :     // Sort out heating and cooling rates
    3171     2076247 :     PurchAir(PurchAirNum).SenHeatRate = max(PurchAir(PurchAirNum).SenCoilLoad, 0.0);
    3172     2076247 :     PurchAir(PurchAirNum).SenCoolRate = std::abs(min(PurchAir(PurchAirNum).SenCoilLoad, 0.0));
    3173     2076247 :     PurchAir(PurchAirNum).LatHeatRate = max(PurchAir(PurchAirNum).LatCoilLoad, 0.0);
    3174     2076247 :     PurchAir(PurchAirNum).LatCoolRate = std::abs(min(PurchAir(PurchAirNum).LatCoilLoad, 0.0));
    3175     2076247 :     PurchAir(PurchAirNum).TotHeatRate = PurchAir(PurchAirNum).SenHeatRate + PurchAir(PurchAirNum).LatHeatRate;
    3176     2076247 :     PurchAir(PurchAirNum).TotCoolRate = PurchAir(PurchAirNum).SenCoolRate + PurchAir(PurchAirNum).LatCoolRate;
    3177             : 
    3178     2076247 :     PurchAir(PurchAirNum).ZoneSenHeatRate = max(PurchAir(PurchAirNum).SenOutputToZone, 0.0);
    3179     2076247 :     PurchAir(PurchAirNum).ZoneSenCoolRate = std::abs(min(PurchAir(PurchAirNum).SenOutputToZone, 0.0));
    3180     2076247 :     PurchAir(PurchAirNum).ZoneLatHeatRate = max(PurchAir(PurchAirNum).LatOutputToZone, 0.0);
    3181     2076247 :     PurchAir(PurchAirNum).ZoneLatCoolRate = std::abs(min(PurchAir(PurchAirNum).LatOutputToZone, 0.0));
    3182     2076247 :     PurchAir(PurchAirNum).ZoneTotHeatRate = PurchAir(PurchAirNum).ZoneSenHeatRate + PurchAir(PurchAirNum).ZoneLatHeatRate;
    3183     2076247 :     PurchAir(PurchAirNum).ZoneTotCoolRate = PurchAir(PurchAirNum).ZoneSenCoolRate + PurchAir(PurchAirNum).ZoneLatCoolRate;
    3184             : 
    3185             :     // Sort out outdoor air "loads"
    3186             :     // OASenOutput = Outdoor air sensible output relative to zone conditions [W], <0 means OA is cooler than zone air
    3187             :     // OALatOutput  = Outdoor air latent output relative to zone conditions [W], <0 means OA is drier than zone air
    3188     2076247 :     if (PurchAir(PurchAirNum).SenCoilLoad > 0.0) { // Heating is active
    3189      800783 :         PurchAir(PurchAirNum).OASenHeatRate = std::abs(min(PurchAir(PurchAirNum).OASenOutput, 0.0));
    3190             :     } else {
    3191     1275464 :         PurchAir(PurchAirNum).OASenHeatRate = 0.0;
    3192             :     }
    3193     2076247 :     if (PurchAir(PurchAirNum).SenCoilLoad < 0.0) { // Cooling is active
    3194      545761 :         PurchAir(PurchAirNum).OASenCoolRate = max(PurchAir(PurchAirNum).OASenOutput, 0.0);
    3195             :     } else {
    3196     1530486 :         PurchAir(PurchAirNum).OASenCoolRate = 0.0;
    3197             :     }
    3198     2076247 :     if (PurchAir(PurchAirNum).LatCoilLoad > 0.0) { // Humidification is active
    3199      797927 :         PurchAir(PurchAirNum).OALatHeatRate = std::abs(min(PurchAir(PurchAirNum).OALatOutput, 0.0));
    3200             :     } else {
    3201     1278320 :         PurchAir(PurchAirNum).OALatHeatRate = 0.0;
    3202             :     }
    3203     2076247 :     if (PurchAir(PurchAirNum).LatCoilLoad < 0.0) { // Dehumidification is active
    3204      460875 :         PurchAir(PurchAirNum).OALatCoolRate = max(PurchAir(PurchAirNum).OALatOutput, 0.0);
    3205             :     } else {
    3206     1615372 :         PurchAir(PurchAirNum).OALatCoolRate = 0.0;
    3207             :     }
    3208             : 
    3209     2076247 :     PurchAir(PurchAirNum).OATotHeatRate = PurchAir(PurchAirNum).OASenHeatRate + PurchAir(PurchAirNum).OALatHeatRate;
    3210     2076247 :     PurchAir(PurchAirNum).OATotCoolRate = PurchAir(PurchAirNum).OASenCoolRate + PurchAir(PurchAirNum).OALatCoolRate;
    3211             : 
    3212     2076247 :     PurchAir(PurchAirNum).HtRecSenHeatRate = max(PurchAir(PurchAirNum).HtRecSenOutput, 0.0);
    3213     2076247 :     PurchAir(PurchAirNum).HtRecSenCoolRate = std::abs(min(PurchAir(PurchAirNum).HtRecSenOutput, 0.0));
    3214     2076247 :     PurchAir(PurchAirNum).HtRecLatHeatRate = max(PurchAir(PurchAirNum).HtRecLatOutput, 0.0);
    3215     2076247 :     PurchAir(PurchAirNum).HtRecLatCoolRate = std::abs(min(PurchAir(PurchAirNum).HtRecLatOutput, 0.0));
    3216     2076247 :     PurchAir(PurchAirNum).HtRecTotHeatRate = PurchAir(PurchAirNum).HtRecSenHeatRate + PurchAir(PurchAirNum).HtRecLatHeatRate;
    3217     2076247 :     PurchAir(PurchAirNum).HtRecTotCoolRate = PurchAir(PurchAirNum).HtRecSenCoolRate + PurchAir(PurchAirNum).HtRecLatCoolRate;
    3218             : 
    3219     2076247 :     PurchAir(PurchAirNum).SenHeatEnergy = PurchAir(PurchAirNum).SenHeatRate * TimeStepSysSec;
    3220     2076247 :     PurchAir(PurchAirNum).SenCoolEnergy = PurchAir(PurchAirNum).SenCoolRate * TimeStepSysSec;
    3221     2076247 :     PurchAir(PurchAirNum).LatHeatEnergy = PurchAir(PurchAirNum).LatHeatRate * TimeStepSysSec;
    3222     2076247 :     PurchAir(PurchAirNum).LatCoolEnergy = PurchAir(PurchAirNum).LatCoolRate * TimeStepSysSec;
    3223     2076247 :     PurchAir(PurchAirNum).TotHeatEnergy = PurchAir(PurchAirNum).TotHeatRate * TimeStepSysSec;
    3224     2076247 :     PurchAir(PurchAirNum).TotCoolEnergy = PurchAir(PurchAirNum).TotCoolRate * TimeStepSysSec;
    3225             : 
    3226     2076247 :     PurchAir(PurchAirNum).ZoneSenHeatEnergy = PurchAir(PurchAirNum).ZoneSenHeatRate * TimeStepSysSec;
    3227     2076247 :     PurchAir(PurchAirNum).ZoneSenCoolEnergy = PurchAir(PurchAirNum).ZoneSenCoolRate * TimeStepSysSec;
    3228     2076247 :     PurchAir(PurchAirNum).ZoneLatHeatEnergy = PurchAir(PurchAirNum).ZoneLatHeatRate * TimeStepSysSec;
    3229     2076247 :     PurchAir(PurchAirNum).ZoneLatCoolEnergy = PurchAir(PurchAirNum).ZoneLatCoolRate * TimeStepSysSec;
    3230     2076247 :     PurchAir(PurchAirNum).ZoneTotHeatEnergy = PurchAir(PurchAirNum).ZoneTotHeatRate * TimeStepSysSec;
    3231     2076247 :     PurchAir(PurchAirNum).ZoneTotCoolEnergy = PurchAir(PurchAirNum).ZoneTotCoolRate * TimeStepSysSec;
    3232             : 
    3233     2076247 :     PurchAir(PurchAirNum).OASenHeatEnergy = PurchAir(PurchAirNum).OASenHeatRate * TimeStepSysSec;
    3234     2076247 :     PurchAir(PurchAirNum).OASenCoolEnergy = PurchAir(PurchAirNum).OASenCoolRate * TimeStepSysSec;
    3235     2076247 :     PurchAir(PurchAirNum).OALatHeatEnergy = PurchAir(PurchAirNum).OALatHeatRate * TimeStepSysSec;
    3236     2076247 :     PurchAir(PurchAirNum).OALatCoolEnergy = PurchAir(PurchAirNum).OALatCoolRate * TimeStepSysSec;
    3237     2076247 :     PurchAir(PurchAirNum).OATotHeatEnergy = PurchAir(PurchAirNum).OATotHeatRate * TimeStepSysSec;
    3238     2076247 :     PurchAir(PurchAirNum).OATotCoolEnergy = PurchAir(PurchAirNum).OATotCoolRate * TimeStepSysSec;
    3239             : 
    3240     2076247 :     PurchAir(PurchAirNum).HtRecSenHeatEnergy = PurchAir(PurchAirNum).HtRecSenHeatRate * TimeStepSysSec;
    3241     2076247 :     PurchAir(PurchAirNum).HtRecSenCoolEnergy = PurchAir(PurchAirNum).HtRecSenCoolRate * TimeStepSysSec;
    3242     2076247 :     PurchAir(PurchAirNum).HtRecLatHeatEnergy = PurchAir(PurchAirNum).HtRecLatHeatRate * TimeStepSysSec;
    3243     2076247 :     PurchAir(PurchAirNum).HtRecLatCoolEnergy = PurchAir(PurchAirNum).HtRecLatCoolRate * TimeStepSysSec;
    3244     2076247 :     PurchAir(PurchAirNum).HtRecTotHeatEnergy = PurchAir(PurchAirNum).HtRecTotHeatRate * TimeStepSysSec;
    3245     2076247 :     PurchAir(PurchAirNum).HtRecTotCoolEnergy = PurchAir(PurchAirNum).HtRecTotCoolRate * TimeStepSysSec;
    3246     2076247 : }
    3247             : 
    3248      457856 : Real64 GetPurchasedAirOutAirMassFlow(EnergyPlusData &state, int const PurchAirNum)
    3249             : {
    3250             : 
    3251             :     // FUNCTION INFORMATION:
    3252             :     //       AUTHOR         B Griffith
    3253             :     //       DATE WRITTEN   Dec  2006
    3254             :     //       MODIFIED       na
    3255             :     //       RE-ENGINEERED  na
    3256             : 
    3257             :     // PURPOSE OF THIS FUNCTION:
    3258             :     // lookup function for OA inlet mass flow for ventilation rate reporting
    3259             : 
    3260             :     // METHODOLOGY EMPLOYED:
    3261             :     // most analagous functions look up an outside air node but this function
    3262             :     // gets the actual mass flow of outdoor air, following the features of the model
    3263             : 
    3264      457856 :     if (state.dataPurchasedAirMgr->GetPurchAirInputFlag) {
    3265           0 :         GetPurchasedAir(state);
    3266           0 :         state.dataPurchasedAirMgr->GetPurchAirInputFlag = false;
    3267             :     }
    3268      457856 :     return state.dataPurchasedAirMgr->PurchAir(PurchAirNum).OutdoorAirMassFlowRate;
    3269             : }
    3270             : 
    3271      457856 : int GetPurchasedAirZoneInletAirNode(EnergyPlusData &state, int const PurchAirNum)
    3272             : {
    3273             : 
    3274             :     // FUNCTION INFORMATION:
    3275             :     //       AUTHOR         B Griffith
    3276             :     //       DATE WRITTEN   Dec  2006
    3277             :     //       MODIFIED       Adapted for purchased air by M.J. Witte, Oct 2013
    3278             :     //       RE-ENGINEERED  na
    3279             : 
    3280             :     // PURPOSE OF THIS FUNCTION:
    3281             :     // lookup function for zone inlet node for ventilation rate reporting
    3282             : 
    3283      457856 :     if (state.dataPurchasedAirMgr->GetPurchAirInputFlag) {
    3284           0 :         GetPurchasedAir(state);
    3285           0 :         state.dataPurchasedAirMgr->GetPurchAirInputFlag = false;
    3286             :     }
    3287             : 
    3288      457856 :     int GetPurchasedAirZoneInletAirNode = 0;
    3289      457856 :     if (PurchAirNum > 0 && PurchAirNum <= state.dataPurchasedAirMgr->NumPurchAir) {
    3290      457856 :         GetPurchasedAirZoneInletAirNode = state.dataPurchasedAirMgr->PurchAir(PurchAirNum).ZoneSupplyAirNodeNum;
    3291             :     }
    3292             : 
    3293      457856 :     return GetPurchasedAirZoneInletAirNode;
    3294             : }
    3295             : 
    3296      457856 : int GetPurchasedAirReturnAirNode(EnergyPlusData &state, int const PurchAirNum)
    3297             : {
    3298             : 
    3299             :     // FUNCTION INFORMATION:
    3300             :     //       AUTHOR         B Griffith
    3301             :     //       DATE WRITTEN   Dec  2006
    3302             :     //       MODIFIED       Adapted for purchased air by M.J. Witte, Oct 2013
    3303             :     //       RE-ENGINEERED  na
    3304             : 
    3305             :     // PURPOSE OF THIS FUNCTION:
    3306             :     // lookup function for recirculation air node for ventilation rate reporting
    3307             : 
    3308      457856 :     if (state.dataPurchasedAirMgr->GetPurchAirInputFlag) {
    3309           0 :         GetPurchasedAir(state);
    3310           0 :         state.dataPurchasedAirMgr->GetPurchAirInputFlag = false;
    3311             :     }
    3312             : 
    3313      457856 :     int GetPurchasedAirReturnAirNode = 0;
    3314      457856 :     if (PurchAirNum > 0 && PurchAirNum <= state.dataPurchasedAirMgr->NumPurchAir) {
    3315      457856 :         GetPurchasedAirReturnAirNode = state.dataPurchasedAirMgr->PurchAir(PurchAirNum).ZoneRecircAirNodeNum;
    3316             :     }
    3317             : 
    3318      457856 :     return GetPurchasedAirReturnAirNode;
    3319             : }
    3320             : 
    3321           0 : int getPurchasedAirIndex(EnergyPlusData &state, std::string_view PurchAirName)
    3322             : {
    3323           0 :     if (state.dataPurchasedAirMgr->GetPurchAirInputFlag) {
    3324           0 :         GetPurchasedAir(state);
    3325           0 :         state.dataPurchasedAirMgr->GetPurchAirInputFlag = false;
    3326             :     }
    3327             : 
    3328           0 :     for (int PurchAirNum = 1; PurchAirNum <= state.dataPurchasedAirMgr->NumPurchAir; ++PurchAirNum) {
    3329           0 :         if (Util::SameString(state.dataPurchasedAirMgr->PurchAir(PurchAirNum).Name, PurchAirName)) {
    3330           0 :             return PurchAirNum;
    3331             :         }
    3332             :     }
    3333             : 
    3334           0 :     return 0;
    3335             : }
    3336             : 
    3337      457856 : Real64 GetPurchasedAirMixedAirTemp(EnergyPlusData &state, int const PurchAirNum)
    3338             : {
    3339             : 
    3340             :     // FUNCTION INFORMATION:
    3341             :     //       AUTHOR         B Griffith
    3342             :     //       DATE WRITTEN   Dec  2006
    3343             :     //       MODIFIED       Adapted for purchased air by M.J. Witte, Oct 2013
    3344             :     //       RE-ENGINEERED  na
    3345             : 
    3346             :     // PURPOSE OF THIS FUNCTION:
    3347             :     // lookup function for mixed air Temp for ventilation rate reporting
    3348             : 
    3349             :     // METHODOLOGY EMPLOYED:
    3350             :     // most analagous functions look up an outside air node but this function
    3351             :     // gets the actual mass flow of outdoor air, following the features of the model
    3352             : 
    3353      457856 :     if (state.dataPurchasedAirMgr->GetPurchAirInputFlag) {
    3354           0 :         GetPurchasedAir(state);
    3355           0 :         state.dataPurchasedAirMgr->GetPurchAirInputFlag = false;
    3356             :     }
    3357             : 
    3358      457856 :     return state.dataPurchasedAirMgr->PurchAir(PurchAirNum).MixedAirTemp;
    3359             : }
    3360             : 
    3361      457856 : Real64 GetPurchasedAirMixedAirHumRat(EnergyPlusData &state, int const PurchAirNum)
    3362             : {
    3363             : 
    3364             :     // FUNCTION INFORMATION:
    3365             :     //       AUTHOR         B Griffith
    3366             :     //       DATE WRITTEN   Dec  2006
    3367             :     //       MODIFIED       Adapted for purchased air by M.J. Witte, Oct 2013
    3368             :     //       RE-ENGINEERED  na
    3369             : 
    3370             :     // PURPOSE OF THIS FUNCTION:
    3371             :     // lookup function for mixed air HumRat for ventilation rate reporting
    3372             : 
    3373             :     // METHODOLOGY EMPLOYED:
    3374             :     // most analogous functions look up an outside air node but this function
    3375             :     // gets the actual mass flow of outdoor air, following the features of the model
    3376             : 
    3377      457856 :     if (state.dataPurchasedAirMgr->GetPurchAirInputFlag) {
    3378           0 :         GetPurchasedAir(state);
    3379           0 :         state.dataPurchasedAirMgr->GetPurchAirInputFlag = false;
    3380             :     }
    3381             : 
    3382      457856 :     return state.dataPurchasedAirMgr->PurchAir(PurchAirNum).MixedAirHumRat;
    3383             : }
    3384             : 
    3385         310 : bool CheckPurchasedAirForReturnPlenum(EnergyPlusData &state, int const ReturnPlenumIndex)
    3386             : {
    3387             : 
    3388             :     // FUNCTION INFORMATION:
    3389             :     //       AUTHOR         R Raustad
    3390             :     //       DATE WRITTEN   July  2017
    3391             : 
    3392             :     // PURPOSE OF THIS FUNCTION:
    3393             :     // lookup function to check if return plenum is used
    3394             : 
    3395             :     // Return value
    3396             :     bool CheckPurchasedAirForReturnPlenum;
    3397             : 
    3398             :     // FUNCTION LOCAL VARIABLE DECLARATIONS:
    3399             :     int PurchAirNum;
    3400             : 
    3401         310 :     if (state.dataPurchasedAirMgr->GetPurchAirInputFlag) {
    3402         188 :         GetPurchasedAir(state);
    3403         188 :         state.dataPurchasedAirMgr->GetPurchAirInputFlag = false;
    3404             :     }
    3405             : 
    3406         310 :     CheckPurchasedAirForReturnPlenum = false;
    3407         336 :     for (PurchAirNum = 1; PurchAirNum <= state.dataPurchasedAirMgr->NumPurchAir; ++PurchAirNum) {
    3408          26 :         if (ReturnPlenumIndex != state.dataPurchasedAirMgr->PurchAir(PurchAirNum).ReturnPlenumIndex) continue;
    3409           5 :         CheckPurchasedAirForReturnPlenum = true;
    3410             :     }
    3411             : 
    3412         310 :     return CheckPurchasedAirForReturnPlenum;
    3413             : }
    3414             : 
    3415           5 : void InitializePlenumArrays(EnergyPlusData &state, int const PurchAirNum)
    3416             : {
    3417             :     // FUNCTION INFORMATION:
    3418             :     //       AUTHOR         R Raustad
    3419             :     //       DATE WRITTEN   July  2017
    3420             : 
    3421             :     // PURPOSE OF THIS FUNCTION:
    3422             :     // to initialize arrays needed to manage ideal load air system used with return plenums
    3423             :     //
    3424             :     // Example:
    3425             :     // NumPlenumArrays = 2 (same as there are two ZoneHVAC:ReturnPlenums objects connected to two or more ideal loads air systems
    3426             :     // In this example ideal loads air system #4 is not connected to a zone return plenum
    3427             :     //
    3428             :     // ZoneHVAC:ReturnPlenum( 1 ) = ReturnPlenum1 is not connected to any ideal loads air systems
    3429             :     // ZoneHVAC:ReturnPlenum( 2 ) = ReturnPlenum2 is connected to PurchAirPlenumArrays( 1 )
    3430             :     // ZoneHVAC:ReturnPlenum( 3 ) = ReturnPlenum3 is connected to PurchAirPlenumArrays( 2 )
    3431             :     //
    3432             :     // PurchAirPlenumArrays( 1 )
    3433             :     //   PurchAirPlenumArrays( 1 ).NumPurchAir = 2, there are 2 ideal loads air systems connected to this plenum
    3434             :     //      PurchAirPlenumArrays( 1 ).PurchAirArray( 1 ) = 1, ideal loads air system #1 is attached to this plenum
    3435             :     //      PurchAirPlenumArrays( 1 ).PurchAirArray( 2 ) = 3, ideal loads air system #3 is attached to this plenum
    3436             :     //      PurchAirPlenumArrays( 1 ).IsSimulated( 1 ) = true, ideal loads air system #1 has been simulated this iteration
    3437             :     //      PurchAirPlenumArrays( 1 ).IsSimulated( 2 ) = false, ideal loads air system #3 has not yet been simulated this iteration
    3438             :     //
    3439             :     //      Ideal loads air sytems keep track of which plenum they are connected to
    3440             :     //      PurchAir( 1 ).PlenumArrayIndex = 1
    3441             :     //      PurchAir( 1 ).ReturnPlenumName = ReturnPlenum2;
    3442             :     //      PurchAir( 3 ).PlenumArrayIndex = 1
    3443             :     //      PurchAir( 3 ).ReturnPlenumName = ReturnPlenum2;
    3444             :     //
    3445             :     //      The ideal loads air sytems also keep track of which item they are in the int and bool arrays
    3446             :     //      PurchAir( 1 ).PurchAirArrayIndex = 1
    3447             :     //      PurchAir( 3 ).PurchAirArrayIndex = 2
    3448             :     //
    3449             :     // PurchAirPlenumArrays( 2 )
    3450             :     //   PurchAirPlenumArrays( 2 ).NumPurchAir = 3, there are 3 ideal loads air systems connected to this plenum
    3451             :     //      PurchAirPlenumArrays( 2 ).PurchAirArray( 1 ) = 2, ideal loads air system #2 is attached to this plenum
    3452             :     //      PurchAirPlenumArrays( 2 ).PurchAirArray( 2 ) = 5, ideal loads air system #5 is attached to this plenum
    3453             :     //      PurchAirPlenumArrays( 2 ).PurchAirArray( 3 ) = 6, ideal loads air system #6 is attached to this plenum
    3454             :     //      PurchAirPlenumArrays( 2 ).IsSimulated( 1 ) = true, ideal loads air system #4 has been simulated this iteration
    3455             :     //      PurchAirPlenumArrays( 2 ).IsSimulated( 2 ) = false, ideal loads air system #5 has not yet been simulated this iteration
    3456             :     //      PurchAirPlenumArrays( 2 ).IsSimulated( 3 ) = false, ideal loads air system #6 has not yet been simulated this iteration
    3457             :     //
    3458             :     //      Ideal loads air sytems keep track of which plenum they are connected to
    3459             :     //      PurchAir( 2 ).PlenumArrayIndex = 2;
    3460             :     //      PurchAir( 2 ).ReturnPlenumName = ReturnPlenum3;
    3461             :     //      PurchAir( 5 ).PlenumArrayIndex = 2;
    3462             :     //      PurchAir( 5 ).ReturnPlenumName = ReturnPlenum3;
    3463             :     //      PurchAir( 6 ).PlenumArrayIndex = 2;
    3464             :     //      PurchAir( 6 ).ReturnPlenumName = ReturnPlenum3;
    3465             :     //
    3466             :     //      The ideal loads air sytems also keep track of which item they are in the int and bool arrays
    3467             :     //      PurchAir( 2 ).PurchAirArrayIndex = 1;
    3468             :     //      PurchAir( 5 ).PurchAirArrayIndex = 2;
    3469             :     //      PurchAir( 6 ).PurchAirArrayIndex = 3;
    3470             :     //
    3471             :     //      Given these connections, the data in the IsSimulated array can be set (or checked) according to this syntax:
    3472             :     //
    3473             :     //      Each time an ideal loads air system is simulated the IsSimulated flag is set to true
    3474             :     //      PurchAirPlenumArrays( PurchAir( PurchNum ).PlenumArrayIndex ).IsSimulated( PurchAir( PurchNum ).PurchAirArrayIndex ) = true;
    3475             :     //
    3476             :     //     if all ideal loads air systems connected to the same plenum have been simulated, simulate the zone air return plenum (once per set of
    3477             :     //     ideal loads systems) if ( all( PurchAirPlenumArrays( PurchAir( PurchAirNum ).ReturnPlenumIndex ).IsSimulated ) ) {
    3478             :     //         SimAirZonePlenum( PurchAir( PurchAirNum ).ReturnPlenumName, DataZoneEquipment::ZoneReturnPlenum_Type, PurchAir( PurchAirNum
    3479             :     //         ).ReturnPlenumIndex, FirstHVACIteration, FirstCall, SupPathInletChanged ); reset all IsSimulated flags for next iteration
    3480             :     //         PurchAirPlenumArrays( PurchAir( PurchAirNum ).ReturnPlenumIndex ).IsSimulated = false;
    3481             :     //     }
    3482             : 
    3483             :     // FUNCTION LOCAL VARIABLE DECLARATIONS:
    3484             :     int ReturnPlenumIndex;        // index to ZoneHVAC:ReturnPlenum object
    3485             :     int ReturnPlenumNum;          // loop counter
    3486             :     bool PlenumNotFound;          // logical to determine if same plenum is used by other ideal loads air systems
    3487             :     int Loop;                     // loop counters
    3488             :     int Loop2;                    // loop counters
    3489           5 :     Array1D_int TempPurchArray;   // temporary array used for dynamic allocation
    3490           5 :     Array1D_bool TempIsSimulated; // temporary array used for dynamic allocation
    3491             : 
    3492             :     // index to ZoneHVAC:ReturnPlenum object
    3493           5 :     ReturnPlenumIndex = state.dataPurchasedAirMgr->PurchAir(PurchAirNum).ReturnPlenumIndex;
    3494           5 :     PlenumNotFound = true;
    3495             : 
    3496             :     // if first time through, set up arrays
    3497           5 :     if (!state.dataPurchasedAirMgr->PurchAirPlenumArrays.allocated()) {
    3498             : 
    3499             :         // the ideal loads air system keeps track of which item this system is in a list
    3500           1 :         state.dataPurchasedAirMgr->PurchAir(PurchAirNum).PurchAirArrayIndex = 1;
    3501             :         // keep track of how many arrays (i.e., how many different plenums are attached to different ideal loads air systems
    3502           1 :         state.dataPurchasedAirMgr->NumPlenumArrays = 1;
    3503             : 
    3504             :         // allocate new array
    3505           1 :         state.dataPurchasedAirMgr->PurchAirPlenumArrays.allocate(state.dataPurchasedAirMgr->NumPlenumArrays);
    3506             :         // set counter for how many ideal loads air systems are attached to this plenum
    3507           1 :         state.dataPurchasedAirMgr->PurchAirPlenumArrays(state.dataPurchasedAirMgr->NumPlenumArrays).NumPurchAir =
    3508             :             1; // keeps track of how many ideal loads air system are connected to this return plenum
    3509             :         // keep track of which plenum this is ( i.e., PurchAirPlenumArrays(1) is ZoneHVAC:ReturnPlenum #4 )
    3510           1 :         state.dataPurchasedAirMgr->PurchAirPlenumArrays(state.dataPurchasedAirMgr->NumPlenumArrays).ReturnPlenumIndex =
    3511             :             ReturnPlenumIndex; // stores index of return plenum (e.g., 4 of 5)
    3512             :         // allocate array holding index to one or more ideal loads air systems
    3513           1 :         state.dataPurchasedAirMgr->PurchAirPlenumArrays(state.dataPurchasedAirMgr->NumPlenumArrays).PurchAirArray.allocate(1);
    3514             :         // allocate boolean to keep track of whether or not this ideal loads air system has been simulated
    3515           1 :         state.dataPurchasedAirMgr->PurchAirPlenumArrays(state.dataPurchasedAirMgr->NumPlenumArrays).IsSimulated.allocate(1);
    3516             :         // save the data
    3517           1 :         state.dataPurchasedAirMgr->PurchAirPlenumArrays(state.dataPurchasedAirMgr->NumPlenumArrays).PurchAirArray(1) = PurchAirNum;
    3518           1 :         state.dataPurchasedAirMgr->PurchAirPlenumArrays(state.dataPurchasedAirMgr->NumPlenumArrays).IsSimulated(1) = false;
    3519             : 
    3520             :     } else {
    3521             : 
    3522             :         // find the correct index to PurchAirPlenumArrays
    3523           4 :         for (ReturnPlenumNum = 1; ReturnPlenumNum <= state.dataPurchasedAirMgr->NumPlenumArrays; ++ReturnPlenumNum) {
    3524           4 :             if (ReturnPlenumIndex != state.dataPurchasedAirMgr->PurchAirPlenumArrays(ReturnPlenumNum).ReturnPlenumIndex) continue;
    3525             : 
    3526             :             // allocate temporary arrays and save existing data
    3527           4 :             TempPurchArray.allocate(state.dataPurchasedAirMgr->PurchAirPlenumArrays(ReturnPlenumNum).NumPurchAir);
    3528           4 :             TempIsSimulated.allocate(state.dataPurchasedAirMgr->PurchAirPlenumArrays(ReturnPlenumNum).NumPurchAir);
    3529             :             // these are the  member arrays in an existing PurchAirPlenumArrays
    3530           4 :             TempPurchArray = state.dataPurchasedAirMgr->PurchAirPlenumArrays(ReturnPlenumNum).PurchAirArray;
    3531           4 :             TempIsSimulated = state.dataPurchasedAirMgr->PurchAirPlenumArrays(ReturnPlenumNum).IsSimulated;
    3532             : 
    3533             :             // if this array has been used before, we need to increase member array space to save new PurchAir data
    3534           4 :             state.dataPurchasedAirMgr->PurchAirPlenumArrays(ReturnPlenumNum).NumPurchAir += 1;
    3535             :             // save the location of this ideal loads air system in the member arrays
    3536           4 :             state.dataPurchasedAirMgr->PurchAir(PurchAirNum).PurchAirArrayIndex =
    3537           4 :                 state.dataPurchasedAirMgr->PurchAirPlenumArrays(ReturnPlenumNum).NumPurchAir;
    3538             : 
    3539             :             // allocate more space, this will wipe out data previously stored
    3540           4 :             state.dataPurchasedAirMgr->PurchAirPlenumArrays(ReturnPlenumNum)
    3541           4 :                 .PurchAirArray.allocate(state.dataPurchasedAirMgr->PurchAirPlenumArrays(ReturnPlenumNum).NumPurchAir);
    3542           4 :             state.dataPurchasedAirMgr->PurchAirPlenumArrays(ReturnPlenumNum)
    3543           4 :                 .IsSimulated.allocate(state.dataPurchasedAirMgr->PurchAirPlenumArrays(ReturnPlenumNum).NumPurchAir);
    3544             : 
    3545             :             // re-initialize previous data
    3546          14 :             for (Loop = 1; Loop < state.dataPurchasedAirMgr->PurchAirPlenumArrays(ReturnPlenumNum).NumPurchAir; ++Loop) {
    3547          10 :                 state.dataPurchasedAirMgr->PurchAirPlenumArrays(ReturnPlenumNum).PurchAirArray(Loop) = TempPurchArray(Loop);
    3548          10 :                 state.dataPurchasedAirMgr->PurchAirPlenumArrays(ReturnPlenumNum).IsSimulated(Loop) = TempIsSimulated(Loop);
    3549             :             }
    3550             :             // delete temporary array
    3551           4 :             TempPurchArray.deallocate();
    3552           4 :             TempIsSimulated.deallocate();
    3553             : 
    3554             :             // save new data in expanded member array
    3555           4 :             state.dataPurchasedAirMgr->PurchAirPlenumArrays(ReturnPlenumNum)
    3556           8 :                 .PurchAirArray(state.dataPurchasedAirMgr->PurchAirPlenumArrays(ReturnPlenumNum).NumPurchAir) = PurchAirNum;
    3557           4 :             state.dataPurchasedAirMgr->PurchAirPlenumArrays(ReturnPlenumNum)
    3558           4 :                 .IsSimulated(state.dataPurchasedAirMgr->PurchAirPlenumArrays(ReturnPlenumNum).NumPurchAir) = false;
    3559             : 
    3560           4 :             PlenumNotFound = false;
    3561           4 :             break;
    3562             :         }
    3563             : 
    3564           4 :         if (PlenumNotFound) {
    3565             : 
    3566             :             // need to allocate additional space for new plenum array
    3567             :             // keep track of how many arrays (i.e., how many different plenums are attached to different ideal loads air systems)
    3568           0 :             state.dataPurchasedAirMgr->NumPlenumArrays += 1;
    3569             : 
    3570             :             // allocate temporary array and save existing data
    3571           0 :             state.dataPurchasedAirMgr->TempPurchAirPlenumArrays.allocate(state.dataPurchasedAirMgr->NumPlenumArrays);
    3572           0 :             for (Loop = 1; Loop < state.dataPurchasedAirMgr->NumPlenumArrays; ++Loop) {
    3573           0 :                 state.dataPurchasedAirMgr->TempPurchAirPlenumArrays(Loop).NumPurchAir =
    3574           0 :                     state.dataPurchasedAirMgr->PurchAirPlenumArrays(Loop).NumPurchAir;
    3575           0 :                 state.dataPurchasedAirMgr->TempPurchAirPlenumArrays(Loop).ReturnPlenumIndex =
    3576           0 :                     state.dataPurchasedAirMgr->PurchAirPlenumArrays(Loop).ReturnPlenumIndex;
    3577           0 :                 state.dataPurchasedAirMgr->TempPurchAirPlenumArrays(Loop).PurchAirArray.allocate(
    3578           0 :                     state.dataPurchasedAirMgr->PurchAirPlenumArrays(Loop).NumPurchAir);
    3579           0 :                 state.dataPurchasedAirMgr->TempPurchAirPlenumArrays(Loop).IsSimulated.allocate(
    3580           0 :                     state.dataPurchasedAirMgr->PurchAirPlenumArrays(Loop).NumPurchAir);
    3581           0 :                 for (Loop2 = 1; Loop2 <= state.dataPurchasedAirMgr->PurchAirPlenumArrays(Loop).NumPurchAir; ++Loop2) {
    3582           0 :                     state.dataPurchasedAirMgr->TempPurchAirPlenumArrays(Loop).PurchAirArray(Loop2) =
    3583           0 :                         state.dataPurchasedAirMgr->PurchAirPlenumArrays(Loop).PurchAirArray(Loop2);
    3584           0 :                     state.dataPurchasedAirMgr->TempPurchAirPlenumArrays(Loop).IsSimulated(Loop2) =
    3585           0 :                         state.dataPurchasedAirMgr->PurchAirPlenumArrays(Loop).IsSimulated(Loop2);
    3586             :                 }
    3587             :             }
    3588             : 
    3589             :             // delete primary array (probably could just re-allocate, but this is only done a few times per simulation)
    3590           0 :             state.dataPurchasedAirMgr->PurchAirPlenumArrays.deallocate();
    3591             :             // reallocate to new size
    3592           0 :             state.dataPurchasedAirMgr->PurchAirPlenumArrays.allocate(state.dataPurchasedAirMgr->NumPlenumArrays);
    3593             : 
    3594             :             // allocate member arrays to same size as before
    3595           0 :             for (Loop = 1; Loop < state.dataPurchasedAirMgr->NumPlenumArrays; ++Loop) {
    3596           0 :                 state.dataPurchasedAirMgr->PurchAirPlenumArrays(Loop).PurchAirArray.allocate(
    3597           0 :                     state.dataPurchasedAirMgr->TempPurchAirPlenumArrays(Loop).NumPurchAir);
    3598           0 :                 state.dataPurchasedAirMgr->PurchAirPlenumArrays(Loop).IsSimulated.allocate(
    3599           0 :                     state.dataPurchasedAirMgr->TempPurchAirPlenumArrays(Loop).NumPurchAir);
    3600             :             }
    3601             : 
    3602             :             // save the data
    3603           0 :             state.dataPurchasedAirMgr->PurchAirPlenumArrays = state.dataPurchasedAirMgr->TempPurchAirPlenumArrays;
    3604             :             // delete temporary data
    3605           0 :             state.dataPurchasedAirMgr->TempPurchAirPlenumArrays.deallocate();
    3606             : 
    3607             :             // save the index to where this ideal loads air system data is stored
    3608           0 :             state.dataPurchasedAirMgr->PurchAir(PurchAirNum).PurchAirArrayIndex = 1;
    3609             :             // save the number of ideal loads air systems stored in these arrays
    3610           0 :             state.dataPurchasedAirMgr->PurchAirPlenumArrays(state.dataPurchasedAirMgr->NumPlenumArrays).NumPurchAir = 1;
    3611             :             // save the index the the ZoneHVAC:ReturnPlenum
    3612           0 :             state.dataPurchasedAirMgr->PurchAirPlenumArrays(state.dataPurchasedAirMgr->NumPlenumArrays).ReturnPlenumIndex = ReturnPlenumIndex;
    3613             :             // allocate member array and store data
    3614           0 :             state.dataPurchasedAirMgr->PurchAirPlenumArrays(state.dataPurchasedAirMgr->NumPlenumArrays).PurchAirArray.allocate(1);
    3615           0 :             state.dataPurchasedAirMgr->PurchAirPlenumArrays(state.dataPurchasedAirMgr->NumPlenumArrays).PurchAirArray(1) = PurchAirNum;
    3616             :             // allocate member array and store data
    3617           0 :             state.dataPurchasedAirMgr->PurchAirPlenumArrays(state.dataPurchasedAirMgr->NumPlenumArrays).IsSimulated.allocate(1);
    3618           0 :             state.dataPurchasedAirMgr->PurchAirPlenumArrays(state.dataPurchasedAirMgr->NumPlenumArrays).IsSimulated(1) = false;
    3619             :         }
    3620             :     }
    3621           5 : }
    3622             : 
    3623             : } // namespace EnergyPlus::PurchasedAirManager

Generated by: LCOV version 1.14