LCOV - code coverage report
Current view: top level - EnergyPlus - PurchasedAirManager.cc (source / functions) Hit Total Coverage
Test: lcov.output.filtered Lines: 1150 1908 60.3 %
Date: 2023-01-17 19:17:23 Functions: 18 18 100.0 %

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

Generated by: LCOV version 1.13