LCOV - code coverage report
Current view: top level - EnergyPlus - HeatRecovery.cc (source / functions) Coverage Total Hit
Test: lcov.output.filtered Lines: 67.2 % 2664 1789
Test Date: 2025-06-02 07:23:51 Functions: 100.0 % 28 28

            Line data    Source code
       1              : // EnergyPlus, Copyright (c) 1996-2025, The Board of Trustees of the University of Illinois,
       2              : // The Regents of the University of California, through Lawrence Berkeley National Laboratory
       3              : // (subject to receipt of any required approvals from the U.S. Dept. of Energy), Oak Ridge
       4              : // National Laboratory, managed by UT-Battelle, Alliance for Sustainable Energy, LLC, and other
       5              : // contributors. All rights reserved.
       6              : //
       7              : // NOTICE: This Software was developed under funding from the U.S. Department of Energy and the
       8              : // U.S. Government consequently retains certain rights. As such, the U.S. Government has been
       9              : // granted for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable,
      10              : // worldwide license in the Software to reproduce, distribute copies to the public, prepare
      11              : // derivative works, and perform publicly and display publicly, and to permit others to do so.
      12              : //
      13              : // Redistribution and use in source and binary forms, with or without modification, are permitted
      14              : // provided that the following conditions are met:
      15              : //
      16              : // (1) Redistributions of source code must retain the above copyright notice, this list of
      17              : //     conditions and the following disclaimer.
      18              : //
      19              : // (2) Redistributions in binary form must reproduce the above copyright notice, this list of
      20              : //     conditions and the following disclaimer in the documentation and/or other materials
      21              : //     provided with the distribution.
      22              : //
      23              : // (3) Neither the name of the University of California, Lawrence Berkeley National Laboratory,
      24              : //     the University of Illinois, U.S. Dept. of Energy nor the names of its contributors may be
      25              : //     used to endorse or promote products derived from this software without specific prior
      26              : //     written permission.
      27              : //
      28              : // (4) Use of EnergyPlus(TM) Name. If Licensee (i) distributes the software in stand-alone form
      29              : //     without changes from the version obtained under this License, or (ii) Licensee makes a
      30              : //     reference solely to the software portion of its product, Licensee must refer to the
      31              : //     software as "EnergyPlus version X" software, where "X" is the version number Licensee
      32              : //     obtained under this License and may not use a different name for the software. Except as
      33              : //     specifically required in this Section (4), Licensee shall not use in a company name, a
      34              : //     product name, in advertising, publicity, or other promotional activities any name, trade
      35              : //     name, trademark, logo, or other designation of "EnergyPlus", "E+", "e+" or confusingly
      36              : //     similar designation, without the U.S. Department of Energy's prior written consent.
      37              : //
      38              : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
      39              : // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
      40              : // AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
      41              : // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
      42              : // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
      43              : // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      44              : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
      45              : // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
      46              : // POSSIBILITY OF SUCH DAMAGE.
      47              : 
      48              : // C++ Headers
      49              : #include <cmath>
      50              : 
      51              : // ObjexxFCL Headers
      52              : #include <ObjexxFCL/Fmath.hh>
      53              : 
      54              : // EnergyPlus Headers
      55              : #include <EnergyPlus/Autosizing/All_Simple_Sizing.hh>
      56              : #include <EnergyPlus/Autosizing/SystemAirFlowSizing.hh>
      57              : #include <EnergyPlus/BranchNodeConnections.hh>
      58              : #include <EnergyPlus/Coils/CoilCoolingDX.hh>
      59              : #include <EnergyPlus/CurveManager.hh>
      60              : #include <EnergyPlus/DXCoils.hh>
      61              : #include <EnergyPlus/Data/EnergyPlusData.hh>
      62              : #include <EnergyPlus/DataContaminantBalance.hh>
      63              : #include <EnergyPlus/DataHVACGlobals.hh>
      64              : #include <EnergyPlus/DataIPShortCuts.hh>
      65              : #include <EnergyPlus/DataLoopNode.hh>
      66              : #include <EnergyPlus/DataSizing.hh>
      67              : #include <EnergyPlus/EMSManager.hh>
      68              : #include <EnergyPlus/General.hh>
      69              : #include <EnergyPlus/GeneralRoutines.hh>
      70              : #include <EnergyPlus/GlobalNames.hh>
      71              : #include <EnergyPlus/HeatRecovery.hh>
      72              : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
      73              : #include <EnergyPlus/NodeInputManager.hh>
      74              : #include <EnergyPlus/OutputProcessor.hh>
      75              : #include <EnergyPlus/OutputReportPredefined.hh>
      76              : #include <EnergyPlus/Psychrometrics.hh>
      77              : #include <EnergyPlus/ScheduleManager.hh>
      78              : #include <EnergyPlus/UtilityRoutines.hh>
      79              : #include <EnergyPlus/VariableSpeedCoils.hh>
      80              : 
      81              : namespace EnergyPlus {
      82              : 
      83              : namespace HeatRecovery {
      84              : 
      85              :     // Module containing the routines dealing with heat recovery from exhaust or relief air
      86              : 
      87              :     // MODULE INFORMATION:
      88              :     //       AUTHOR         Michael Wetter
      89              :     //       DATE WRITTEN   March 1999
      90              :     //       MODIFIED       F Buhl Nov 2000, D Shirey Feb 2003, R. Raustad April 2003
      91              :     //       RE-ENGINEERED  na
      92              : 
      93              :     // PURPOSE OF THIS MODULE:
      94              :     // To encapsulate the data and routines required to model heat
      95              :     // recovery components in the EnergyPlus HVAC simulation
      96              : 
      97              :     // METHODOLOGY EMPLOYED:
      98              :     // Heat exchanger effectiveness - NTU models are used.
      99              : 
     100              :     // REFERENCES:
     101              :     // M. Wetter, Simulation Model Air-to-Air Plate Heat Exchanger,LBNL Report 42354, 1999.
     102              :     // ARI Standard 1060-2001,Rating Air-to-Air Heat Exchangers for Energy Recovery Ventilation Equipment, www.ari.org
     103              :     // ASHRAE Standard 84, Method of Testing Air-To-Air Heat Exchangers, www.ashrae.org
     104              :     // U.S. Environmental Protection Agency software "SAVES" -
     105              :     //  School Advanced Ventilation Engineering Software http://www.epa.gov/iaq/schooldesign/saves.html
     106              : 
     107              :     Real64 constexpr KELVZERO = 273.16;
     108              :     Real64 constexpr SMALL = 1.e-10;
     109              :     constexpr std::array<std::string_view, static_cast<int>(FrostControlOption::Num)> frostControlNamesUC = {
     110              :         "NONE", "EXHAUSTONLY", "EXHAUSTAIRRECIRCULATION", "MINIMUMEXHAUSTTEMPERATURE"};
     111              : 
     112              :     constexpr std::array<std::string_view, static_cast<int>(HXConfigurationType::Num)> hxConfigurationNames = {"Plate", "Rotary"};
     113              : 
     114              :     constexpr std::array<std::string_view, static_cast<int>(HXConfigurationType::Num)> hxConfigurationNamesUC = {"PLATE", "ROTARY"};
     115              : 
     116      3904968 :     void SimHeatRecovery(EnergyPlusData &state,
     117              :                          std::string_view CompName,                          // name of the heat exchanger unit
     118              :                          bool const FirstHVACIteration,                      // TRUE if 1st HVAC simulation of system timestep
     119              :                          int &CompIndex,                                     // Pointer to Component
     120              :                          HVAC::FanOp const fanOp,                            // Supply air fan operating mode
     121              :                          ObjexxFCL::Optional<Real64 const> HXPartLoadRatio,  // Part load ratio requested of DX compressor
     122              :                          ObjexxFCL::Optional_bool_const HXUnitEnable,        // Flag to operate heat exchanger
     123              :                          ObjexxFCL::Optional_int_const CompanionCoilIndex,   // index of companion cooling coil
     124              :                          ObjexxFCL::Optional_bool_const RegenInletIsOANode,  // flag to determine if supply inlet is OA node, if so air flow cycles
     125              :                          ObjexxFCL::Optional_bool_const EconomizerFlag,      // economizer operation flag passed by airloop or OA sys
     126              :                          ObjexxFCL::Optional_bool_const HighHumCtrlFlag,     // high humidity control flag passed by airloop or OA sys
     127              :                          ObjexxFCL::Optional_int_const CompanionCoilType_Num // cooling coil type of coil
     128              :     )
     129              :     {
     130              : 
     131              :         // SUBROUTINE INFORMATION:
     132              :         //       AUTHOR         Michael Wetter
     133              :         //       DATE WRITTEN   March 1999
     134              :         //       MODIFIED       Fred Buhl November 2000, R. Raustad FSEC - Feb 2009
     135              :         //       RE-ENGINEERED  na
     136              : 
     137              :         // PURPOSE OF THIS SUBROUTINE:
     138              :         // Manage the simulation of a heat recovery unit
     139              : 
     140      3904968 :         if (state.dataHeatRecovery->GetInputFlag) {
     141           26 :             GetHeatRecoveryInput(state);
     142           26 :             state.dataHeatRecovery->GetInputFlag = false;
     143              :         }
     144              : 
     145              :         // Find the correct unit index
     146              :         int HeatExchNum; // index of unit being simulated
     147      3904968 :         if (CompIndex == 0) {
     148          162 :             HeatExchNum = Util::FindItemInList(CompName, state.dataHeatRecovery->ExchCond);
     149          162 :             if (HeatExchNum == 0) {
     150            0 :                 ShowFatalError(state, format("SimHeatRecovery: Unit not found={}", CompName));
     151              :             }
     152          162 :             CompIndex = HeatExchNum;
     153              :         } else {
     154      3904806 :             HeatExchNum = CompIndex;
     155      3904806 :             if (HeatExchNum > state.dataHeatRecovery->NumHeatExchangers || HeatExchNum < 1) {
     156            0 :                 ShowFatalError(state,
     157            0 :                                format("SimHeatRecovery:  Invalid CompIndex passed={}, Number of Units={}, Entered Unit name={}",
     158              :                                       HeatExchNum,
     159            0 :                                       state.dataHeatRecovery->NumHeatExchangers,
     160              :                                       CompName));
     161              :             }
     162      3904806 :             if (state.dataHeatRecovery->CheckEquipName(HeatExchNum)) {
     163          162 :                 if (CompName != state.dataHeatRecovery->ExchCond(HeatExchNum).Name) {
     164            0 :                     ShowFatalError(state,
     165            0 :                                    format("SimHeatRecovery: Invalid CompIndex passed={}, Unit name={}, stored Unit Name for that index={}",
     166              :                                           HeatExchNum,
     167              :                                           CompName,
     168            0 :                                           state.dataHeatRecovery->ExchCond(HeatExchNum).Name));
     169              :                 }
     170          162 :                 state.dataHeatRecovery->CheckEquipName(HeatExchNum) = false;
     171              :             }
     172              :         }
     173              : 
     174      3904968 :         int CompanionCoilNum = present(CompanionCoilIndex) ? int(CompanionCoilIndex) : -1; // Index to companion cooling coil
     175      3904968 :         int companionCoilType = present(CompanionCoilType_Num) ? int(CompanionCoilType_Num) : -1;
     176              : 
     177              :         bool HXUnitOn; // flag to enable heat exchanger
     178      3904968 :         if (present(HXUnitEnable)) {
     179      2068438 :             HXUnitOn = HXUnitEnable;
     180              :             //   When state.dataHeatRecovery->CalledFromParentObject is TRUE, this SIM routine was called by a parent object that passed in
     181              :             //   HXUnitEnable. HX will use the DX coil part-load ratio (optional CompanionCoilIndex must be present) or PLR passed in if not used with
     182              :             //   DX coil (optional CompanionCoilIndex must not be present).
     183      2068438 :             state.dataHeatRecovery->CalledFromParentObject = true;
     184              :         } else {
     185              :             //   HX is placed on a BRANCH, optional arguments are not passed in from SimAirServingZones.
     186              :             //   HX will calculate its own part-load ratio if optional HXUnitEnable flag is not present
     187      1836530 :             if (present(HXPartLoadRatio)) {
     188      1762205 :                 HXUnitOn = (HXPartLoadRatio > 0.0);
     189              :             } else {
     190        74325 :                 HXUnitOn = true;
     191              :             }
     192      1836530 :             state.dataHeatRecovery->CalledFromParentObject = false;
     193              :         }
     194              : 
     195      3904968 :         auto &thisExch = state.dataHeatRecovery->ExchCond(HeatExchNum);
     196              : 
     197      3904968 :         thisExch.initialize(state, CompanionCoilNum, companionCoilType);
     198              : 
     199              :         // call the correct heat exchanger calculation routine
     200      3904968 :         switch (state.dataHeatRecovery->ExchCond(HeatExchNum).type) {
     201       771556 :         case HVAC::HXType::AirToAir_FlatPlate: {
     202       771556 :             thisExch.CalcAirToAirPlateHeatExch(state, HXUnitOn, EconomizerFlag, HighHumCtrlFlag);
     203       771556 :         } break;
     204              : 
     205      2460883 :         case HVAC::HXType::AirToAir_SensAndLatent: {
     206      2460883 :             thisExch.CalcAirToAirGenericHeatExch(state, HXUnitOn, FirstHVACIteration, fanOp, EconomizerFlag, HighHumCtrlFlag, HXPartLoadRatio);
     207      2460883 :         } break;
     208              : 
     209       672529 :         case HVAC::HXType::Desiccant_Balanced: {
     210       672529 :             Real64 PartLoadRatio = present(HXPartLoadRatio) ? Real64(HXPartLoadRatio) : 1.0; // Part load ratio requested of DX compressor
     211       672529 :             bool RegInIsOANode = present(RegenInletIsOANode) && bool(RegenInletIsOANode);
     212       672529 :             thisExch.CalcDesiccantBalancedHeatExch(state,
     213              :                                                    HXUnitOn,
     214              :                                                    FirstHVACIteration,
     215              :                                                    fanOp,
     216              :                                                    PartLoadRatio,
     217              :                                                    CompanionCoilNum,
     218              :                                                    companionCoilType,
     219              :                                                    RegInIsOANode,
     220              :                                                    EconomizerFlag,
     221              :                                                    HighHumCtrlFlag);
     222       672529 :         } break;
     223              : 
     224            0 :         default: {
     225            0 :             assert(false);
     226              :         } break;
     227              :         }
     228              : 
     229      3904968 :         thisExch.UpdateHeatRecovery(state);
     230              : 
     231      3904968 :         thisExch.ReportHeatRecovery(state);
     232      3904968 :     }
     233              : 
     234           44 :     void GetHeatRecoveryInput(EnergyPlusData &state)
     235              :     {
     236              : 
     237              :         // SUBROUTINE INFORMATION:
     238              :         //       AUTHOR         Michael Wetter
     239              :         //       DATE WRITTEN   March 1999
     240              :         //       MODIFIED       F Buhl Nov 2000, D Shirey Feb 2003, R. Raustad FSEC - Feb 2009 (EconoLockout inputs)
     241              :         //       RE-ENGINEERED  na
     242              : 
     243              :         // PURPOSE OF THIS SUBROUTINE:
     244              :         // Obtains input data for heat recovery units and stores it in
     245              :         // appropriate data structures.
     246              : 
     247              :         // METHODOLOGY EMPLOYED:
     248              :         // Uses InputProcessor "Get" routines to obtain data.
     249              : 
     250              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     251              :         int NumAlphas;                                                     // Number of Alphas for each GetObjectItem call
     252              :         int NumNumbers;                                                    // Number of Numbers for each GetObjectItem call
     253              :         int IOStatus;                                                      // Used in GetObjectItem
     254           44 :         bool ErrorsFound(false);                                           // Set to true if errors in input, fatal at end of routine
     255           44 :         constexpr std::string_view RoutineName = "GetHeatRecoveryInput: "; // include trailing blank space
     256           44 :         constexpr std::string_view routineName = "GetHeatRecoveryInput";
     257           44 :         auto &cCurrentModuleObject = state.dataIPShortCut->cCurrentModuleObject;
     258              : 
     259           44 :         int NumAirToAirPlateExchs = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "HeatExchanger:AirToAir:FlatPlate");
     260              :         int NumAirToAirGenericExchs =
     261           44 :             state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "HeatExchanger:AirToAir:SensibleAndLatent");
     262           44 :         int NumDesiccantBalancedExchs = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "HeatExchanger:Desiccant:BalancedFlow");
     263              :         int NumDesBalExchsPerfDataType1 =
     264           44 :             state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "HeatExchanger:Desiccant:BalancedFlow:PerformanceDataType1");
     265           44 :         state.dataHeatRecovery->NumHeatExchangers = NumAirToAirPlateExchs + NumAirToAirGenericExchs + NumDesiccantBalancedExchs;
     266              : 
     267              :         // allocate the data array
     268           44 :         state.dataHeatRecovery->ExchCond.allocate(state.dataHeatRecovery->NumHeatExchangers);
     269           44 :         state.dataHeatRecovery->HeatExchangerUniqueNames.reserve(state.dataHeatRecovery->NumHeatExchangers);
     270           44 :         state.dataHeatRecovery->CheckEquipName.dimension(state.dataHeatRecovery->NumHeatExchangers, true);
     271              : 
     272           44 :         if (NumDesBalExchsPerfDataType1 > 0) {
     273            5 :             state.dataHeatRecovery->BalDesDehumPerfData.allocate(NumDesBalExchsPerfDataType1);
     274              :         }
     275              : 
     276              :         // loop over the air to air plate heat exchangers and load their input data
     277           58 :         for (int ExchIndex = 1; ExchIndex <= NumAirToAirPlateExchs; ++ExchIndex) {
     278           14 :             cCurrentModuleObject = "HeatExchanger:AirToAir:FlatPlate";
     279           28 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
     280              :                                                                      cCurrentModuleObject,
     281              :                                                                      ExchIndex,
     282           14 :                                                                      state.dataIPShortCut->cAlphaArgs,
     283              :                                                                      NumAlphas,
     284           14 :                                                                      state.dataIPShortCut->rNumericArgs,
     285              :                                                                      NumNumbers,
     286              :                                                                      IOStatus,
     287           14 :                                                                      state.dataIPShortCut->lNumericFieldBlanks,
     288           14 :                                                                      state.dataIPShortCut->lAlphaFieldBlanks,
     289           14 :                                                                      state.dataIPShortCut->cAlphaFieldNames,
     290           14 :                                                                      state.dataIPShortCut->cNumericFieldNames);
     291              : 
     292           14 :             ErrorObjectHeader eoh{routineName, cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)};
     293           14 :             int const ExchNum = ExchIndex;
     294           14 :             auto &thisExchanger = state.dataHeatRecovery->ExchCond(ExchNum);
     295           14 :             thisExchanger.NumericFieldNames.allocate(NumNumbers);
     296           14 :             thisExchanger.NumericFieldNames = state.dataIPShortCut->cNumericFieldNames;
     297              : 
     298           14 :             GlobalNames::VerifyUniqueInterObjectName(state,
     299           14 :                                                      state.dataHeatRecovery->HeatExchangerUniqueNames,
     300           14 :                                                      state.dataIPShortCut->cAlphaArgs(1),
     301              :                                                      cCurrentModuleObject,
     302           14 :                                                      state.dataIPShortCut->cAlphaFieldNames(1),
     303              :                                                      ErrorsFound);
     304              : 
     305           14 :             thisExchanger.Name = state.dataIPShortCut->cAlphaArgs(1);
     306           14 :             thisExchanger.type = HVAC::HXType::AirToAir_FlatPlate;
     307           14 :             thisExchanger.ExchConfig = HXConfigurationType::Plate;
     308           14 :             if (state.dataIPShortCut->lAlphaFieldBlanks(2)) {
     309            0 :                 thisExchanger.availSched = Sched::GetScheduleAlwaysOn(state);
     310           14 :             } else if ((thisExchanger.availSched = Sched::GetSchedule(state, state.dataIPShortCut->cAlphaArgs(2))) == nullptr) {
     311            0 :                 ShowSevereItemNotFound(state, eoh, state.dataIPShortCut->cAlphaFieldNames(2), state.dataIPShortCut->cAlphaArgs(2));
     312            0 :                 ErrorsFound = true;
     313              :             }
     314              : 
     315           14 :             constexpr std::array<std::string_view, static_cast<int>(HXConfiguration::Num)> hxConfigurationNamesUC = {
     316              :                 "COUNTERFLOW", "PARALLELFLOW", "CROSSFLOWBOTHUNMIXED", "CROSS_FLOW_OTHER_NOT_USED"};
     317           14 :             thisExchanger.FlowArr = static_cast<HXConfiguration>(getEnumValue(hxConfigurationNamesUC, state.dataIPShortCut->cAlphaArgs(3)));
     318           14 :             if (thisExchanger.FlowArr == HXConfiguration::Invalid) {
     319            0 :                 ShowSevereError(state, format("{}: incorrect flow arrangement: {}", cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(3)));
     320            0 :                 ErrorsFound = true;
     321              :             }
     322              : 
     323           14 :             if (state.dataIPShortCut->lAlphaFieldBlanks(4)) {
     324            0 :                 thisExchanger.EconoLockOut = true;
     325              :             } else {
     326           14 :                 BooleanSwitch toggle = getYesNoValue(state.dataIPShortCut->cAlphaArgs(4));
     327           14 :                 if (toggle == BooleanSwitch::Invalid) {
     328            0 :                     ShowSevereError(state, format("{}: incorrect econo lockout: {}", cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(4)));
     329              :                 }
     330           14 :                 thisExchanger.EconoLockOut = static_cast<bool>(toggle);
     331              :             }
     332              : 
     333           14 :             thisExchanger.hARatio = state.dataIPShortCut->rNumericArgs(1);
     334           14 :             thisExchanger.NomSupAirVolFlow = state.dataIPShortCut->rNumericArgs(2);
     335           14 :             thisExchanger.NomSupAirInTemp = state.dataIPShortCut->rNumericArgs(3);
     336           14 :             thisExchanger.NomSupAirOutTemp = state.dataIPShortCut->rNumericArgs(4);
     337           14 :             thisExchanger.NomSecAirVolFlow = state.dataIPShortCut->rNumericArgs(5);
     338           14 :             thisExchanger.NomSecAirInTemp = state.dataIPShortCut->rNumericArgs(6);
     339           14 :             thisExchanger.NomElecPower = state.dataIPShortCut->rNumericArgs(7);
     340           14 :             thisExchanger.SupInletNode = GetOnlySingleNode(state,
     341           14 :                                                            state.dataIPShortCut->cAlphaArgs(5),
     342              :                                                            ErrorsFound,
     343              :                                                            DataLoopNode::ConnectionObjectType::HeatExchangerAirToAirFlatPlate,
     344           14 :                                                            thisExchanger.Name,
     345              :                                                            DataLoopNode::NodeFluidType::Air,
     346              :                                                            DataLoopNode::ConnectionType::Inlet,
     347              :                                                            NodeInputManager::CompFluidStream::Primary,
     348              :                                                            DataLoopNode::ObjectIsNotParent);
     349           14 :             thisExchanger.SupOutletNode = GetOnlySingleNode(state,
     350           14 :                                                             state.dataIPShortCut->cAlphaArgs(6),
     351              :                                                             ErrorsFound,
     352              :                                                             DataLoopNode::ConnectionObjectType::HeatExchangerAirToAirFlatPlate,
     353           14 :                                                             thisExchanger.Name,
     354              :                                                             DataLoopNode::NodeFluidType::Air,
     355              :                                                             DataLoopNode::ConnectionType::Outlet,
     356              :                                                             NodeInputManager::CompFluidStream::Primary,
     357              :                                                             DataLoopNode::ObjectIsNotParent);
     358           14 :             thisExchanger.SecInletNode = GetOnlySingleNode(state,
     359           14 :                                                            state.dataIPShortCut->cAlphaArgs(7),
     360              :                                                            ErrorsFound,
     361              :                                                            DataLoopNode::ConnectionObjectType::HeatExchangerAirToAirFlatPlate,
     362           14 :                                                            thisExchanger.Name,
     363              :                                                            DataLoopNode::NodeFluidType::Air,
     364              :                                                            DataLoopNode::ConnectionType::Inlet,
     365              :                                                            NodeInputManager::CompFluidStream::Secondary,
     366              :                                                            DataLoopNode::ObjectIsNotParent);
     367           28 :             thisExchanger.SecOutletNode = GetOnlySingleNode(state,
     368           14 :                                                             state.dataIPShortCut->cAlphaArgs(8),
     369              :                                                             ErrorsFound,
     370              :                                                             DataLoopNode::ConnectionObjectType::HeatExchangerAirToAirFlatPlate,
     371           14 :                                                             thisExchanger.Name,
     372              :                                                             DataLoopNode::NodeFluidType::Air,
     373              :                                                             DataLoopNode::ConnectionType::Outlet,
     374              :                                                             NodeInputManager::CompFluidStream::Secondary,
     375              :                                                             DataLoopNode::ObjectIsNotParent);
     376              : 
     377           42 :             BranchNodeConnections::TestCompSet(state,
     378           14 :                                                HVAC::hxTypeNames[(int)thisExchanger.type],
     379              :                                                thisExchanger.Name,
     380           14 :                                                state.dataIPShortCut->cAlphaArgs(5),
     381           14 :                                                state.dataIPShortCut->cAlphaArgs(6),
     382              :                                                "Process Air Nodes");
     383              : 
     384              :         } // end of input loop over air to air plate heat exchangers
     385              : 
     386              :         // loop over the air to air generic heat exchangers and load their input data
     387          185 :         for (int ExchIndex = 1; ExchIndex <= NumAirToAirGenericExchs; ++ExchIndex) {
     388          141 :             cCurrentModuleObject = "HeatExchanger:AirToAir:SensibleAndLatent";
     389          282 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
     390              :                                                                      cCurrentModuleObject,
     391              :                                                                      ExchIndex,
     392          141 :                                                                      state.dataIPShortCut->cAlphaArgs,
     393              :                                                                      NumAlphas,
     394          141 :                                                                      state.dataIPShortCut->rNumericArgs,
     395              :                                                                      NumNumbers,
     396              :                                                                      IOStatus,
     397          141 :                                                                      state.dataIPShortCut->lNumericFieldBlanks,
     398          141 :                                                                      state.dataIPShortCut->lAlphaFieldBlanks,
     399          141 :                                                                      state.dataIPShortCut->cAlphaFieldNames,
     400          141 :                                                                      state.dataIPShortCut->cNumericFieldNames);
     401              : 
     402          141 :             ErrorObjectHeader eoh{routineName, cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)};
     403          141 :             int const ExchNum = ExchIndex + NumAirToAirPlateExchs;
     404          141 :             auto &thisExchanger = state.dataHeatRecovery->ExchCond(ExchNum);
     405          141 :             thisExchanger.NumericFieldNames.allocate(NumNumbers);
     406          141 :             thisExchanger.NumericFieldNames = state.dataIPShortCut->cNumericFieldNames;
     407              : 
     408          141 :             GlobalNames::VerifyUniqueInterObjectName(state,
     409          141 :                                                      state.dataHeatRecovery->HeatExchangerUniqueNames,
     410          141 :                                                      state.dataIPShortCut->cAlphaArgs(1),
     411              :                                                      cCurrentModuleObject,
     412          141 :                                                      state.dataIPShortCut->cAlphaFieldNames(1),
     413              :                                                      ErrorsFound);
     414              : 
     415          141 :             thisExchanger.Name = state.dataIPShortCut->cAlphaArgs(1);
     416          141 :             thisExchanger.type = HVAC::HXType::AirToAir_SensAndLatent;
     417          141 :             if (state.dataIPShortCut->lAlphaFieldBlanks(2)) {
     418            3 :                 thisExchanger.availSched = Sched::GetScheduleAlwaysOn(state);
     419          138 :             } else if ((thisExchanger.availSched = Sched::GetSchedule(state, state.dataIPShortCut->cAlphaArgs(2))) == nullptr) {
     420            0 :                 ShowSevereItemNotFound(state, eoh, state.dataIPShortCut->cAlphaFieldNames(2), state.dataIPShortCut->cAlphaArgs(2));
     421            0 :                 ErrorsFound = true;
     422              :             }
     423          141 :             thisExchanger.NomSupAirVolFlow = state.dataIPShortCut->rNumericArgs(1);
     424          141 :             thisExchanger.HeatEffectSensible100 = state.dataIPShortCut->rNumericArgs(2);
     425          141 :             thisExchanger.HeatEffectLatent100 = state.dataIPShortCut->rNumericArgs(3);
     426          141 :             thisExchanger.CoolEffectSensible100 = state.dataIPShortCut->rNumericArgs(4);
     427          141 :             thisExchanger.CoolEffectLatent100 = state.dataIPShortCut->rNumericArgs(5);
     428          141 :             thisExchanger.SupInletNode = GetOnlySingleNode(state,
     429          141 :                                                            state.dataIPShortCut->cAlphaArgs(3),
     430              :                                                            ErrorsFound,
     431              :                                                            DataLoopNode::ConnectionObjectType::HeatExchangerAirToAirSensibleAndLatent,
     432          141 :                                                            thisExchanger.Name,
     433              :                                                            DataLoopNode::NodeFluidType::Air,
     434              :                                                            DataLoopNode::ConnectionType::Inlet,
     435              :                                                            NodeInputManager::CompFluidStream::Primary,
     436              :                                                            DataLoopNode::ObjectIsNotParent);
     437          141 :             thisExchanger.SupOutletNode = GetOnlySingleNode(state,
     438          141 :                                                             state.dataIPShortCut->cAlphaArgs(4),
     439              :                                                             ErrorsFound,
     440              :                                                             DataLoopNode::ConnectionObjectType::HeatExchangerAirToAirSensibleAndLatent,
     441          141 :                                                             thisExchanger.Name,
     442              :                                                             DataLoopNode::NodeFluidType::Air,
     443              :                                                             DataLoopNode::ConnectionType::Outlet,
     444              :                                                             NodeInputManager::CompFluidStream::Primary,
     445              :                                                             DataLoopNode::ObjectIsNotParent);
     446          141 :             thisExchanger.SecInletNode = GetOnlySingleNode(state,
     447          141 :                                                            state.dataIPShortCut->cAlphaArgs(5),
     448              :                                                            ErrorsFound,
     449              :                                                            DataLoopNode::ConnectionObjectType::HeatExchangerAirToAirSensibleAndLatent,
     450          141 :                                                            thisExchanger.Name,
     451              :                                                            DataLoopNode::NodeFluidType::Air,
     452              :                                                            DataLoopNode::ConnectionType::Inlet,
     453              :                                                            NodeInputManager::CompFluidStream::Secondary,
     454              :                                                            DataLoopNode::ObjectIsNotParent);
     455          141 :             thisExchanger.SecOutletNode = GetOnlySingleNode(state,
     456          141 :                                                             state.dataIPShortCut->cAlphaArgs(6),
     457              :                                                             ErrorsFound,
     458              :                                                             DataLoopNode::ConnectionObjectType::HeatExchangerAirToAirSensibleAndLatent,
     459          141 :                                                             thisExchanger.Name,
     460              :                                                             DataLoopNode::NodeFluidType::Air,
     461              :                                                             DataLoopNode::ConnectionType::Outlet,
     462              :                                                             NodeInputManager::CompFluidStream::Secondary,
     463              :                                                             DataLoopNode::ObjectIsNotParent);
     464              : 
     465          141 :             thisExchanger.NomElecPower = state.dataIPShortCut->rNumericArgs(6);
     466              : 
     467          141 :             if (Util::SameString(state.dataIPShortCut->cAlphaArgs(7), "Yes")) {
     468           19 :                 thisExchanger.ControlToTemperatureSetPoint = true;
     469              :             } else {
     470          122 :                 if (!Util::SameString(state.dataIPShortCut->cAlphaArgs(7), "No")) {
     471            0 :                     ShowSevereError(state, "Rotary HX Speed Modulation or Plate Bypass for Temperature Control for ");
     472            0 :                     ShowContinueError(state, format("{} must be set to Yes or No", thisExchanger.Name));
     473            0 :                     ErrorsFound = true;
     474              :                 }
     475              :             }
     476              : 
     477          141 :             thisExchanger.ExchConfig = static_cast<HXConfigurationType>(getEnumValue(hxConfigurationNamesUC, state.dataIPShortCut->cAlphaArgs(8)));
     478              : 
     479              :             // Added additional inputs for frost control
     480          141 :             thisExchanger.FrostControlType = static_cast<FrostControlOption>(getEnumValue(frostControlNamesUC, state.dataIPShortCut->cAlphaArgs(9)));
     481              : 
     482          141 :             if (thisExchanger.FrostControlType != FrostControlOption::None) {
     483          128 :                 thisExchanger.ThresholdTemperature = state.dataIPShortCut->rNumericArgs(7);
     484          128 :                 thisExchanger.InitialDefrostTime = state.dataIPShortCut->rNumericArgs(8);
     485          128 :                 thisExchanger.RateofDefrostTimeIncrease = state.dataIPShortCut->rNumericArgs(9);
     486              :             }
     487              : 
     488          141 :             if (state.dataIPShortCut->lAlphaFieldBlanks(10)) {
     489          113 :                 thisExchanger.EconoLockOut = true;
     490              :             } else {
     491           28 :                 BooleanSwitch toggle = getYesNoValue(state.dataIPShortCut->cAlphaArgs(10));
     492           28 :                 if (toggle == BooleanSwitch::Invalid) {
     493            0 :                     ShowSevereError(state, format("{}: incorrect econo lockout: {}", cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(10)));
     494              :                 }
     495           28 :                 thisExchanger.EconoLockOut = static_cast<bool>(toggle);
     496              :             }
     497              : 
     498              :             // read new curves here
     499          141 :             thisExchanger.HeatEffectSensibleCurveIndex =
     500          141 :                 Curve::GetCurveIndex(state, state.dataIPShortCut->cAlphaArgs(11)); // convert curve name to number
     501          141 :             thisExchanger.HeatEffectLatentCurveIndex =
     502          141 :                 Curve::GetCurveIndex(state, state.dataIPShortCut->cAlphaArgs(12)); // convert curve name to number
     503          141 :             thisExchanger.CoolEffectSensibleCurveIndex =
     504          141 :                 Curve::GetCurveIndex(state, state.dataIPShortCut->cAlphaArgs(13)); // convert curve name to number
     505          141 :             thisExchanger.CoolEffectLatentCurveIndex =
     506          141 :                 Curve::GetCurveIndex(state, state.dataIPShortCut->cAlphaArgs(14)); // convert curve name to number
     507              : 
     508          423 :             BranchNodeConnections::TestCompSet(state,
     509          141 :                                                HVAC::hxTypeNames[(int)thisExchanger.type],
     510              :                                                thisExchanger.Name,
     511          141 :                                                state.dataIPShortCut->cAlphaArgs(3),
     512          141 :                                                state.dataIPShortCut->cAlphaArgs(4),
     513              :                                                "Process Air Nodes");
     514              :         } // end of input loop over air to air generic heat exchangers
     515              : 
     516              :         // loop over the desiccant balanced heat exchangers and load their input data
     517           51 :         for (int ExchIndex = 1; ExchIndex <= NumDesiccantBalancedExchs; ++ExchIndex) {
     518            7 :             cCurrentModuleObject = "HeatExchanger:Desiccant:BalancedFlow";
     519           14 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
     520              :                                                                      cCurrentModuleObject,
     521              :                                                                      ExchIndex,
     522            7 :                                                                      state.dataIPShortCut->cAlphaArgs,
     523              :                                                                      NumAlphas,
     524            7 :                                                                      state.dataIPShortCut->rNumericArgs,
     525              :                                                                      NumNumbers,
     526              :                                                                      IOStatus,
     527            7 :                                                                      state.dataIPShortCut->lNumericFieldBlanks,
     528            7 :                                                                      state.dataIPShortCut->lAlphaFieldBlanks,
     529            7 :                                                                      state.dataIPShortCut->cAlphaFieldNames,
     530            7 :                                                                      state.dataIPShortCut->cNumericFieldNames);
     531              : 
     532            7 :             ErrorObjectHeader eoh{routineName, cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)};
     533              : 
     534            7 :             int const ExchNum = ExchIndex + NumAirToAirPlateExchs + NumAirToAirGenericExchs;
     535            7 :             auto &thisExchanger = state.dataHeatRecovery->ExchCond(ExchNum);
     536            7 :             thisExchanger.NumericFieldNames.allocate(NumNumbers);
     537            7 :             thisExchanger.NumericFieldNames = state.dataIPShortCut->cNumericFieldNames;
     538              : 
     539            7 :             GlobalNames::VerifyUniqueInterObjectName(state,
     540            7 :                                                      state.dataHeatRecovery->HeatExchangerUniqueNames,
     541            7 :                                                      state.dataIPShortCut->cAlphaArgs(1),
     542              :                                                      cCurrentModuleObject,
     543            7 :                                                      state.dataIPShortCut->cAlphaFieldNames(1),
     544              :                                                      ErrorsFound);
     545              : 
     546            7 :             thisExchanger.Name = state.dataIPShortCut->cAlphaArgs(1);
     547            7 :             thisExchanger.type = HVAC::HXType::Desiccant_Balanced;
     548            7 :             thisExchanger.ExchConfig = HXConfigurationType::Rotary;
     549            7 :             if (state.dataIPShortCut->lAlphaFieldBlanks(2)) {
     550            0 :                 thisExchanger.availSched = Sched::GetScheduleAlwaysOn(state);
     551            7 :             } else if ((thisExchanger.availSched = Sched::GetSchedule(state, state.dataIPShortCut->cAlphaArgs(2))) == nullptr) {
     552            0 :                 ShowSevereItemNotFound(state, eoh, state.dataIPShortCut->cAlphaFieldNames(2), state.dataIPShortCut->cAlphaArgs(2));
     553            0 :                 ErrorsFound = true;
     554              :             }
     555              :             // desiccant HX's usually refer to process and regeneration air streams
     556              :             // In this module, Sup = Regeneration nodes and Sec = Process nodes
     557              :             // regeneration air inlet and outlet nodes
     558            7 :             thisExchanger.SupInletNode = GetOnlySingleNode(state,
     559            7 :                                                            state.dataIPShortCut->cAlphaArgs(3),
     560              :                                                            ErrorsFound,
     561              :                                                            DataLoopNode::ConnectionObjectType::HeatExchangerDesiccantBalancedFlow,
     562            7 :                                                            thisExchanger.Name,
     563              :                                                            DataLoopNode::NodeFluidType::Air,
     564              :                                                            DataLoopNode::ConnectionType::Inlet,
     565              :                                                            NodeInputManager::CompFluidStream::Primary,
     566              :                                                            DataLoopNode::ObjectIsNotParent);
     567            7 :             thisExchanger.SupOutletNode = GetOnlySingleNode(state,
     568            7 :                                                             state.dataIPShortCut->cAlphaArgs(4),
     569              :                                                             ErrorsFound,
     570              :                                                             DataLoopNode::ConnectionObjectType::HeatExchangerDesiccantBalancedFlow,
     571            7 :                                                             thisExchanger.Name,
     572              :                                                             DataLoopNode::NodeFluidType::Air,
     573              :                                                             DataLoopNode::ConnectionType::Outlet,
     574              :                                                             NodeInputManager::CompFluidStream::Primary,
     575              :                                                             DataLoopNode::ObjectIsNotParent);
     576              :             // process air inlet and outlet nodes
     577            7 :             thisExchanger.SecInletNode = GetOnlySingleNode(state,
     578            7 :                                                            state.dataIPShortCut->cAlphaArgs(5),
     579              :                                                            ErrorsFound,
     580              :                                                            DataLoopNode::ConnectionObjectType::HeatExchangerDesiccantBalancedFlow,
     581            7 :                                                            thisExchanger.Name,
     582              :                                                            DataLoopNode::NodeFluidType::Air,
     583              :                                                            DataLoopNode::ConnectionType::Inlet,
     584              :                                                            NodeInputManager::CompFluidStream::Secondary,
     585              :                                                            DataLoopNode::ObjectIsNotParent);
     586           14 :             thisExchanger.SecOutletNode = GetOnlySingleNode(state,
     587            7 :                                                             state.dataIPShortCut->cAlphaArgs(6),
     588              :                                                             ErrorsFound,
     589              :                                                             DataLoopNode::ConnectionObjectType::HeatExchangerDesiccantBalancedFlow,
     590            7 :                                                             thisExchanger.Name,
     591              :                                                             DataLoopNode::NodeFluidType::Air,
     592              :                                                             DataLoopNode::ConnectionType::Outlet,
     593              :                                                             NodeInputManager::CompFluidStream::Secondary,
     594              :                                                             DataLoopNode::ObjectIsNotParent);
     595              : 
     596              :             // Set up the component set for the process side of the HX (Sec = Process)
     597           14 :             BranchNodeConnections::TestCompSet(state,
     598            7 :                                                HVAC::hxTypeNames[(int)thisExchanger.type],
     599              :                                                thisExchanger.Name,
     600            7 :                                                state.dataLoopNodes->NodeID(thisExchanger.SecInletNode),
     601            7 :                                                state.dataLoopNodes->NodeID(thisExchanger.SecOutletNode),
     602              :                                                "Process Air Nodes");
     603              : 
     604              :             // A7 is the heat exchanger performance object type
     605              :             // It currently only has one choice key, with a default value, so currently no logic is needed
     606              :             // In the future if someone added another performance type, the logic could be added back here
     607              :             // HeatExchPerfType = state.dataIPShortCut->cAlphaArgs(7);
     608              : 
     609            7 :             thisExchanger.HeatExchPerfName = state.dataIPShortCut->cAlphaArgs(8);
     610              : 
     611            7 :             if (state.dataIPShortCut->lAlphaFieldBlanks(9)) {
     612            7 :                 thisExchanger.EconoLockOut = true;
     613              :             } else {
     614            0 :                 BooleanSwitch toggle = getYesNoValue(state.dataIPShortCut->cAlphaArgs(9));
     615            0 :                 if (toggle == BooleanSwitch::Invalid) {
     616            0 :                     ShowSevereError(state, format("{}: incorrect econo lockout: {}", cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(9)));
     617              :                 }
     618            0 :                 thisExchanger.EconoLockOut = static_cast<bool>(toggle);
     619              :             }
     620              : 
     621              :         } // end of input loop over desiccant balanced heat exchangers
     622              : 
     623              :         // get performance data set for balanced desiccant heat exchanger
     624              : 
     625           51 :         for (int PerfDataIndex = 1; PerfDataIndex <= NumDesBalExchsPerfDataType1; ++PerfDataIndex) {
     626            7 :             cCurrentModuleObject = "HeatExchanger:Desiccant:BalancedFlow:PerformanceDataType1";
     627           14 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
     628              :                                                                      cCurrentModuleObject,
     629              :                                                                      PerfDataIndex,
     630            7 :                                                                      state.dataIPShortCut->cAlphaArgs,
     631              :                                                                      NumAlphas,
     632            7 :                                                                      state.dataIPShortCut->rNumericArgs,
     633              :                                                                      NumNumbers,
     634              :                                                                      IOStatus,
     635            7 :                                                                      state.dataIPShortCut->lNumericFieldBlanks,
     636            7 :                                                                      state.dataIPShortCut->lAlphaFieldBlanks,
     637            7 :                                                                      state.dataIPShortCut->cAlphaFieldNames,
     638            7 :                                                                      state.dataIPShortCut->cNumericFieldNames);
     639            7 :             int const PerfDataNum = PerfDataIndex;
     640            7 :             auto &thisPerfData = state.dataHeatRecovery->BalDesDehumPerfData(PerfDataNum);
     641            7 :             thisPerfData.NumericFieldNames.allocate(NumNumbers);
     642            7 :             thisPerfData.NumericFieldNames = state.dataIPShortCut->cNumericFieldNames;
     643              : 
     644            7 :             thisPerfData.Name = state.dataIPShortCut->cAlphaArgs(1);
     645            7 :             thisPerfData.PerfType = cCurrentModuleObject;
     646            7 :             thisPerfData.NomSupAirVolFlow = state.dataIPShortCut->rNumericArgs(1);
     647              :             // check validity
     648            7 :             if (thisPerfData.NomSupAirVolFlow <= 0.0 && thisPerfData.NomSupAirVolFlow != DataSizing::AutoSize) {
     649            0 :                 ShowSevereError(state, format("{} \"{}\"", cCurrentModuleObject, thisPerfData.Name));
     650            0 :                 ShowContinueError(state, "Nominal air flow rate must be greater than zero.");
     651            0 :                 ShowContinueError(state, format("... value entered = {:.6R}", thisPerfData.NomSupAirVolFlow));
     652            0 :                 ErrorsFound = true;
     653              :             }
     654              : 
     655            7 :             thisPerfData.NomProcAirFaceVel = state.dataIPShortCut->rNumericArgs(2);
     656              :             // check validity
     657            7 :             if ((thisPerfData.NomProcAirFaceVel <= 0.0 && thisPerfData.NomProcAirFaceVel != DataSizing::AutoSize) ||
     658            7 :                 thisPerfData.NomProcAirFaceVel > 6.0) {
     659            0 :                 ShowSevereError(state, format("{} \"{}\"", cCurrentModuleObject, thisPerfData.Name));
     660            0 :                 ShowContinueError(state, "Nominal air face velocity cannot be less than or equal to zero or greater than 6 m/s.");
     661            0 :                 ShowContinueError(state, format("... value entered = {:.6R}", thisPerfData.NomProcAirFaceVel));
     662            0 :                 ErrorsFound = true;
     663              :             }
     664            7 :             thisPerfData.NomElecPower = state.dataIPShortCut->rNumericArgs(3);
     665              :             // check validity
     666            7 :             if (thisPerfData.NomElecPower < 0.0) {
     667            0 :                 ShowSevereError(state, format("{} \"{}\"", cCurrentModuleObject, thisPerfData.Name));
     668            0 :                 ShowContinueError(state, "Nominal electric power cannot be less than zero.");
     669            0 :                 ShowContinueError(state, format("... value entered = {:.6R}", thisPerfData.NomElecPower));
     670            0 :                 ErrorsFound = true;
     671              :             }
     672              : 
     673              :             // regen outlet temp variables
     674           63 :             for (int i = 0; i < 8; ++i) {
     675           56 :                 thisPerfData.B[i] = state.dataIPShortCut->rNumericArgs(i + 4);
     676              :             }
     677              : 
     678              :             //     Check that the minimum is not greater than or equal to the maximum for each of the following model boundaries
     679            7 :             thisPerfData.T_MinRegenAirInHumRat = state.dataIPShortCut->rNumericArgs(12);
     680            7 :             thisPerfData.T_MaxRegenAirInHumRat = state.dataIPShortCut->rNumericArgs(13);
     681            7 :             if (thisPerfData.T_MinRegenAirInHumRat >= thisPerfData.T_MaxRegenAirInHumRat) {
     682            0 :                 ShowSevereError(state, format("{} \"{}\"", cCurrentModuleObject, thisPerfData.Name));
     683            0 :                 ShowContinueError(state, "Error found in min/max boundary for the regen outlet air temperature equation.");
     684            0 :                 ShowContinueError(state, "... the minimum value of regeneration inlet air humidity ratio must be less than the maximum.");
     685            0 :                 ShowContinueError(state, format("... minimum value entered by user = {:.6R}", thisPerfData.T_MinRegenAirInHumRat));
     686            0 :                 ShowContinueError(state, format("... maximum value entered by user = {:.6R}", thisPerfData.T_MaxRegenAirInHumRat));
     687            0 :                 ErrorsFound = true;
     688              :             }
     689            7 :             if (thisPerfData.T_MinRegenAirInHumRat < 0.0) {
     690            0 :                 ShowSevereError(state, format("{} \"{}\"", cCurrentModuleObject, thisPerfData.Name));
     691            0 :                 ShowContinueError(state, "Error found in min boundary for the regen outlet air temperature equation.");
     692            0 :                 ShowContinueError(state, "... the minimum value of regeneration inlet air humidity ratio must be greater than or equal to 0.");
     693            0 :                 ShowContinueError(state, format("... minimum value entered by user = {:.6R}", thisPerfData.T_MinRegenAirInHumRat));
     694            0 :                 ErrorsFound = true;
     695              :             }
     696            7 :             if (thisPerfData.T_MaxRegenAirInHumRat > 1.0) {
     697            0 :                 ShowSevereError(state, format("{} \"{}\"", cCurrentModuleObject, thisPerfData.Name));
     698            0 :                 ShowContinueError(state, "Error found in max boundary for the regen outlet air temperature equation.");
     699            0 :                 ShowContinueError(state, "... the maximum value of regeneration inlet air humidity ratio must be less than or equal to 1.");
     700            0 :                 ShowContinueError(state, format("... maximum value entered by user = {:.6R}", thisPerfData.T_MaxRegenAirInHumRat));
     701            0 :                 ErrorsFound = true;
     702              :             }
     703              : 
     704            7 :             thisPerfData.T_MinRegenAirInTemp = state.dataIPShortCut->rNumericArgs(14);
     705            7 :             thisPerfData.T_MaxRegenAirInTemp = state.dataIPShortCut->rNumericArgs(15);
     706            7 :             if (thisPerfData.T_MinRegenAirInTemp >= thisPerfData.T_MaxRegenAirInTemp) {
     707            0 :                 ShowSevereError(state, format("{} \"{}\"", cCurrentModuleObject, thisPerfData.Name));
     708            0 :                 ShowContinueError(state, "Error found in min/max boundary for the regen outlet air temperature equation.");
     709            0 :                 ShowContinueError(state, "... the minimum value of regeneration inlet air temperature must be less than the maximum.");
     710            0 :                 ShowContinueError(state, format("... minimum value entered = {:.6R}", thisPerfData.T_MinRegenAirInTemp));
     711            0 :                 ShowContinueError(state, format("... maximum value entered = {:.6R}", thisPerfData.T_MaxRegenAirInTemp));
     712            0 :                 ErrorsFound = true;
     713              :             }
     714              : 
     715            7 :             thisPerfData.T_MinProcAirInHumRat = state.dataIPShortCut->rNumericArgs(16);
     716            7 :             thisPerfData.T_MaxProcAirInHumRat = state.dataIPShortCut->rNumericArgs(17);
     717            7 :             if (thisPerfData.T_MinProcAirInHumRat >= thisPerfData.T_MaxProcAirInHumRat) {
     718            0 :                 ShowSevereError(state, format("{} \"{}\"", cCurrentModuleObject, thisPerfData.Name));
     719            0 :                 ShowContinueError(state, "Error found in min/max boundary for the regen outlet air temperature equation.");
     720            0 :                 ShowContinueError(state, "... the minimum value of process inlet air humidity ratio must be less than the maximum.");
     721            0 :                 ShowContinueError(state, format("... minimum value entered by user = {:.6R}", thisPerfData.T_MinProcAirInHumRat));
     722            0 :                 ShowContinueError(state, format("... maximum value entered by user = {:.6R}", thisPerfData.T_MaxProcAirInHumRat));
     723            0 :                 ErrorsFound = true;
     724              :             }
     725            7 :             if (thisPerfData.T_MinProcAirInHumRat < 0.0) {
     726            0 :                 ShowSevereError(state, format("{} \"{}\"", cCurrentModuleObject, thisPerfData.Name));
     727            0 :                 ShowContinueError(state, "Error found in min boundary for the regen outlet air temperature equation.");
     728            0 :                 ShowContinueError(state, "... the minimum value of process inlet air humidity ratio must be greater than or equal to 0.");
     729            0 :                 ShowContinueError(state, format("... minimum value entered by user = {:.6R}", thisPerfData.T_MinProcAirInHumRat));
     730            0 :                 ErrorsFound = true;
     731              :             }
     732            7 :             if (thisPerfData.T_MaxProcAirInHumRat > 1.0) {
     733            0 :                 ShowSevereError(state, format("{} \"{}\"", cCurrentModuleObject, thisPerfData.Name));
     734            0 :                 ShowContinueError(state, "Error found in max boundary for the regen outlet air temperature equation.");
     735            0 :                 ShowContinueError(state, "... the maximum value of process inlet air humidity ratio must be less than or equal to 1.");
     736            0 :                 ShowContinueError(state, format("... maximum value entered by user = {:.6R}", thisPerfData.T_MaxProcAirInHumRat));
     737            0 :                 ErrorsFound = true;
     738              :             }
     739              : 
     740            7 :             thisPerfData.T_MinProcAirInTemp = state.dataIPShortCut->rNumericArgs(18);
     741            7 :             thisPerfData.T_MaxProcAirInTemp = state.dataIPShortCut->rNumericArgs(19);
     742            7 :             if (thisPerfData.T_MinProcAirInTemp >= thisPerfData.T_MaxProcAirInTemp) {
     743            0 :                 ShowSevereError(state, format("{} \"{}\"", cCurrentModuleObject, thisPerfData.Name));
     744            0 :                 ShowContinueError(state, "Error found in min/max boundary for the regen outlet air temperature equation.");
     745            0 :                 ShowContinueError(state, "... the minimum value of process inlet air temperature must be less than the maximum.");
     746            0 :                 ShowContinueError(state, format("... minimum value entered = {:.6R}", thisPerfData.T_MinProcAirInTemp));
     747            0 :                 ShowContinueError(state, format("... maximum value entered = {:.6R}", thisPerfData.T_MaxProcAirInTemp));
     748            0 :                 ErrorsFound = true;
     749              :             }
     750              : 
     751            7 :             thisPerfData.T_MinFaceVel = state.dataIPShortCut->rNumericArgs(20);
     752            7 :             thisPerfData.T_MaxFaceVel = state.dataIPShortCut->rNumericArgs(21);
     753            7 :             if (thisPerfData.T_MinFaceVel >= thisPerfData.T_MaxFaceVel) {
     754            0 :                 ShowSevereError(state, format("{} \"{}\"", cCurrentModuleObject, thisPerfData.Name));
     755            0 :                 ShowContinueError(state, "Error found in min/max boundary for the regen outlet air temperature equation.");
     756            0 :                 ShowContinueError(state, "... the minimum value of regen air velocity must be less than the maximum.");
     757            0 :                 ShowContinueError(state, format("... minimum value entered = {:.6R}", thisPerfData.T_MinFaceVel));
     758            0 :                 ShowContinueError(state, format("... maximum value entered = {:.6R}", thisPerfData.T_MaxFaceVel));
     759            0 :                 ErrorsFound = true;
     760              :             }
     761              : 
     762            7 :             thisPerfData.MinRegenAirOutTemp = state.dataIPShortCut->rNumericArgs(22);
     763            7 :             thisPerfData.MaxRegenAirOutTemp = state.dataIPShortCut->rNumericArgs(23);
     764            7 :             if (thisPerfData.MinRegenAirOutTemp >= thisPerfData.MaxRegenAirOutTemp) {
     765            0 :                 ShowSevereError(state, format("{} \"{}\"", cCurrentModuleObject, thisPerfData.Name));
     766            0 :                 ShowContinueError(state, "Error found in min/max boundary for the regen outlet air temperature equation.");
     767            0 :                 ShowContinueError(state, "... the minimum value of regen outlet air temperature must be less than the maximum.");
     768            0 :                 ShowContinueError(state, format("... minimum value entered = {:.6R}", thisPerfData.MinRegenAirOutTemp));
     769            0 :                 ShowContinueError(state, format("... maximum value entered = {:.6R}", thisPerfData.MaxRegenAirOutTemp));
     770            0 :                 ErrorsFound = true;
     771              :             }
     772              : 
     773            7 :             thisPerfData.T_MinRegenAirInRelHum = state.dataIPShortCut->rNumericArgs(24) / 100.0;
     774            7 :             thisPerfData.T_MaxRegenAirInRelHum = state.dataIPShortCut->rNumericArgs(25) / 100.0;
     775            7 :             if (thisPerfData.T_MinRegenAirInRelHum >= thisPerfData.T_MaxRegenAirInRelHum) {
     776            0 :                 ShowSevereError(state, format("{} \"{}\"", cCurrentModuleObject, thisPerfData.Name));
     777            0 :                 ShowContinueError(state, "Error found in min/max boundary for the regen outlet air temperature equation.");
     778            0 :                 ShowContinueError(state, "... the minimum value of regen inlet air relative humidity must be less than the maximum.");
     779            0 :                 ShowContinueError(state, format("... minimum value entered = {:.6R}", thisPerfData.T_MinRegenAirInRelHum * 100.0));
     780            0 :                 ShowContinueError(state, format("... maximum value entered = {:.6R}", thisPerfData.T_MaxRegenAirInRelHum * 100.0));
     781            0 :                 ErrorsFound = true;
     782              :             }
     783            7 :             if (thisPerfData.T_MinRegenAirInRelHum < 0.0) {
     784            0 :                 ShowSevereError(state, format("{} \"{}\"", cCurrentModuleObject, thisPerfData.Name));
     785            0 :                 ShowContinueError(state, "Error found in min boundary for the regen outlet air temperature equation.");
     786            0 :                 ShowContinueError(state, "... the minimum value of regen inlet air relative humidity must be greater than or equal to 0.");
     787            0 :                 ShowContinueError(state, format("... minimum value entered = {:.6R}", thisPerfData.T_MinRegenAirInRelHum * 100.0));
     788            0 :                 ErrorsFound = true;
     789              :             }
     790            7 :             if (thisPerfData.T_MaxRegenAirInRelHum > 1.0) {
     791            0 :                 ShowSevereError(state, format("{} \"{}\"", cCurrentModuleObject, thisPerfData.Name));
     792            0 :                 ShowContinueError(state, "Error found in max boundary for the regen outlet air temperature equation.");
     793            0 :                 ShowContinueError(state, "... the maximum value of regen inlet air relative humidity must be less than or equal to 100.");
     794            0 :                 ShowContinueError(state, format("... maximum value entered = {:.6R}", thisPerfData.T_MaxRegenAirInRelHum * 100.0));
     795            0 :                 ErrorsFound = true;
     796              :             }
     797              : 
     798            7 :             thisPerfData.T_MinProcAirInRelHum = state.dataIPShortCut->rNumericArgs(26) / 100.0;
     799            7 :             thisPerfData.T_MaxProcAirInRelHum = state.dataIPShortCut->rNumericArgs(27) / 100.0;
     800            7 :             if (thisPerfData.T_MinProcAirInRelHum >= thisPerfData.T_MaxProcAirInRelHum) {
     801            0 :                 ShowSevereError(state, format("{} \"{}\"", cCurrentModuleObject, thisPerfData.Name));
     802            0 :                 ShowContinueError(state, "Error found in min/max boundary for the regen outlet air temperature equation.");
     803            0 :                 ShowContinueError(state, "... the minimum value of process inlet air relative humidity must be less than the maximum.");
     804            0 :                 ShowContinueError(state, format("... minimum value entered = {:.6R}", thisPerfData.T_MinProcAirInRelHum * 100.0));
     805            0 :                 ShowContinueError(state, format("... maximum value entered = {:.6R}", thisPerfData.T_MaxProcAirInRelHum * 100.0));
     806            0 :                 ErrorsFound = true;
     807              :             }
     808            7 :             if (thisPerfData.T_MinProcAirInRelHum < 0.0) {
     809            0 :                 ShowSevereError(state, format("{} \"{}\"", cCurrentModuleObject, thisPerfData.Name));
     810            0 :                 ShowContinueError(state, "Error found in min boundary for the regen outlet air temperature equation.");
     811            0 :                 ShowContinueError(state, "... the minimum value of process inlet air relative humidity must be greater than or equal to 0.");
     812            0 :                 ShowContinueError(state, format("... minimum value entered = {:.6R}", thisPerfData.T_MinProcAirInRelHum * 100.0));
     813            0 :                 ErrorsFound = true;
     814              :             }
     815            7 :             if (thisPerfData.T_MaxProcAirInRelHum > 1.0) {
     816            0 :                 ShowSevereError(state, format("{} \"{}\"", cCurrentModuleObject, thisPerfData.Name));
     817            0 :                 ShowContinueError(state, "Error found in max boundary for the regen outlet air temperature equation.");
     818            0 :                 ShowContinueError(state, "... the maximum value of process inlet air relative humidity must be less than or equal to 100.");
     819            0 :                 ShowContinueError(state, format("... maximum value entered = {:.6R}", thisPerfData.T_MaxProcAirInRelHum * 100.0));
     820            0 :                 ErrorsFound = true;
     821              :             }
     822              : 
     823              :             // regen outlet humidity ratio variables
     824           63 :             for (int i = 0; i < 8; ++i) {
     825           56 :                 thisPerfData.C[i] = state.dataIPShortCut->rNumericArgs(i + 28);
     826              :             }
     827              : 
     828              :             //     Check that the minimum is not greater than or equal to the maximum for each of the following model boundaries
     829            7 :             thisPerfData.H_MinRegenAirInHumRat = state.dataIPShortCut->rNumericArgs(36);
     830            7 :             thisPerfData.H_MaxRegenAirInHumRat = state.dataIPShortCut->rNumericArgs(37);
     831            7 :             if (thisPerfData.H_MinRegenAirInHumRat >= thisPerfData.H_MaxRegenAirInHumRat) {
     832            0 :                 ShowSevereError(state, format("{} \"{}\"", cCurrentModuleObject, thisPerfData.Name));
     833            0 :                 ShowContinueError(state, "Error found in min/max boundary for the regen outlet air humidity ratio equation.");
     834            0 :                 ShowContinueError(state, "... the minimum value of regeneration inlet air humidity ratio must be less than the maximum.");
     835            0 :                 ShowContinueError(state, format("... minimum value entered by user = {:.6R}", thisPerfData.H_MinRegenAirInHumRat));
     836            0 :                 ShowContinueError(state, format("... maximum value entered by user = {:.6R}", thisPerfData.H_MaxRegenAirInHumRat));
     837            0 :                 ErrorsFound = true;
     838              :             }
     839            7 :             if (thisPerfData.H_MinRegenAirInHumRat < 0.0) {
     840            0 :                 ShowSevereError(state, format("{} \"{}\"", cCurrentModuleObject, thisPerfData.Name));
     841            0 :                 ShowContinueError(state, "Error found in min boundary for the regen outlet air humidity ratio equation.");
     842            0 :                 ShowContinueError(state, "... the minimum value of regeneration inlet air humidity ratio must be greater than or equal to 0.");
     843            0 :                 ShowContinueError(state, format("... minimum value entered by user = {:.6R}", thisPerfData.H_MinRegenAirInHumRat));
     844            0 :                 ErrorsFound = true;
     845              :             }
     846            7 :             if (thisPerfData.H_MaxRegenAirInHumRat > 1.0) {
     847            0 :                 ShowSevereError(state, format("{} \"{}\"", cCurrentModuleObject, thisPerfData.Name));
     848            0 :                 ShowContinueError(state, "Error found in max boundary for the regen outlet air humidity ratio equation.");
     849            0 :                 ShowContinueError(state, "... the maximum value of regeneration inlet air humidity ratio must be less than or equal to 1.");
     850            0 :                 ShowContinueError(state, format("... maximum value entered by user = {:.6R}", thisPerfData.H_MaxRegenAirInHumRat));
     851            0 :                 ErrorsFound = true;
     852              :             }
     853              : 
     854            7 :             thisPerfData.H_MinRegenAirInTemp = state.dataIPShortCut->rNumericArgs(38);
     855            7 :             thisPerfData.H_MaxRegenAirInTemp = state.dataIPShortCut->rNumericArgs(39);
     856            7 :             if (thisPerfData.H_MinRegenAirInTemp >= thisPerfData.H_MaxRegenAirInTemp) {
     857            0 :                 ShowSevereError(state, format("{} \"{}\"", cCurrentModuleObject, thisPerfData.Name));
     858            0 :                 ShowContinueError(state, "Error found in min/max boundary for the regen outlet air humidity ratio equation.");
     859            0 :                 ShowContinueError(state, "... the minimum value of regeneration inlet air temperature must be less than the maximum.");
     860            0 :                 ShowContinueError(state, format("... minimum value entered = {:.6R}", thisPerfData.H_MinRegenAirInTemp));
     861            0 :                 ShowContinueError(state, format("... maximum value entered = {:.6R}", thisPerfData.H_MaxRegenAirInTemp));
     862            0 :                 ErrorsFound = true;
     863              :             }
     864              : 
     865            7 :             thisPerfData.H_MinProcAirInHumRat = state.dataIPShortCut->rNumericArgs(40);
     866            7 :             thisPerfData.H_MaxProcAirInHumRat = state.dataIPShortCut->rNumericArgs(41);
     867            7 :             if (thisPerfData.H_MinProcAirInHumRat >= thisPerfData.H_MaxProcAirInHumRat) {
     868            0 :                 ShowSevereError(state, format("{} \"{}\"", cCurrentModuleObject, thisPerfData.Name));
     869            0 :                 ShowContinueError(state, "Error found in min/max boundary for the regen outlet air humidity ratio equation.");
     870            0 :                 ShowContinueError(state, "... the minimum value of process inlet air humidity ratio must be less than the maximum.");
     871            0 :                 ShowContinueError(state, format("... minimum value entered by user = {:.6R}", thisPerfData.H_MinProcAirInHumRat));
     872            0 :                 ShowContinueError(state, format("... maximum value entered by user = {:.6R}", thisPerfData.H_MaxProcAirInHumRat));
     873            0 :                 ErrorsFound = true;
     874              :             }
     875            7 :             if (thisPerfData.H_MinProcAirInHumRat < 0.0) {
     876            0 :                 ShowSevereError(state, format("{} \"{}\"", cCurrentModuleObject, thisPerfData.Name));
     877            0 :                 ShowContinueError(state, "Error found in min boundary for the regen outlet air humidity ratio equation.");
     878            0 :                 ShowContinueError(state, "... the minimum value of process inlet air humidity ratio must be greater than or equal to 0.");
     879            0 :                 ShowContinueError(state, format("... minimum value entered by user = {:.6R}", thisPerfData.H_MinProcAirInHumRat));
     880            0 :                 ErrorsFound = true;
     881              :             }
     882            7 :             if (thisPerfData.H_MaxProcAirInHumRat > 1.0) {
     883            0 :                 ShowSevereError(state, format("{} \"{}\"", cCurrentModuleObject, thisPerfData.Name));
     884            0 :                 ShowContinueError(state, "Error found in max boundary for the regen outlet air humidity ratio equation.");
     885            0 :                 ShowContinueError(state, "... the maximum value of process inlet air humidity ratio must be less than or equal to 1.");
     886            0 :                 ShowContinueError(state, format("... maximum value entered by user = {:.6R}", thisPerfData.H_MaxProcAirInHumRat));
     887            0 :                 ErrorsFound = true;
     888              :             }
     889              : 
     890            7 :             thisPerfData.H_MinProcAirInTemp = state.dataIPShortCut->rNumericArgs(42);
     891            7 :             thisPerfData.H_MaxProcAirInTemp = state.dataIPShortCut->rNumericArgs(43);
     892            7 :             if (thisPerfData.H_MinProcAirInTemp >= thisPerfData.H_MaxProcAirInTemp) {
     893            0 :                 ShowSevereError(state, format("{} \"{}\"", cCurrentModuleObject, thisPerfData.Name));
     894            0 :                 ShowContinueError(state, "Error found in min/max boundary for the regen outlet air humidity ratio equation.");
     895            0 :                 ShowContinueError(state, "... the minimum value of process inlet air temperature must be less than the maximum.");
     896            0 :                 ShowContinueError(state, format("... minimum value entered = {:.6R}", thisPerfData.H_MinProcAirInTemp));
     897            0 :                 ShowContinueError(state, format("... maximum value entered = {:.6R}", thisPerfData.H_MaxProcAirInTemp));
     898            0 :                 ErrorsFound = true;
     899              :             }
     900              : 
     901            7 :             thisPerfData.H_MinFaceVel = state.dataIPShortCut->rNumericArgs(44);
     902            7 :             thisPerfData.H_MaxFaceVel = state.dataIPShortCut->rNumericArgs(45);
     903            7 :             if (thisPerfData.H_MinFaceVel >= thisPerfData.H_MaxFaceVel) {
     904            0 :                 ShowSevereError(state, format("{} \"{}\"", cCurrentModuleObject, thisPerfData.Name));
     905            0 :                 ShowContinueError(state, "Error found in min/max boundary for the regen outlet air humidity ratio equation.");
     906            0 :                 ShowContinueError(state, "... the minimum value of regen air velocity must be less than the maximum.");
     907            0 :                 ShowContinueError(state, format("... minimum value entered = {:.6R}", thisPerfData.H_MinFaceVel));
     908            0 :                 ShowContinueError(state, format("... maximum value entered = {:.6R}", thisPerfData.H_MaxFaceVel));
     909            0 :                 ErrorsFound = true;
     910              :             }
     911              : 
     912            7 :             thisPerfData.MinRegenAirOutHumRat = state.dataIPShortCut->rNumericArgs(46);
     913            7 :             thisPerfData.MaxRegenAirOutHumRat = state.dataIPShortCut->rNumericArgs(47);
     914            7 :             if (thisPerfData.MinRegenAirOutHumRat >= thisPerfData.MaxRegenAirOutHumRat) {
     915            0 :                 ShowSevereError(state, format("{} \"{}\"", cCurrentModuleObject, thisPerfData.Name));
     916            0 :                 ShowContinueError(state, "Error found in min/max boundary for the regen outlet air humidity ratio equation.");
     917            0 :                 ShowContinueError(state, "... the minimum value of regen outlet air humidity ratio must be less than the maximum.");
     918            0 :                 ShowContinueError(state, format("... minimum value entered = {:.6R}", thisPerfData.MinRegenAirOutHumRat));
     919            0 :                 ShowContinueError(state, format("... maximum value entered = {:.6R}", thisPerfData.MaxRegenAirOutHumRat));
     920            0 :                 ErrorsFound = true;
     921              :             }
     922            7 :             if (thisPerfData.MinRegenAirOutHumRat < 0.0) {
     923            0 :                 ShowSevereError(state, format("{} \"{}\"", cCurrentModuleObject, thisPerfData.Name));
     924            0 :                 ShowContinueError(state, "Error found in min boundary for the regen outlet air humidity ratio equation.");
     925            0 :                 ShowContinueError(state, "... the minimum value of regen outlet air humidity ratio must be greater than or equal to 0.");
     926            0 :                 ShowContinueError(state, format("... minimum value entered = {:.6R}", thisPerfData.MinRegenAirOutHumRat));
     927            0 :                 ErrorsFound = true;
     928              :             }
     929            7 :             if (thisPerfData.MaxRegenAirOutHumRat > 1.0) {
     930            0 :                 ShowSevereError(state, format("{} \"{}\"", cCurrentModuleObject, thisPerfData.Name));
     931            0 :                 ShowContinueError(state, "Error found in max boundary for the regen outlet air humidity ratio equation.");
     932            0 :                 ShowContinueError(state, "... the maximum value of regen outlet air humidity ratio must be less or equal to 1.");
     933            0 :                 ShowContinueError(state, format("... maximum value entered = {:.6R}", thisPerfData.MaxRegenAirOutHumRat));
     934            0 :                 ErrorsFound = true;
     935              :             }
     936              : 
     937            7 :             thisPerfData.H_MinRegenAirInRelHum = state.dataIPShortCut->rNumericArgs(48) / 100.0;
     938            7 :             thisPerfData.H_MaxRegenAirInRelHum = state.dataIPShortCut->rNumericArgs(49) / 100.0;
     939            7 :             if (thisPerfData.H_MinRegenAirInRelHum >= thisPerfData.H_MaxRegenAirInRelHum) {
     940            0 :                 ShowSevereError(state, format("{} \"{}\"", cCurrentModuleObject, thisPerfData.Name));
     941            0 :                 ShowContinueError(state, "Error found in min/max boundary for the regen outlet air humidity ratio equation.");
     942            0 :                 ShowContinueError(state, "... the minimum value of regen inlet air relative humidity must be less than the maximum.");
     943            0 :                 ShowContinueError(state, format("... minimum value entered = {:.6R}", thisPerfData.H_MinRegenAirInRelHum * 100.0));
     944            0 :                 ShowContinueError(state, format("... maximum value entered = {:.6R}", thisPerfData.H_MaxRegenAirInRelHum * 100.0));
     945            0 :                 ErrorsFound = true;
     946              :             }
     947            7 :             if (thisPerfData.H_MinRegenAirInRelHum < 0.0) {
     948            0 :                 ShowSevereError(state, format("{} \"{}\"", cCurrentModuleObject, thisPerfData.Name));
     949            0 :                 ShowContinueError(state, "Error found in min boundary for the regen outlet air humidity ratio equation.");
     950            0 :                 ShowContinueError(state, "... the minimum value of regen inlet air relative humidity must be greater than or equal to 0.");
     951            0 :                 ShowContinueError(state, format("... minimum value entered = {:.6R}", thisPerfData.H_MinRegenAirInRelHum * 100.0));
     952            0 :                 ErrorsFound = true;
     953              :             }
     954            7 :             if (thisPerfData.H_MaxRegenAirInRelHum > 1.0) {
     955            0 :                 ShowSevereError(state, format("{} \"{}\"", cCurrentModuleObject, thisPerfData.Name));
     956            0 :                 ShowContinueError(state, "Error found in max boundary for the regen outlet air humidity ratio equation.");
     957            0 :                 ShowContinueError(state, "... the maximum value of regen inlet air relative humidity must be less or equal to 100.");
     958            0 :                 ShowContinueError(state, format("... maximum value entered = {:.6R}", thisPerfData.H_MaxRegenAirInRelHum * 100.0));
     959            0 :                 ErrorsFound = true;
     960              :             }
     961              : 
     962            7 :             thisPerfData.H_MinProcAirInRelHum = state.dataIPShortCut->rNumericArgs(50) / 100.0;
     963            7 :             thisPerfData.H_MaxProcAirInRelHum = state.dataIPShortCut->rNumericArgs(51) / 100.0;
     964            7 :             if (thisPerfData.H_MinProcAirInRelHum >= thisPerfData.H_MaxProcAirInRelHum) {
     965            0 :                 ShowSevereError(state, format("{} \"{}\"", cCurrentModuleObject, thisPerfData.Name));
     966            0 :                 ShowContinueError(state, "Error found in min/max boundary for the regen outlet air humidity ratio equation.");
     967            0 :                 ShowContinueError(state, "... the minimum value of process inlet air relative humidity must be less than the maximum.");
     968            0 :                 ShowContinueError(state, format("... minimum value entered = {:.6R}", thisPerfData.H_MinProcAirInRelHum * 100.0));
     969            0 :                 ShowContinueError(state, format("... maximum value entered = {:.6R}", thisPerfData.H_MaxProcAirInRelHum * 100.0));
     970            0 :                 ErrorsFound = true;
     971              :             }
     972            7 :             if (thisPerfData.H_MinProcAirInRelHum < 0.0) {
     973            0 :                 ShowSevereError(state, format("{} \"{}\"", cCurrentModuleObject, thisPerfData.Name));
     974            0 :                 ShowContinueError(state, "Error found in min boundary for the regen outlet air humidity ratio equation.");
     975            0 :                 ShowContinueError(state, "... the minimum value of process inlet air relative humidity must be greater than or equal to 0.");
     976            0 :                 ShowContinueError(state, format("... minimum value entered = {:.6R}", thisPerfData.H_MinProcAirInRelHum * 100.0));
     977            0 :                 ErrorsFound = true;
     978              :             }
     979            7 :             if (thisPerfData.H_MaxProcAirInRelHum > 1.0) {
     980            0 :                 ShowSevereError(state, format("{} \"{}\"", cCurrentModuleObject, thisPerfData.Name));
     981            0 :                 ShowContinueError(state, "Error found in max boundary for the regen outlet air humidity ratio equation.");
     982            0 :                 ShowContinueError(state, "... the maximum value of process inlet air relative humidity must be less than or equal to 100.");
     983            0 :                 ShowContinueError(state, format("... maximum value entered = {:.6R}", thisPerfData.H_MaxProcAirInRelHum * 100.0));
     984            0 :                 ErrorsFound = true;
     985              :             }
     986              :         }
     987              :         // getting performance data set for balanced desiccant heat exchanger ends
     988              : 
     989              :         // match desiccant heat exchanger index to performance data index
     990           51 :         for (int ExchIndex = 1; ExchIndex <= NumDesiccantBalancedExchs; ++ExchIndex) {
     991            7 :             int const ExchNum = ExchIndex + NumAirToAirPlateExchs + NumAirToAirGenericExchs;
     992            7 :             auto &thisExchanger = state.dataHeatRecovery->ExchCond(ExchNum);
     993            9 :             for (int PerfDataNum = 1; PerfDataNum <= NumDesBalExchsPerfDataType1; ++PerfDataNum) {
     994            9 :                 if (Util::SameString(thisExchanger.HeatExchPerfName, state.dataHeatRecovery->BalDesDehumPerfData(PerfDataNum).Name)) {
     995            7 :                     thisExchanger.PerfDataIndex = PerfDataNum;
     996            7 :                     break;
     997              :                 }
     998              :             }
     999            7 :             if (thisExchanger.PerfDataIndex == 0) {
    1000            0 :                 ShowSevereError(state, format("{} \"{}\"", HVAC::hxTypeNames[(int)thisExchanger.type], thisExchanger.Name));
    1001            0 :                 ShowContinueError(state, format("... Performance data set not found = {}", thisExchanger.HeatExchPerfName));
    1002            0 :                 ErrorsFound = true;
    1003              :             } else {
    1004            7 :                 if (!ErrorsFound) {
    1005            7 :                     thisExchanger.FaceArea = state.dataHeatRecovery->BalDesDehumPerfData(thisExchanger.PerfDataIndex).NomSupAirVolFlow /
    1006            7 :                                              (state.dataHeatRecovery->BalDesDehumPerfData(thisExchanger.PerfDataIndex).NomProcAirFaceVel);
    1007              :                 }
    1008              :             }
    1009              :         }
    1010              :         // matching done
    1011              : 
    1012              :         // setup common report variables for heat exchangers
    1013          206 :         for (int ExchIndex = 1; ExchIndex <= state.dataHeatRecovery->NumHeatExchangers; ++ExchIndex) {
    1014          162 :             int const ExchNum = ExchIndex;
    1015          162 :             auto &thisExchanger = state.dataHeatRecovery->ExchCond(ExchNum);
    1016              :             // CurrentModuleObject='HeatExchanger:AirToAir:FlatPlate/AirToAir:SensibleAndLatent/Desiccant:BalancedFlow')
    1017          324 :             SetupOutputVariable(state,
    1018              :                                 "Heat Exchanger Sensible Heating Rate",
    1019              :                                 Constant::Units::W,
    1020          162 :                                 thisExchanger.SensHeatingRate,
    1021              :                                 OutputProcessor::TimeStepType::System,
    1022              :                                 OutputProcessor::StoreType::Average,
    1023          162 :                                 thisExchanger.Name);
    1024          324 :             SetupOutputVariable(state,
    1025              :                                 "Heat Exchanger Sensible Heating Energy",
    1026              :                                 Constant::Units::J,
    1027          162 :                                 thisExchanger.SensHeatingEnergy,
    1028              :                                 OutputProcessor::TimeStepType::System,
    1029              :                                 OutputProcessor::StoreType::Sum,
    1030          162 :                                 thisExchanger.Name);
    1031          324 :             SetupOutputVariable(state,
    1032              :                                 "Heat Exchanger Latent Gain Rate",
    1033              :                                 Constant::Units::W,
    1034          162 :                                 thisExchanger.LatHeatingRate,
    1035              :                                 OutputProcessor::TimeStepType::System,
    1036              :                                 OutputProcessor::StoreType::Average,
    1037          162 :                                 thisExchanger.Name);
    1038          324 :             SetupOutputVariable(state,
    1039              :                                 "Heat Exchanger Latent Gain Energy",
    1040              :                                 Constant::Units::J,
    1041          162 :                                 thisExchanger.LatHeatingEnergy,
    1042              :                                 OutputProcessor::TimeStepType::System,
    1043              :                                 OutputProcessor::StoreType::Sum,
    1044          162 :                                 thisExchanger.Name);
    1045          324 :             SetupOutputVariable(state,
    1046              :                                 "Heat Exchanger Total Heating Rate",
    1047              :                                 Constant::Units::W,
    1048          162 :                                 thisExchanger.TotHeatingRate,
    1049              :                                 OutputProcessor::TimeStepType::System,
    1050              :                                 OutputProcessor::StoreType::Average,
    1051          162 :                                 thisExchanger.Name);
    1052          324 :             SetupOutputVariable(state,
    1053              :                                 "Heat Exchanger Total Heating Energy",
    1054              :                                 Constant::Units::J,
    1055          162 :                                 thisExchanger.TotHeatingEnergy,
    1056              :                                 OutputProcessor::TimeStepType::System,
    1057              :                                 OutputProcessor::StoreType::Sum,
    1058          162 :                                 thisExchanger.Name,
    1059              :                                 Constant::eResource::EnergyTransfer,
    1060              :                                 OutputProcessor::Group::HVAC,
    1061              :                                 OutputProcessor::EndUseCat::HeatRecoveryForHeating);
    1062          324 :             SetupOutputVariable(state,
    1063              :                                 "Heat Exchanger Sensible Cooling Rate",
    1064              :                                 Constant::Units::W,
    1065          162 :                                 thisExchanger.SensCoolingRate,
    1066              :                                 OutputProcessor::TimeStepType::System,
    1067              :                                 OutputProcessor::StoreType::Average,
    1068          162 :                                 thisExchanger.Name);
    1069          324 :             SetupOutputVariable(state,
    1070              :                                 "Heat Exchanger Sensible Cooling Energy",
    1071              :                                 Constant::Units::J,
    1072          162 :                                 thisExchanger.SensCoolingEnergy,
    1073              :                                 OutputProcessor::TimeStepType::System,
    1074              :                                 OutputProcessor::StoreType::Sum,
    1075          162 :                                 thisExchanger.Name);
    1076          324 :             SetupOutputVariable(state,
    1077              :                                 "Heat Exchanger Latent Cooling Rate",
    1078              :                                 Constant::Units::W,
    1079          162 :                                 thisExchanger.LatCoolingRate,
    1080              :                                 OutputProcessor::TimeStepType::System,
    1081              :                                 OutputProcessor::StoreType::Average,
    1082          162 :                                 thisExchanger.Name);
    1083          324 :             SetupOutputVariable(state,
    1084              :                                 "Heat Exchanger Latent Cooling Energy",
    1085              :                                 Constant::Units::J,
    1086          162 :                                 thisExchanger.LatCoolingEnergy,
    1087              :                                 OutputProcessor::TimeStepType::System,
    1088              :                                 OutputProcessor::StoreType::Sum,
    1089          162 :                                 thisExchanger.Name);
    1090          324 :             SetupOutputVariable(state,
    1091              :                                 "Heat Exchanger Total Cooling Rate",
    1092              :                                 Constant::Units::W,
    1093          162 :                                 thisExchanger.TotCoolingRate,
    1094              :                                 OutputProcessor::TimeStepType::System,
    1095              :                                 OutputProcessor::StoreType::Average,
    1096          162 :                                 thisExchanger.Name);
    1097          324 :             SetupOutputVariable(state,
    1098              :                                 "Heat Exchanger Total Cooling Energy",
    1099              :                                 Constant::Units::J,
    1100          162 :                                 thisExchanger.TotCoolingEnergy,
    1101              :                                 OutputProcessor::TimeStepType::System,
    1102              :                                 OutputProcessor::StoreType::Sum,
    1103          162 :                                 thisExchanger.Name,
    1104              :                                 Constant::eResource::EnergyTransfer,
    1105              :                                 OutputProcessor::Group::HVAC,
    1106              :                                 OutputProcessor::EndUseCat::HeatRecoveryForCooling);
    1107              : 
    1108          324 :             SetupOutputVariable(state,
    1109              :                                 "Heat Exchanger Electricity Rate",
    1110              :                                 Constant::Units::W,
    1111          162 :                                 thisExchanger.ElecUseRate,
    1112              :                                 OutputProcessor::TimeStepType::System,
    1113              :                                 OutputProcessor::StoreType::Average,
    1114          162 :                                 thisExchanger.Name);
    1115          324 :             SetupOutputVariable(state,
    1116              :                                 "Heat Exchanger Electricity Energy",
    1117              :                                 Constant::Units::J,
    1118          162 :                                 thisExchanger.ElecUseEnergy,
    1119              :                                 OutputProcessor::TimeStepType::System,
    1120              :                                 OutputProcessor::StoreType::Sum,
    1121          162 :                                 thisExchanger.Name,
    1122              :                                 Constant::eResource::Electricity,
    1123              :                                 OutputProcessor::Group::HVAC,
    1124              :                                 OutputProcessor::EndUseCat::HeatRecovery);
    1125              :         }
    1126              : 
    1127              :         // setup additional report variables for generic heat exchangers
    1128          185 :         for (int ExchIndex = 1; ExchIndex <= NumAirToAirGenericExchs; ++ExchIndex) {
    1129              :             // generic heat exchangers are read in after flat plate heat exchanger objects (index needs to be set correctly)
    1130              :             // CurrentModuleObject=HeatExchanger:AirToAir:SensibleAndLatent
    1131          141 :             int const ExchNum = ExchIndex + NumAirToAirPlateExchs;
    1132          141 :             auto &thisExchanger = state.dataHeatRecovery->ExchCond(ExchNum);
    1133          282 :             SetupOutputVariable(state,
    1134              :                                 "Heat Exchanger Sensible Effectiveness",
    1135              :                                 Constant::Units::None,
    1136          141 :                                 thisExchanger.SensEffectiveness,
    1137              :                                 OutputProcessor::TimeStepType::System,
    1138              :                                 OutputProcessor::StoreType::Average,
    1139          141 :                                 thisExchanger.Name);
    1140          282 :             SetupOutputVariable(state,
    1141              :                                 "Heat Exchanger Latent Effectiveness",
    1142              :                                 Constant::Units::None,
    1143          141 :                                 thisExchanger.LatEffectiveness,
    1144              :                                 OutputProcessor::TimeStepType::System,
    1145              :                                 OutputProcessor::StoreType::Average,
    1146          141 :                                 thisExchanger.Name);
    1147          282 :             SetupOutputVariable(state,
    1148              :                                 "Heat Exchanger Supply Air Bypass Mass Flow Rate",
    1149              :                                 Constant::Units::kg_s,
    1150          141 :                                 thisExchanger.SupBypassMassFlow,
    1151              :                                 OutputProcessor::TimeStepType::System,
    1152              :                                 OutputProcessor::StoreType::Average,
    1153          141 :                                 thisExchanger.Name);
    1154          282 :             SetupOutputVariable(state,
    1155              :                                 "Heat Exchanger Exhaust Air Bypass Mass Flow Rate",
    1156              :                                 Constant::Units::kg_s,
    1157          141 :                                 thisExchanger.SecBypassMassFlow,
    1158              :                                 OutputProcessor::TimeStepType::System,
    1159              :                                 OutputProcessor::StoreType::Average,
    1160          141 :                                 thisExchanger.Name);
    1161          282 :             SetupOutputVariable(state,
    1162              :                                 "Heat Exchanger Defrost Time Fraction",
    1163              :                                 Constant::Units::None,
    1164          141 :                                 thisExchanger.DefrostFraction,
    1165              :                                 OutputProcessor::TimeStepType::System,
    1166              :                                 OutputProcessor::StoreType::Average,
    1167          141 :                                 thisExchanger.Name);
    1168              :         }
    1169              : 
    1170           44 :         if (ErrorsFound) {
    1171            0 :             ShowFatalError(state, format("{}Errors found in input.  Program terminates.", RoutineName));
    1172              :         }
    1173           44 :     }
    1174              : 
    1175      3904968 :     void HeatExchCond::initialize(EnergyPlusData &state, int const CompanionCoilIndex, int const CompanionCoilType_Num)
    1176              :     {
    1177              : 
    1178              :         // SUBROUTINE INFORMATION:
    1179              :         //       AUTHOR         Michael Wetter
    1180              :         //       DATE WRITTEN   March 1999
    1181              :         //       MODIFIED       F Buhl Nov 2000, D Shirey Feb 2003
    1182              :         //                      B Griffith May 2009, EMS setpoint check
    1183              :         //       RE-ENGINEERED  na
    1184              : 
    1185              :         // PURPOSE OF THIS SUBROUTINE:
    1186              :         // This subroutine is for initializations of the Heat Recovery Components.
    1187              : 
    1188              :         // METHODOLOGY EMPLOYED:
    1189              :         // Uses the status flags to trigger initializations.
    1190              : 
    1191              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    1192              :         Real64 CMin0;  // minimum capacity flow
    1193              :         Real64 CMax0;  // maximum capacity flow
    1194              :         Real64 Eps0;   // effectiveness at rated conditions
    1195              :         Real64 NTU0;   // NTU at rated conditions
    1196              :         Real64 RhoAir; // air density at outside pressure & standard temperature and humidity
    1197              :         Real64 CpAir;  // heat capacity of air
    1198              :         // of humidity ratio and temperature
    1199              :         Real64 Z; // Min/max flow ratio
    1200              : 
    1201      3904968 :         if (!state.dataGlobal->SysSizingCalc && this->MySizeFlag) {
    1202          162 :             this->size(state);
    1203          162 :             this->MySizeFlag = false;
    1204              :         }
    1205              : 
    1206              :         // Do the Begin Environment initializations
    1207      3904968 :         if (state.dataGlobal->BeginEnvrnFlag && this->myEnvrnFlag) {
    1208         1064 :             bool FatalError = false;
    1209              :             // I believe that all of these initializations should be taking place at the SCFM conditions
    1210         1064 :             RhoAir = state.dataEnvrn->StdRhoAir;
    1211              :             //    RhoAir = PsyRhoAirFnPbTdbW(101325.0,20.0,0.0)  do we want standard air density at sea level for generic ERVs per ARI 1060?
    1212         1064 :             CpAir = Psychrometrics::PsyCpAirFnW(0.0);
    1213              : 
    1214         1064 :             CalculateNTUBoundsErrors ErrStat = CalculateNTUBoundsErrors::NoError;
    1215         1064 :             switch (this->type) {
    1216           81 :             case HVAC::HXType::AirToAir_FlatPlate:
    1217           81 :                 this->NomSupAirMassFlow = RhoAir * this->NomSupAirVolFlow;
    1218           81 :                 this->NomSecAirMassFlow = RhoAir * this->NomSecAirVolFlow;
    1219              :                 // Note: the capacity stream is here simply the mass flow
    1220              :                 //       since the thermal capacity can be assumed to be
    1221              :                 //       equal for both streams
    1222           81 :                 if (this->NomSupAirMassFlow > this->NomSecAirMassFlow) {
    1223            6 :                     CMin0 = this->NomSecAirMassFlow;
    1224            6 :                     CMax0 = this->NomSupAirMassFlow;
    1225              :                 } else {
    1226           75 :                     CMin0 = this->NomSupAirMassFlow;
    1227           75 :                     CMax0 = this->NomSecAirMassFlow;
    1228              :                 }
    1229              : 
    1230          162 :                 Eps0 = this->NomSupAirMassFlow *
    1231           81 :                        SafeDiv(this->NomSupAirOutTemp - this->NomSupAirInTemp, CMin0 * (this->NomSecAirInTemp - this->NomSupAirInTemp));
    1232           81 :                 Z = CMin0 / CMax0;
    1233              : 
    1234           81 :                 CalculateNTUfromEpsAndZ(state, NTU0, ErrStat, Z, this->FlowArr, Eps0);
    1235              : 
    1236           81 :                 switch (ErrStat) {
    1237           81 :                 case CalculateNTUBoundsErrors::NoError:
    1238           81 :                     break; // great!
    1239            0 :                 case CalculateNTUBoundsErrors::MassFlowRatio:
    1240            0 :                     FatalError = true;
    1241            0 :                     ShowSevereError(state, format("In the HeatExchanger:AirToAir:FlatPlate component {}", this->Name));
    1242            0 :                     ShowContinueError(state, "  the mass flow ratio is out of bounds");
    1243            0 :                     ShowContinueError(state, format("The mass flow ratio is (Min_Mass_Flow_Rate / Max_Mass_Flow_Rate) = {:.2R}", Z));
    1244            0 :                     ShowContinueError(state, "The mass flow ratio should be >= 0.0 and <= 1.0");
    1245            0 :                     ShowContinueError(state,
    1246            0 :                                       format("Min_Mass_Flow_Rate = {:.2R} [air density] * {:.1R} [Min_Vol_Flow_Rate]",
    1247              :                                              RhoAir,
    1248            0 :                                              min(this->NomSupAirVolFlow, this->NomSecAirVolFlow)));
    1249            0 :                     ShowContinueError(state,
    1250            0 :                                       format("Max_Mass_Flow_Rate = {:.2R} [air density] * {:.1R} [Max_Vol_Flow_Rate]",
    1251              :                                              RhoAir,
    1252            0 :                                              max(this->NomSupAirVolFlow, this->NomSecAirVolFlow)));
    1253            0 :                     break;
    1254            0 :                 case CalculateNTUBoundsErrors::NominalEffectiveness1:
    1255            0 :                     FatalError = true;
    1256            0 :                     ShowSevereError(state, format("In the HeatExchanger:AirToAir:FlatPlate component {}", this->Name));
    1257            0 :                     ShowContinueError(state, "  the calculated nominal effectiveness is out of bounds");
    1258            0 :                     ShowContinueError(state, format("The effectiveness is {:.3R}", Eps0));
    1259            0 :                     ShowContinueError(state, format("The effectiveness should be >= 0.0 and <= {:.3R}", 1.0 / (1.0 + Z)));
    1260            0 :                     ShowContinueError(state,
    1261              :                                       "Eff = (Nom_Sup_Mass_Flow_Rate/Min_Mass_Flow_Rate)*(T_nom_sup_out-T_nom_sup_in)/(T_nom_sec_in-T_nom_sup_in)");
    1262            0 :                     ShowContinueError(state, "The temperatures are user inputs. The mass flow rates are user input volume flow rates");
    1263            0 :                     ShowContinueError(state, format("  times the density of air [{:.2R} kg/m3]", RhoAir));
    1264            0 :                     ShowContinueError(state, "Change these inputs to obtain a physically realizable heat exchanger effectiveness");
    1265            0 :                     break;
    1266            0 :                 case CalculateNTUBoundsErrors::NominalEffectiveness2:
    1267            0 :                     FatalError = true;
    1268            0 :                     ShowSevereError(state, format("In the HeatExchanger:AirToAir:FlatPlate component {}", this->Name));
    1269            0 :                     ShowContinueError(state, "  the calculated nominal effectiveness is out of bounds");
    1270            0 :                     ShowContinueError(state, format("The effectiveness is {:.3R}", Eps0));
    1271            0 :                     ShowContinueError(state, format("The effectiveness should be >= 0.0 and <= {:.3R}", (1.0 - std::exp(-Z)) / Z));
    1272            0 :                     ShowContinueError(state,
    1273              :                                       "Eff = (Nom_Sup_Mass_Flow_Rate/Min_Mass_Flow_Rate)*(T_nom_sup_out-T_nom_sup_in)/(T_nom_sec_in-T_nom_sup_in)");
    1274            0 :                     ShowContinueError(state, "The temperatures are user inputs. The mass flow rates are user input volume flow rates");
    1275            0 :                     ShowContinueError(state, format("  times the density of air [{:.2R} kg/m3]", RhoAir));
    1276            0 :                     ShowContinueError(state, "Change these inputs to obtain a physically realizable heat exchanger effectiveness");
    1277            0 :                     break;
    1278            0 :                 case CalculateNTUBoundsErrors::Quantity:
    1279            0 :                     FatalError = true;
    1280            0 :                     ShowSevereError(state, format("In the HeatExchanger:AirToAir:FlatPlate component {}", this->Name));
    1281            0 :                     ShowContinueError(state, "  the quantity Eff_nom*(Min_Mass_Flow_Rate / Max_Mass_Flow_Rate) is out of bounds");
    1282            0 :                     ShowContinueError(state, format("The value is {:.3R}", Eps0 * Z));
    1283            0 :                     ShowContinueError(state, format("The value should be >= 0.0 and <= {:.3R}", 1.0 - std::exp(Z * (SMALL - 1.0))));
    1284            0 :                     ShowContinueError(
    1285              :                         state,
    1286              :                         "Eff_nom = (Nom_Sup_Mass_Flow_Rate/Min_Mass_Flow_Rate) * (T_nom_sup_out - T_nom_sup_in)/(T_nom_sec_in - T_nom_sup_in)");
    1287            0 :                     ShowContinueError(state, "The temperatures are user inputs. The mass flow rates are user input volume flow rates");
    1288            0 :                     ShowContinueError(state, format("  times the density of air [{:.2R} kg/m3]", RhoAir));
    1289            0 :                     ShowContinueError(state,
    1290              :                                       "Change these inputs to obtain a physically realizable product of effectiveness times min/max mass ratio "
    1291              :                                       "for this heat exchanger");
    1292            0 :                     break;
    1293            0 :                 case CalculateNTUBoundsErrors::NominalEffectiveness3:
    1294            0 :                     FatalError = true;
    1295            0 :                     ShowSevereError(state, format("In the HeatExchanger:AirToAir:FlatPlate component {}", this->Name));
    1296            0 :                     ShowContinueError(state, "  the calculated nominal effectiveness is out of bounds");
    1297            0 :                     ShowContinueError(state, format("The effectiveness is {:.3R}", Eps0));
    1298            0 :                     ShowContinueError(state, "The effectiveness should be >= 0.0 and <= 1.0");
    1299            0 :                     ShowContinueError(state,
    1300              :                                       "Eff = (Nom_Sup_Mass_Flow_Rate/Min_Mass_Flow_Rate)*(T_nom_sup_out-T_nom_sup_in)/(T_nom_sec_in-T_nom_sup_in)");
    1301            0 :                     ShowContinueError(state, "The temperatures are user inputs. The mass flow rates are user input volume flow rates");
    1302            0 :                     ShowContinueError(state, format("  times the density of air [{:.2R} kg/m3]", RhoAir));
    1303            0 :                     ShowContinueError(state, "Change these inputs to obtain a physically realizable heat exchanger effectiveness");
    1304            0 :                     break;
    1305            0 :                 case CalculateNTUBoundsErrors::Invalid:
    1306              :                 case CalculateNTUBoundsErrors::Num:
    1307            0 :                     break; // function won't actually return ::Invalid or ::Num, this is just so the compiler doesn't complain about the missing cases
    1308              :                 }
    1309              : 
    1310           81 :                 if (FatalError) {
    1311            0 :                     ShowFatalError(state, "Heat exchanger design calculation caused fatal error: program terminated.");
    1312              :                 }
    1313              : 
    1314           81 :                 this->UA0 = NTU0 * CMin0 * CpAir;
    1315           81 :                 this->mTSup0 = this->NomSupAirMassFlow * (this->NomSupAirInTemp + KELVZERO);
    1316           81 :                 this->mTSec0 = this->NomSecAirMassFlow * (this->NomSecAirInTemp + KELVZERO);
    1317              : 
    1318              :                 // check validity
    1319           81 :                 if (this->NomSupAirMassFlow * this->NomSecAirMassFlow < HVAC::SmallMassFlow * HVAC::SmallMassFlow) {
    1320            0 :                     ShowFatalError(state, "Mass flow in HeatExchanger:AirToAir:FlatPlate too small in initialization.");
    1321              :                 }
    1322              : 
    1323           81 :                 if (this->mTSup0 < HVAC::SmallMassFlow) {
    1324            0 :                     ShowFatalError(state, "(m*T)Sup,in in HeatExchanger:AirToAir:FlatPlate too small in initialization.");
    1325              :                 }
    1326              : 
    1327           81 :                 if (this->mTSec0 < HVAC::SmallMassFlow) {
    1328            0 :                     ShowFatalError(state, "(m*T)Sec,in in HeatExchanger:AirToAir:FlatPlate too small in initialization.");
    1329              :                 }
    1330              : 
    1331           81 :                 if (CMin0 < HVAC::SmallMassFlow) {
    1332            0 :                     ShowFatalError(state, "CMin0 in HeatExchanger:AirToAir:FlatPlate too small in initialization.");
    1333              :                 }
    1334           81 :                 break;
    1335              : 
    1336          947 :             case HVAC::HXType::AirToAir_SensAndLatent:
    1337          947 :                 if (this->SupOutletNode > 0 && this->ControlToTemperatureSetPoint) {
    1338          116 :                     if (state.dataLoopNodes->Node(this->SupOutletNode).TempSetPoint == DataLoopNode::SensedNodeFlagValue) {
    1339            0 :                         if (!state.dataGlobal->AnyEnergyManagementSystemInModel) {
    1340            0 :                             ShowSevereError(state,
    1341            0 :                                             format("Missing temperature setpoint for {} \"{}\" :", HVAC::hxTypeNames[(int)this->type], this->Name));
    1342            0 :                             ShowContinueError(
    1343              :                                 state, "  use a Setpoint Manager to establish a setpoint at the supply air outlet node of the Heat Exchanger.");
    1344            0 :                             ShowFatalError(state, " Previous condition causes program termination.");
    1345              :                         } else {
    1346              :                             // need call to EMS to check node
    1347            0 :                             EMSManager::CheckIfNodeSetPointManagedByEMS(state, this->SupOutletNode, HVAC::CtrlVarType::Temp, FatalError);
    1348            0 :                             if (FatalError) {
    1349            0 :                                 ShowSevereError(
    1350            0 :                                     state, format("Missing temperature setpoint for {} \"{}\" :", HVAC::hxTypeNames[(int)this->type], this->Name));
    1351            0 :                                 ShowContinueError(
    1352              :                                     state, "  use a Setpoint Manager to establish a setpoint at the supply air outlet node of the Heat Exchanger.");
    1353            0 :                                 ShowContinueError(
    1354              :                                     state, "  or use an EMS actuator to establish a setpoint at the supply air outlet node of the Heat Exchanger.");
    1355            0 :                                 ShowFatalError(state, " Previous condition causes program termination.");
    1356              :                             }
    1357              :                         }
    1358              :                     }
    1359              :                 }
    1360          947 :                 break;
    1361              : 
    1362           36 :             default:
    1363              :                 // nothing
    1364           36 :                 break;
    1365              :             }
    1366              : 
    1367         1064 :             this->myEnvrnFlag = false;
    1368              :         }
    1369              : 
    1370      3904968 :         if (!state.dataGlobal->BeginEnvrnFlag) {
    1371      3888267 :             this->myEnvrnFlag = true;
    1372              :         }
    1373              : 
    1374              :         // Do these initializations every time step
    1375      3904968 :         int const SupInNode = this->SupInletNode;
    1376      3904968 :         int const SecInNode = this->SecInletNode;
    1377              : 
    1378              :         // Get information from inlet nodes
    1379              : 
    1380      3904968 :         this->SupInTemp = state.dataLoopNodes->Node(SupInNode).Temp;
    1381      3904968 :         this->SupInHumRat = state.dataLoopNodes->Node(SupInNode).HumRat;
    1382      3904968 :         this->SupInEnth = state.dataLoopNodes->Node(SupInNode).Enthalpy;
    1383      3904968 :         this->SupInMassFlow = state.dataLoopNodes->Node(SupInNode).MassFlowRate;
    1384      3904968 :         this->SecInTemp = state.dataLoopNodes->Node(SecInNode).Temp;
    1385      3904968 :         this->SecInHumRat = state.dataLoopNodes->Node(SecInNode).HumRat;
    1386      3904968 :         this->SecInEnth = state.dataLoopNodes->Node(SecInNode).Enthalpy;
    1387      3904968 :         this->SecInMassFlow = state.dataLoopNodes->Node(SecInNode).MassFlowRate;
    1388              : 
    1389              :         // initialize the output variables
    1390      3904968 :         this->SensHeatingRate = 0.0;
    1391      3904968 :         this->SensHeatingEnergy = 0.0;
    1392      3904968 :         this->LatHeatingRate = 0.0;
    1393      3904968 :         this->LatHeatingEnergy = 0.0;
    1394      3904968 :         this->TotHeatingRate = 0.0;
    1395      3904968 :         this->TotHeatingEnergy = 0.0;
    1396      3904968 :         this->SensCoolingRate = 0.0;
    1397      3904968 :         this->SensCoolingEnergy = 0.0;
    1398      3904968 :         this->LatCoolingRate = 0.0;
    1399      3904968 :         this->LatCoolingEnergy = 0.0;
    1400      3904968 :         this->TotCoolingRate = 0.0;
    1401      3904968 :         this->TotCoolingEnergy = 0.0;
    1402      3904968 :         this->ElecUseRate = 0.0;
    1403      3904968 :         this->ElecUseEnergy = 0.0;
    1404      3904968 :         this->SensEffectiveness = 0.0;
    1405      3904968 :         this->LatEffectiveness = 0.0;
    1406      3904968 :         this->SupBypassMassFlow = 0.0;
    1407      3904968 :         this->SecBypassMassFlow = 0.0;
    1408              : 
    1409              :         //  Initialize inlet conditions
    1410              : 
    1411      3904968 :         switch (this->type) {
    1412      3232439 :         case HVAC::HXType::AirToAir_FlatPlate:
    1413              :         case HVAC::HXType::AirToAir_SensAndLatent:
    1414      3232439 :             break;
    1415              : 
    1416       672529 :         case HVAC::HXType::Desiccant_Balanced:
    1417       672529 :             if (this->MySetPointTest) {
    1418           61 :                 if (!state.dataGlobal->SysSizingCalc && state.dataHVACGlobal->DoSetPointTest) {
    1419            7 :                     if (!state.dataHeatRecovery->CalledFromParentObject) {
    1420            0 :                         if (state.dataLoopNodes->Node(this->SecOutletNode).HumRatMax == DataLoopNode::SensedNodeFlagValue) {
    1421            0 :                             if (!state.dataGlobal->AnyEnergyManagementSystemInModel) {
    1422            0 :                                 ShowWarningError(
    1423              :                                     state,
    1424            0 :                                     format("Missing optional HumRatMax setpoint for {} \"{}\"", HVAC::hxTypeNames[(int)this->type], this->Name));
    1425            0 :                                 ShowContinueError(state,
    1426              :                                                   "...the simulation will continue without control of the desiccant heat exchanger to a maximum "
    1427              :                                                   "humidity ratio setpoint.");
    1428            0 :                                 ShowContinueError(state,
    1429              :                                                   "...use a Setpoint Manager to establish a setpoint at the process air outlet node of the "
    1430              :                                                   "desiccant Heat Exchanger if control is desired.");
    1431              :                             } else {
    1432            0 :                                 bool LocalWarningError = false;
    1433              :                                 // need call to EMS to check node
    1434            0 :                                 EMSManager::CheckIfNodeSetPointManagedByEMS(
    1435              :                                     state, this->SecOutletNode, HVAC::CtrlVarType::MaxHumRat, LocalWarningError);
    1436            0 :                                 state.dataLoopNodes->NodeSetpointCheck(this->SecOutletNode).needsSetpointChecking = false;
    1437            0 :                                 if (LocalWarningError) {
    1438            0 :                                     ShowWarningError(
    1439              :                                         state,
    1440            0 :                                         format("Missing optional HumRatMax setpoint for {} \"{}\"", HVAC::hxTypeNames[(int)this->type], this->Name));
    1441            0 :                                     ShowContinueError(state,
    1442              :                                                       "...the simulation will continue without control of the desiccant heat exchanger to a "
    1443              :                                                       "maximum humidity ratio setpoint.");
    1444            0 :                                     ShowContinueError(state,
    1445              :                                                       "...use a Setpoint Manager to establish a setpoint at the process air outlet node of the "
    1446              :                                                       "desiccant Heat Exchanger if control is desired.");
    1447            0 :                                     ShowContinueError(state,
    1448              :                                                       "...or use an EMS Actuator to establish a maximum humidity ratio setpoint at the process "
    1449              :                                                       "air outlet node of the desiccant Heat Exchanger if control is desired.");
    1450              :                                 }
    1451              :                             }
    1452              :                         }
    1453              :                     }
    1454            7 :                     this->MySetPointTest = false;
    1455              :                 }
    1456              :             }
    1457              : 
    1458       672529 :             if ((CompanionCoilIndex > -1) &&
    1459       242786 :                 ((CompanionCoilType_Num == HVAC::CoilDX_CoolingSingleSpeed) || (CompanionCoilType_Num == HVAC::Coil_CoolingAirToAirVariableSpeed) ||
    1460              :                  (CompanionCoilType_Num == HVAC::CoilDX_Cooling))) {
    1461              : 
    1462       494944 :                 if (CompanionCoilType_Num == HVAC::CoilDX_CoolingSingleSpeed || CompanionCoilType_Num == HVAC::CoilDX_CoolingTwoStageWHumControl) {
    1463       971559 :                     if (state.dataDXCoils->DXCoilFullLoadOutAirTemp(CompanionCoilIndex) == 0.0 ||
    1464       112073 :                         state.dataDXCoils->DXCoilFullLoadOutAirHumRat(CompanionCoilIndex) == 0.0) {
    1465              :                         //       DX Coil is OFF, read actual inlet conditions
    1466       317670 :                         state.dataHeatRecovery->FullLoadOutAirTemp = this->SecInTemp;
    1467       317670 :                         state.dataHeatRecovery->FullLoadOutAirHumRat = this->SecInHumRat;
    1468              :                     } else {
    1469              :                         //       DX Coil is ON, read full load DX coil outlet conditions (conditions HX sees when ON)
    1470       112073 :                         state.dataHeatRecovery->FullLoadOutAirTemp = state.dataDXCoils->DXCoilFullLoadOutAirTemp(CompanionCoilIndex);
    1471       112073 :                         state.dataHeatRecovery->FullLoadOutAirHumRat = state.dataDXCoils->DXCoilFullLoadOutAirHumRat(CompanionCoilIndex);
    1472              :                     }
    1473        65201 :                 } else if (CompanionCoilType_Num == HVAC::Coil_CoolingAirToAirVariableSpeed) {
    1474              :                     // how to support VS dx coil here?
    1475         6632 :                     state.dataHeatRecovery->FullLoadOutAirTemp = state.dataVariableSpeedCoils->VarSpeedCoil(CompanionCoilIndex).OutletAirDBTemp;
    1476         6632 :                     state.dataHeatRecovery->FullLoadOutAirHumRat = state.dataVariableSpeedCoils->VarSpeedCoil(CompanionCoilIndex).OutletAirHumRat;
    1477        58569 :                 } else if (CompanionCoilType_Num == HVAC::CoilDX_Cooling) {
    1478              :                     // Use the new coil option:
    1479        58569 :                     state.dataHeatRecovery->FullLoadOutAirTemp = state.dataCoilCoolingDX->coilCoolingDXs[CompanionCoilIndex].outletAirDryBulbTemp;
    1480        58569 :                     state.dataHeatRecovery->FullLoadOutAirHumRat = state.dataCoilCoolingDX->coilCoolingDXs[CompanionCoilIndex].outletAirHumRat;
    1481              :                 } else {
    1482              :                     //
    1483              :                 }
    1484              : 
    1485              :             } else {
    1486              : 
    1487              :                 //     HX only (not used in conjunction with DX coil), read inlet conditions
    1488       177585 :                 state.dataHeatRecovery->FullLoadOutAirTemp = this->SecInTemp;
    1489       177585 :                 state.dataHeatRecovery->FullLoadOutAirHumRat = this->SecInHumRat;
    1490              :             }
    1491       672529 :             break;
    1492              : 
    1493            0 :         default:
    1494              :             //   Will never get here
    1495            0 :             break;
    1496              :         }
    1497      3904968 :     }
    1498              : 
    1499          162 :     void HeatExchCond::size(EnergyPlusData &state)
    1500              :     {
    1501              : 
    1502              :         // SUBROUTINE INFORMATION:
    1503              :         //       AUTHOR         Richard Raustad
    1504              :         //       DATE WRITTEN   October 2007
    1505              :         //       MODIFIED       February 2014 Daeho Kang, enable sizing multiple HX types and add additional sizing fields
    1506              :         //       RE-ENGINEERED  na
    1507              : 
    1508              :         // PURPOSE OF THIS SUBROUTINE:
    1509              :         // This subroutine is for sizing Heat Exchanger components for which flow rates have not been
    1510              :         // specified in the input. Currently, only nominal supply air flow rate for the generic HX can be autosized.
    1511              : 
    1512              :         // METHODOLOGY EMPLOYED:
    1513              :         // Obtains flow rates from the system or OA system sizing arrays
    1514              : 
    1515              :         // SUBROUTINE PARAMETER DEFINITIONS:
    1516          162 :         std::string_view RoutineName = "SizeHeatRecovery";
    1517              : 
    1518              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    1519          162 :         std::string SizingString; // input field sizing description
    1520              : 
    1521          162 :         auto &ZoneEqSizing(state.dataSize->ZoneEqSizing);
    1522              : 
    1523          162 :         state.dataSize->HRFlowSizingFlag = true;
    1524          162 :         bool PrintFlag = true; // true when sizing information is reported in the eio file
    1525          162 :         int FieldNum = 0;      // IDD numeric field index where input field description is found
    1526          162 :         switch (this->type) {
    1527            7 :         case HVAC::HXType::Desiccant_Balanced:
    1528            7 :             PrintFlag = false;
    1529            7 :             break;
    1530          141 :         case HVAC::HXType::AirToAir_SensAndLatent:
    1531          141 :             FieldNum = 1;
    1532          141 :             break;
    1533           14 :         case HVAC::HXType::AirToAir_FlatPlate:
    1534           14 :             FieldNum = 2;
    1535           14 :             break;
    1536            0 :         default:
    1537            0 :             assert(0);
    1538              :         }
    1539              : 
    1540          324 :         std::string CompName = this->Name;
    1541          324 :         std::string CompType = std::string(HVAC::hxTypeNames[(int)this->type]);
    1542          162 :         if (FieldNum > 0) {
    1543          155 :             SizingString = this->NumericFieldNames(FieldNum) + " [m3/s]";
    1544              :         } else {
    1545            7 :             SizingString = "Nominal Supply Air Flow Rate [m3/s]"; // desiccant balanced flow does not have an input for air volume flow rate
    1546              :         }
    1547          162 :         if (state.dataSize->CurZoneEqNum > 0) {
    1548          118 :             if (this->NomSupAirVolFlow == DataSizing::AutoSize) {
    1549          104 :                 if (ZoneEqSizing(state.dataSize->CurZoneEqNum).DesignSizeFromParent) {
    1550              :                     // Heat recovery heat exchanger in zoneHVAC equipment should have been sized to OA flow in the parent equipment
    1551          102 :                     state.dataSize->DataConstantUsedForSizing = ZoneEqSizing(state.dataSize->CurZoneEqNum).AirVolFlow;
    1552              :                 } else {
    1553            2 :                     state.dataSize->DataConstantUsedForSizing =
    1554            2 :                         std::max(state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).DesCoolVolFlow,
    1555            2 :                                  state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).DesHeatVolFlow);
    1556              :                 }
    1557          104 :                 state.dataSize->DataFractionUsedForSizing = 1.0;
    1558              :             } else {
    1559           14 :                 if (state.dataSize->ZoneSizingRunDone) {
    1560           14 :                     if (ZoneEqSizing(state.dataSize->CurZoneEqNum).DesignSizeFromParent) {
    1561              :                         // Heat recovery heat exchanger in zoneHVAC equipment should have been sized to OA flow in the parent equipment
    1562            5 :                         state.dataSize->DataConstantUsedForSizing = ZoneEqSizing(state.dataSize->CurZoneEqNum).AirVolFlow;
    1563              :                     } else {
    1564            9 :                         state.dataSize->DataConstantUsedForSizing =
    1565            9 :                             std::max(state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).DesCoolVolFlow,
    1566            9 :                                      state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).DesHeatVolFlow);
    1567              :                     }
    1568           14 :                     state.dataSize->DataFractionUsedForSizing = 1.0;
    1569              :                 }
    1570              :             }
    1571              :         }
    1572          162 :         Real64 TempSize = this->NomSupAirVolFlow;
    1573          162 :         bool errorsFound = false;
    1574          324 :         SystemAirFlowSizer sizerSystemAirFlow;
    1575          162 :         sizerSystemAirFlow.overrideSizingString(SizingString);
    1576              :         // sizerSystemAirFlow.setHVACSizingIndexData(FanCoil(FanCoilNum).HVACSizingIndex);
    1577          162 :         sizerSystemAirFlow.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
    1578          162 :         this->NomSupAirVolFlow = sizerSystemAirFlow.size(state, TempSize, errorsFound);
    1579          162 :         state.dataSize->DataConstantUsedForSizing = 0.0;
    1580          162 :         state.dataSize->DataFractionUsedForSizing = 0.0;
    1581          162 :         switch (this->type) {
    1582          141 :         case HVAC::HXType::AirToAir_SensAndLatent: {
    1583          141 :             this->NomSecAirVolFlow = this->NomSupAirVolFlow;
    1584          141 :             state.dataSize->HRFlowSizingFlag = false;
    1585          141 :             break;
    1586              :         }
    1587           14 :         case HVAC::HXType::AirToAir_FlatPlate: {
    1588           14 :             PrintFlag = true;
    1589           14 :             FieldNum = 5;
    1590           14 :             CompName = this->Name;
    1591           14 :             CompType = HVAC::hxTypeNames[(int)this->type];
    1592           14 :             SizingString = this->NumericFieldNames(FieldNum) + " [m3/s]";
    1593           14 :             if (this->NomSecAirVolFlow == DataSizing::AutoSize) {
    1594            0 :                 state.dataSize->DataConstantUsedForSizing = this->NomSupAirVolFlow;
    1595            0 :                 state.dataSize->DataFractionUsedForSizing = 1.0;
    1596              :             } else {
    1597           14 :                 if (state.dataSize->ZoneSizingRunDone || state.dataSize->SysSizingRunDone) {
    1598            9 :                     state.dataSize->DataConstantUsedForSizing = this->NomSupAirVolFlow;
    1599            9 :                     state.dataSize->DataFractionUsedForSizing = 1.0;
    1600              :                 }
    1601              :             }
    1602           14 :             TempSize = this->NomSecAirVolFlow;
    1603           14 :             bool errorsFound2 = false;
    1604           14 :             SystemAirFlowSizer sizerSystemAirFlow2;
    1605           14 :             sizerSystemAirFlow2.overrideSizingString(SizingString);
    1606              :             // sizerSystemAirFlow2.setHVACSizingIndexData(FanCoil(FanCoilNum).HVACSizingIndex);
    1607           14 :             sizerSystemAirFlow2.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
    1608           14 :             this->NomSecAirVolFlow = sizerSystemAirFlow2.size(state, TempSize, errorsFound2);
    1609           14 :             state.dataSize->DataConstantUsedForSizing = 0.0;
    1610           14 :             state.dataSize->DataFractionUsedForSizing = 0.0;
    1611           14 :             state.dataSize->HRFlowSizingFlag = false;
    1612              : 
    1613              :             // Calculate nominal effectiveness
    1614              : 
    1615           14 :             break;
    1616           14 :         }
    1617            7 :         case HVAC::HXType::Desiccant_Balanced: {
    1618            7 :             state.dataSize->HRFlowSizingFlag = false;
    1619            7 :             int const BalDesDehumPerfIndex = this->PerfDataIndex; // index of dehum performance data1 object
    1620            7 :             auto &thisBDDPerf = state.dataHeatRecovery->BalDesDehumPerfData(BalDesDehumPerfIndex);
    1621              : 
    1622            7 :             FieldNum = 1;
    1623            7 :             PrintFlag = true;
    1624            7 :             CompName = thisBDDPerf.Name;
    1625            7 :             CompType = thisBDDPerf.PerfType;
    1626            7 :             SizingString = thisBDDPerf.NumericFieldNames(FieldNum) + " [m3/s]";
    1627            7 :             TempSize = thisBDDPerf.NomSupAirVolFlow;
    1628            7 :             bool errorsFound2 = false;
    1629            7 :             SystemAirFlowSizer sizerSystemAirFlow3;
    1630            7 :             sizerSystemAirFlow3.overrideSizingString(SizingString);
    1631              :             // sizerSystemAirFlow3.setHVACSizingIndexData(FanCoil(FanCoilNum).HVACSizingIndex);
    1632            7 :             sizerSystemAirFlow3.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
    1633            7 :             thisBDDPerf.NomSupAirVolFlow = sizerSystemAirFlow3.size(state, TempSize, errorsFound2);
    1634            7 :             this->NomSupAirVolFlow = thisBDDPerf.NomSupAirVolFlow;
    1635            7 :             this->NomSecAirVolFlow = thisBDDPerf.NomSupAirVolFlow;
    1636              : 
    1637            7 :             state.dataSize->DataAirFlowUsedForSizing = thisBDDPerf.NomSupAirVolFlow;
    1638            7 :             TempSize = thisBDDPerf.NomProcAirFaceVel;
    1639            7 :             bool errorsFound3 = false;
    1640            7 :             DesiccantDehumidifierBFPerfDataFaceVelocitySizer sizerDesDehumBFFaceVel;
    1641            7 :             sizerDesDehumBFFaceVel.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
    1642            7 :             thisBDDPerf.NomProcAirFaceVel = sizerDesDehumBFFaceVel.size(state, TempSize, errorsFound3);
    1643              : 
    1644            7 :             state.dataSize->DataAirFlowUsedForSizing = 0.0;
    1645            7 :             break;
    1646            7 :         }
    1647            0 :         default:
    1648            0 :             assert(0);
    1649              :         }
    1650              : 
    1651              :         // std 229 new heat recovery table variables
    1652          162 :         assert((this->type != HVAC::HXType::Invalid) && (this->ExchConfig != HXConfigurationType::Invalid));
    1653          324 :         OutputReportPredefined::PreDefTableEntry(
    1654          324 :             state, state.dataOutRptPredefined->pdchAirHRInputObjType, this->Name, HVAC::hxTypeNames[(int)this->type]);
    1655          324 :         OutputReportPredefined::PreDefTableEntry(
    1656          324 :             state, state.dataOutRptPredefined->pdchAirHRPlateOrRotary, this->Name, hxConfigurationNames[(int)this->ExchConfig]);
    1657          162 :         OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchAirHRSupplyAirflow, this->Name, this->NomSupAirVolFlow);
    1658          162 :         OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchAirHRExhaustAirflow, this->Name, this->NomSecAirVolFlow);
    1659              : 
    1660          162 :         if (this->type == HVAC::HXType::AirToAir_SensAndLatent) {
    1661          282 :             OutputReportPredefined::PreDefTableEntry(
    1662          141 :                 state, state.dataOutRptPredefined->pdchAirHRSenEffAt100PerHeatAirFlow, this->Name, this->HeatEffectSensible100);
    1663          282 :             OutputReportPredefined::PreDefTableEntry(
    1664          141 :                 state, state.dataOutRptPredefined->pdchAirHRSenEffAt100PerCoolAirFlow, this->Name, this->CoolEffectSensible100);
    1665          282 :             OutputReportPredefined::PreDefTableEntry(
    1666          141 :                 state, state.dataOutRptPredefined->pdchAirHRLatEffAt100PerHeatAirFlow, this->Name, this->HeatEffectLatent100);
    1667          282 :             OutputReportPredefined::PreDefTableEntry(
    1668          141 :                 state, state.dataOutRptPredefined->pdchAirHRLatEffAt100PerCoolAirFlow, this->Name, this->CoolEffectLatent100);
    1669              :         } else {
    1670           21 :             OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchAirHRSenEffAt100PerHeatAirFlow, this->Name, "N/A");
    1671           21 :             OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchAirHRSenEffAt100PerCoolAirFlow, this->Name, "N/A");
    1672           21 :             OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchAirHRLatEffAt100PerHeatAirFlow, this->Name, "N/A");
    1673           21 :             OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchAirHRLatEffAt100PerCoolAirFlow, this->Name, "N/A");
    1674              :         }
    1675          162 :     }
    1676              : 
    1677              :     void
    1678       771556 :     HeatExchCond::CalcAirToAirPlateHeatExch(EnergyPlusData &state,
    1679              :                                             bool const HXUnitOn,                           // flag to simulate heat exchanger heat recovery
    1680              :                                             ObjexxFCL::Optional_bool_const EconomizerFlag, // economizer flag pass by air loop or OA sys
    1681              :                                             ObjexxFCL::Optional_bool_const HighHumCtrlFlag // high humidity control flag passed by airloop or OA sys
    1682              :     )
    1683              :     {
    1684              : 
    1685              :         // SUBROUTINE INFORMATION:
    1686              :         //       AUTHOR         Michael Wetter
    1687              :         //       DATE WRITTEN   March 1999
    1688              :         //       MODIFIED       F. Buhl Nov 2000, R. Raustad - FSEC, Feb 2009 - added economizer flags
    1689              :         //                      Both the economizer and high humidity control flags can disable the HX
    1690              :         //       RE-ENGINEERED  na
    1691              : 
    1692              :         // PURPOSE OF THIS SUBROUTINE:
    1693              :         // Calculate the outlet conditions for an air to air plate heat
    1694              :         // exchanger given the inlet conditions.
    1695              : 
    1696              :         // METHODOLOGY EMPLOYED:
    1697              :         // This is a static heat exchanger model. No geometrical input data
    1698              :         // is needed. No knowledge of h*A values is needed except the ratio
    1699              :         // of the primary side to the secondary side convective heat transfer
    1700              :         // coefficient times the exchanger surface area. Effectiveness - NTU
    1701              :         // heat exchanger formulas are used.
    1702              : 
    1703              :         // The time varying load is calculated based on the variation of the
    1704              :         // convective heat transfer coefficient.The variation is a function of
    1705              :         // mass flow rate and inlet temperature. An iterative solution is only
    1706              :         // required during initialization in one specific flow arrangement. During
    1707              :         // the time steps the solution is explicit. The iteration is done with
    1708              :         // the Regula Falsi algorithm. Convergence is always achieved.
    1709              : 
    1710              :         // REFERENCES:
    1711              :         // M. Wetter, Simulation Model Air-to-Air Plate Heat Exchanger
    1712              :         // LBNL Report 42354, 1999.
    1713              : 
    1714              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    1715       771556 :         bool UnitOn = true;    // unit on flag
    1716       771556 :         Real64 QTrans = 0.0;   // heat transferred in the heat exchanger [W]
    1717       771556 :         Real64 ElecCons = 0.0; // electricity consumption rate [W]
    1718              : 
    1719       771556 :         bool EconomizerActiveFlag = present(EconomizerFlag) && bool(EconomizerFlag);    // local representing the economizer status when PRESENT
    1720       771556 :         bool HighHumCtrlActiveFlag = present(HighHumCtrlFlag) && bool(HighHumCtrlFlag); // local representing high humidity control when PRESENT
    1721              : 
    1722              :         Real64 UnitSupMassFlow; // supply air mass flow rate passing through the unit [kg/s]
    1723              :         Real64 UnitSecMassFlow; // secondary air mass flow rate passing through the unit [kg/s]
    1724       771556 :         if ((EconomizerActiveFlag || HighHumCtrlActiveFlag) && this->EconoLockOut) {
    1725       128124 :             UnitSupMassFlow = 0.0; // set HX supply flow to 0, all supply air will go through supply bypass
    1726       128124 :             UnitSecMassFlow = 0.0; // set HX secondary flow to 0, all secondary air will got through secondary bypass
    1727       128124 :             UnitOn = false;        // turn off HX calculations when in economizer mode
    1728              :         } else {
    1729              :             // if economizer operation is not allowed, air always passes through HX
    1730              :             // if CompanionCoilNum > 0, air always passes through HX (no economizer operation allowed)
    1731       643432 :             UnitSupMassFlow = min(this->NomSupAirMassFlow, this->SupInMassFlow);
    1732       643432 :             UnitSecMassFlow = min(this->NomSecAirMassFlow, this->SecInMassFlow);
    1733              :         }
    1734              : 
    1735       771556 :         if (this->availSched->getCurrentVal() <= 0.0) {
    1736        72902 :             UnitOn = false;
    1737              :         }
    1738       771556 :         if (this->SupInMassFlow <= HVAC::SmallMassFlow) {
    1739          120 :             UnitOn = false;
    1740              :         }
    1741       771556 :         if (this->SecInMassFlow <= HVAC::SmallMassFlow) {
    1742          120 :             UnitOn = false;
    1743              :         }
    1744       771556 :         if (!HXUnitOn) {
    1745            0 :             UnitOn = false;
    1746              :         }
    1747              : 
    1748       771556 :         if (UnitOn) {
    1749              :             // unit is on
    1750              :             // calculate the UA for this time step
    1751              :             // ratio of supply nominal m*T to actual m*T
    1752       570512 :             Real64 const QuotSup = SafeDiv(this->mTSup0, UnitSupMassFlow * (this->SupInTemp + KELVZERO));
    1753              :             // ratio of secondary nominal m*T to actual m*T
    1754       570512 :             Real64 const QuotExh = SafeDiv(this->mTSec0, UnitSecMassFlow * (this->SecInTemp + KELVZERO));
    1755              :             // denominator of UA calculation
    1756       570512 :             Real64 const Deno = std::pow(QuotSup, 0.78) + this->hARatio * std::pow(QuotExh, 0.78);
    1757              :             // present UA
    1758       570512 :             Real64 const UA = this->UA0 * (this->hARatio + 1.0) / Deno;
    1759              :             // calculate the NTU
    1760       570512 :             Real64 const CSup = UnitSupMassFlow * Psychrometrics::PsyCpAirFnW(this->SupInHumRat);
    1761              :             // secondary air capacitance rate [J/C/s]
    1762       570512 :             Real64 const CSec = UnitSecMassFlow * Psychrometrics::PsyCpAirFnW(this->SecInHumRat);
    1763              :             // note: no C can be zero since otherwise we wouldn't be here
    1764              :             Real64 Z;    // Ratio of minimum air capacitance rate to maximum air capacitance rate
    1765              :             Real64 CMin; // minimum air capacitance rate [J/C/s]
    1766       570512 :             if (CSup < CSec) {
    1767        84949 :                 CMin = CSup;
    1768        84949 :                 Z = CMin / CSec;
    1769              :             } else {
    1770       485563 :                 CMin = CSec;
    1771       485563 :                 Z = CMin / CSup;
    1772              :             }
    1773              :             // Number of heat transfer units
    1774       570512 :             Real64 const NTU = UA / CMin;
    1775              :             // Get the effectiveness
    1776       570512 :             Real64 Eps = CalculateEpsFromNTUandZ(state, NTU, Z, this->FlowArr);
    1777              :             // use the effectiveness to calculate the unit outlet conditions
    1778       570512 :             Real64 TempSupOut = this->SupInTemp + Eps * CMin / CSup * (this->SecInTemp - this->SupInTemp);
    1779       570512 :             QTrans = CSup * (TempSupOut - this->SupInTemp);
    1780              :             // unit secondary outlet temperature [C]
    1781       570512 :             Real64 TempSecOut = this->SecInTemp - QTrans / CSec;
    1782              :             // unit supply outlet humidity ratio [kg water / kg dry air]
    1783       570512 :             Real64 HumRatSupOut = this->SupInHumRat;
    1784              :             // unit supply outlet enthalpy [J/kg]
    1785       570512 :             Real64 const EnthSupOut = Psychrometrics::PsyHFnTdbW(TempSupOut, HumRatSupOut);
    1786              :             // check for saturation in supply outlet
    1787              :             // unit supply outlet temperature at saturation (at EnthSupOut) [C]
    1788       570512 :             Real64 const TempSupOutSat = Psychrometrics::PsyTsatFnHPb(state, EnthSupOut, state.dataEnvrn->OutBaroPress);
    1789       570512 :             if (TempSupOutSat > TempSupOut) {
    1790         9544 :                 TempSupOut = TempSupOutSat;
    1791         9544 :                 HumRatSupOut = Psychrometrics::PsyWFnTdbH(state, TempSupOut, EnthSupOut);
    1792              :             }
    1793              :             // unit secondary outlet humidity ratio [kg water / kg dry air]
    1794       570512 :             Real64 HumRatSecOut = this->SecInHumRat;
    1795              :             // unit secondary outlet enthalpy [J/kgC]
    1796       570512 :             Real64 const EnthSecOut = Psychrometrics::PsyHFnTdbW(TempSecOut, HumRatSecOut);
    1797              :             // check for saturation in secondary outlet
    1798              :             // unit secondary outlet temperature at saturation (at EnthsSecOut) [C]
    1799       570512 :             Real64 const TempSecOutSat = Psychrometrics::PsyTsatFnHPb(state, EnthSecOut, state.dataEnvrn->OutBaroPress);
    1800       570512 :             if (TempSecOutSat > TempSecOut) {
    1801        20675 :                 TempSecOut = TempSecOutSat;
    1802        20675 :                 HumRatSecOut = Psychrometrics::PsyWFnTdbH(state, TempSecOut, EnthSecOut);
    1803              :             }
    1804              :             // calculate outlet conditions by mixing bypass air stream with air that went through the
    1805              :             // heat exchanger core.
    1806       570512 :             Real64 local_SupBypassMassFlow = max(0.0, this->SupInMassFlow - UnitSupMassFlow); // supply air mass flow rate bypassing unit [kg/s]
    1807       570512 :             Real64 local_SecBypassMassFlow = max(0.0, this->SecInMassFlow - UnitSecMassFlow); // secondary air mass flow rate bypassing unit [kg/s]
    1808              : 
    1809       570512 :             this->SupOutEnth = (UnitSupMassFlow * EnthSupOut + local_SupBypassMassFlow * this->SupInEnth) / this->SupInMassFlow;
    1810       570512 :             this->SupOutHumRat = (UnitSupMassFlow * HumRatSupOut + local_SupBypassMassFlow * this->SupInHumRat) / this->SupInMassFlow;
    1811       570512 :             this->SupOutTemp = Psychrometrics::PsyTdbFnHW(this->SupOutEnth, this->SupOutHumRat);
    1812       570512 :             this->SupOutMassFlow = this->SupInMassFlow;
    1813       570512 :             this->SecOutEnth = (UnitSecMassFlow * EnthSecOut + local_SecBypassMassFlow * this->SecInEnth) / this->SecInMassFlow;
    1814       570512 :             this->SecOutHumRat = (UnitSecMassFlow * HumRatSecOut + local_SecBypassMassFlow * this->SecInHumRat) / this->SecInMassFlow;
    1815       570512 :             this->SecOutTemp = Psychrometrics::PsyTdbFnHW(this->SecOutEnth, this->SecOutHumRat);
    1816       570512 :             this->SecOutMassFlow = this->SecInMassFlow;
    1817       570512 :             ElecCons = this->NomElecPower;
    1818              : 
    1819              :         } else {
    1820              :             // the unit is off. Pass through the air streams with no change
    1821       201044 :             this->SupOutEnth = this->SupInEnth;
    1822       201044 :             this->SupOutHumRat = this->SupInHumRat;
    1823       201044 :             this->SupOutTemp = this->SupInTemp;
    1824       201044 :             this->SupOutMassFlow = this->SupInMassFlow;
    1825       201044 :             this->SecOutEnth = this->SecInEnth;
    1826       201044 :             this->SecOutHumRat = this->SecInHumRat;
    1827       201044 :             this->SecOutTemp = this->SecInTemp;
    1828       201044 :             this->SecOutMassFlow = this->SecInMassFlow;
    1829              :         }
    1830              :         // supply air capacitance rate [J/C/s]
    1831       771556 :         Real64 const CSup = this->SupInMassFlow * Psychrometrics::PsyCpAirFnW(this->SupInHumRat);
    1832              :         // sensible heat recovery rate to supply air (heating +, cooling -)
    1833       771556 :         Real64 const SensHeatRecRate = CSup * (this->SupOutTemp - this->SupInTemp);
    1834              :         // total heat recovery rate to supply air (heating +, cooling -)
    1835       771556 :         Real64 const TotHeatRecRate = this->SupOutMassFlow * (this->SupOutEnth - this->SupInEnth);
    1836              :         // latent heat recovery rate to supply air (heating [humidify] +, cooling [dehumidify] -)
    1837       771556 :         Real64 const LatHeatRecRate = TotHeatRecRate - SensHeatRecRate;
    1838              : 
    1839       771556 :         if (SensHeatRecRate > 0.0) {
    1840        57230 :             this->SensHeatingRate = SensHeatRecRate;
    1841        57230 :             this->SensCoolingRate = 0.0;
    1842              :         } else {
    1843       714326 :             this->SensHeatingRate = 0.0;
    1844       714326 :             this->SensCoolingRate = std::abs(SensHeatRecRate);
    1845              :         }
    1846       771556 :         if (LatHeatRecRate > 0.0) {
    1847       211268 :             this->LatHeatingRate = LatHeatRecRate;
    1848       211268 :             this->LatCoolingRate = 0.0;
    1849              :         } else {
    1850       560288 :             this->LatHeatingRate = 0.0;
    1851       560288 :             this->LatCoolingRate = std::abs(LatHeatRecRate);
    1852              :         }
    1853       771556 :         if (TotHeatRecRate > 0.0) {
    1854        55305 :             this->TotHeatingRate = TotHeatRecRate;
    1855        55305 :             this->TotCoolingRate = 0.0;
    1856              :         } else {
    1857       716251 :             this->TotHeatingRate = 0.0;
    1858       716251 :             this->TotCoolingRate = std::abs(TotHeatRecRate);
    1859              :         }
    1860              : 
    1861       771556 :         this->ElecUseRate = ElecCons;
    1862       771556 :     }
    1863              : 
    1864      2460883 :     void HeatExchCond::CalcAirToAirGenericHeatExch(
    1865              :         EnergyPlusData &state,
    1866              :         bool const HXUnitOn,                              // flag to simulate heat exchanger heat recovery
    1867              :         bool const FirstHVACIteration,                    // first HVAC iteration flag
    1868              :         HVAC::FanOp const fanOp,                          // Supply air fan operating mode (1=cycling, 2=constant)
    1869              :         ObjexxFCL::Optional_bool_const EconomizerFlag,    // economizer flag pass by air loop or OA sys
    1870              :         ObjexxFCL::Optional_bool_const HighHumCtrlFlag,   // high humidity control flag passed by airloop or OA sys
    1871              :         ObjexxFCL::Optional<Real64 const> HXPartLoadRatio //
    1872              :     )
    1873              :     {
    1874              : 
    1875              :         // SUBROUTINE INFORMATION:
    1876              :         //       AUTHOR         Don Shirey
    1877              :         //       DATE WRITTEN   February 2003
    1878              :         //       MODIFIED       R. Raustad - FSEC, Feb 2009 - added economizer flags
    1879              :         //                      Both the economizer and high humidity control flags can disable the HX
    1880              :         //       RE-ENGINEERED  Richard Raustad, June 2003
    1881              : 
    1882              :         // PURPOSE OF THIS SUBROUTINE:
    1883              :         //  Calculate the outlet conditions for an air to air generic heat
    1884              :         //  exchanger given the inlet conditions.
    1885              : 
    1886              :         // METHODOLOGY EMPLOYED:
    1887              :         //  This is a standard heat exchanger effectiveness model. No geometrical input data
    1888              :         //  is needed. The model uses heat exchanger effectiveness performance data
    1889              :         //  to calculate the air temperature and humidity ratio of the leaving
    1890              :         //  supply and secondary air streams. Linear interpolation (or extrapolation)
    1891              :         //  is assumed to obtain heat exchanger effectiveness at off-rated conditions.
    1892              :         //  Economizer operation is allowed through the use of a Controller: Outside Air
    1893              :         //  object.
    1894              : 
    1895              :         // REFERENCES:
    1896              :         //  ARI Standard 1060-2001,Rating Air-to-Air Heat Exchangers for Energy Recovery Ventilation Equipment, www.ari.org
    1897              :         //  ASHRAE Standard 84, Method of Testing Air-To-Air Heat Exchangers, www.ashrae.org
    1898              :         //  U.S. Environmental Protection Agency software "SAVES" -
    1899              :         //   School Advanced Ventilation Engineering Software http://www.epa.gov/iaq/schooldesign/saves.html
    1900              : 
    1901              :         // SUBROUTINE PARAMETER DEFINITIONS:
    1902      2460883 :         Real64 constexpr ErrorTol(0.001); // error tolerance
    1903              : 
    1904              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    1905              :         int SupOutNode;
    1906              :         Real64 Error;           // iteration loop error variable
    1907              :         Real64 Iter;            // iteration counter
    1908              :         Real64 ControlFraction; // fraction of effectiveness when rotary HX speed or plate bypass modulation is used for
    1909              :         // temperature control
    1910              :         Real64 RhoSup;              // supply air density at actual pressure, temperature and humidity conditions [kg/m3]
    1911              :         Real64 RhoSec;              // secondary air density at actual pressure, temperature and humidity conditions [kg/m3]
    1912              :         Real64 RhoStd;              // standard air density at actual pressure, 20C dry-bulb temp and 0.0 absolute humidity [kg/m3]
    1913              :         Real64 CSup;                // supply air heat capacity rate [W/K]
    1914              :         Real64 CSec;                // secondary air heat capacity rate [W/K]
    1915              :         Real64 CMin;                // minimum air heat capacity rate [W/K]
    1916              :         Real64 TempSecOutSat;       // secondary air outlet temperature at saturation (at EnthsSecOut) [C]
    1917              :         Real64 HXSecAirVolFlowRate; // air volume flow rate of the secondary air stream through the heat exchanger [m3/sec]
    1918              :         Real64 HXSupAirVolFlowRate; // air volume flow rate of the supply air stream through the heat exchanger [m3/sec]
    1919              :         Real64 HXAvgAirVolFlowRate; // average air volume flow rate through the heat exchanger [m3/sec]
    1920              :         Real64 HXAirVolFlowRatio;   // ratio of avg actual air volume flow through HX to nominal HX air volume flow [-]
    1921              :         Real64 HXTempSetPoint;      // setpoint temperature at supply outlet node of HX when ControlToTemperatureSetPoint = Yes
    1922              :         Real64 MassFlowSecIn;       // secondary air mass flow rate at HX inlet
    1923              :         //  REAL(r64)    :: MassFlowSecOut      ! secondary air mass flow rate at HX outlet
    1924              :         Real64 MassFlowSupIn;     // supply air mass flow rate at HX inlet
    1925              :         Real64 MassFlowSupOut;    // supply air mass flow rate through HX core outlet
    1926              :         Real64 MassFlowSupBypass; // supply air bypass mass flow rate around HX core
    1927              :         Real64 TempSupIn;         // supply side temperature of air entering HX
    1928              :         Real64 TempSupOut;        // supply side temperature of air leaving HX core
    1929              :         Real64 HumRatSupIn;       // supply side humidity ratio of air entering HX
    1930              :         Real64 TempSecIn;         // secondary side temperature of air entering HX
    1931              :         Real64 SensHeatRecRate;   // sensible heat recovery rate to supply air (heating +, cooling -)
    1932              :         Real64 LatHeatRecRate;    // latent heat recovery rate to supply air (heating [humidify] +, cooling [dehumidify] -)
    1933              :         Real64 TotHeatRecRate;    // total heat recovery rate to supply air (heating +, cooling -)
    1934              :         Real64 AirSidePLR;
    1935              : 
    1936              :         // Initialize local variables
    1937      2460883 :         bool UnitOn = true;      // unit on flag
    1938      2460883 :         Real64 QSensTrans = 0.0; // sensible heat transferred by the heat exchanger [W]
    1939      2460883 :         Real64 QTotTrans = 0.0;  // total heat (sensible + latent) transferred by the heat exchanger [W]
    1940              : 
    1941      2460883 :         this->DefrostFraction = 0.0;
    1942      2460883 :         this->SensEffectiveness = 0.0;
    1943      2460883 :         this->LatEffectiveness = 0.0;
    1944      2460883 :         this->ElecUseRate = 0.0;
    1945      2460883 :         this->SupOutTemp = this->SupInTemp;
    1946      2460883 :         this->SecOutTemp = this->SecInTemp;
    1947      2460883 :         this->SupOutHumRat = this->SupInHumRat;
    1948      2460883 :         this->SecOutHumRat = this->SecInHumRat;
    1949      2460883 :         this->SupOutEnth = this->SupInEnth;
    1950      2460883 :         this->SecOutEnth = this->SecInEnth;
    1951      2460883 :         SupOutNode = this->SupOutletNode;
    1952      2460883 :         HXTempSetPoint = state.dataLoopNodes->Node(SupOutNode).TempSetPoint;
    1953              : 
    1954      2460883 :         bool EconomizerActiveFlag = present(EconomizerFlag) && bool(EconomizerFlag);    // local representing the economizer status when PRESENT
    1955      2460883 :         bool HighHumCtrlActiveFlag = present(HighHumCtrlFlag) && bool(HighHumCtrlFlag); // local representing high humidity control when PRESENT
    1956              : 
    1957              :         // Determine mass flow through heat exchanger and mass flow being bypassed (only flat plate bypasses flow)
    1958      2460883 :         if (((EconomizerActiveFlag || HighHumCtrlActiveFlag) && this->EconoLockOut) && this->ExchConfig == HXConfigurationType::Plate) {
    1959         2466 :             this->SupBypassMassFlow = this->SupInMassFlow;
    1960         2466 :             this->SupOutMassFlow = this->SupInMassFlow;
    1961         2466 :             this->SecBypassMassFlow = this->SecInMassFlow;
    1962         2466 :             this->SecOutMassFlow = this->SecInMassFlow;
    1963              :         } else { // No bypass mass flow
    1964      2458417 :             this->SupOutMassFlow = this->SupInMassFlow;
    1965      2458417 :             this->SecOutMassFlow = this->SecInMassFlow;
    1966      2458417 :             this->SupBypassMassFlow = 0.0;
    1967      2458417 :             this->SecBypassMassFlow = 0.0;
    1968              :         }
    1969              :         // Unit is scheduled OFF, so bypass heat exchange calcs
    1970      2460883 :         if (this->availSched->getCurrentVal() <= 0.0) {
    1971       568300 :             UnitOn = false;
    1972              :         }
    1973              :         //! Economizer is active, so bypass heat exchange calcs. This applies to both flat plate and rotary HX's
    1974      2460883 :         if ((EconomizerActiveFlag || HighHumCtrlActiveFlag) && this->EconoLockOut) {
    1975       231220 :             UnitOn = false;
    1976              :         }
    1977              :         // Determine if unit is ON or OFF based on air mass flow through the supply and secondary airstreams and operation flag
    1978      2460883 :         if (this->SupInMassFlow <= HVAC::SmallMassFlow) {
    1979       109159 :             UnitOn = false;
    1980              :         }
    1981      2460883 :         if (this->SecInMassFlow <= HVAC::SmallMassFlow) {
    1982       109159 :             UnitOn = false;
    1983              :         }
    1984      2460883 :         if (!HXUnitOn) {
    1985        36850 :             UnitOn = false;
    1986              :         }
    1987      2460883 :         if (this->NomSupAirVolFlow == 0.0) {
    1988            0 :             UnitOn = false;
    1989              :         }
    1990              : 
    1991      2460883 :         if (UnitOn) {
    1992      1567948 :             bool FrostControlFlag = false; // unit is in frost control mode when TRUE
    1993              :             // Unit is on.
    1994      1567948 :             if (present(HXPartLoadRatio) && fanOp == HVAC::FanOp::Cycling) {
    1995            0 :                 if (HXPartLoadRatio > 0) {
    1996            0 :                     AirSidePLR = HXPartLoadRatio;
    1997              :                 } else {
    1998            0 :                     AirSidePLR = 1.0;
    1999              :                 }
    2000              :             } else {
    2001      1567948 :                 AirSidePLR = 1.0;
    2002              :             }
    2003              : 
    2004      1567948 :             if (fanOp == HVAC::FanOp::Cycling) {
    2005            0 :                 this->SupInMassFlow /= AirSidePLR;
    2006            0 :                 this->SupOutMassFlow /= AirSidePLR;
    2007            0 :                 this->SecInMassFlow /= AirSidePLR;
    2008            0 :                 this->SecOutMassFlow /= AirSidePLR;
    2009            0 :                 this->SupBypassMassFlow /= AirSidePLR;
    2010            0 :                 this->SecBypassMassFlow /= AirSidePLR;
    2011              :             }
    2012              : 
    2013              :             // In the future, use actual node pressures in the following air density calls
    2014      1567948 :             RhoStd = Psychrometrics::PsyRhoAirFnPbTdbW(state, state.dataEnvrn->OutBaroPress, 20.0, 0.0);
    2015      1567948 :             HXSupAirVolFlowRate = this->SupOutMassFlow / RhoStd; // volume flow using standard density
    2016      1567948 :             HXSecAirVolFlowRate = this->SecOutMassFlow / RhoStd;
    2017              :             // Limit unbalanced volumetric flow ratio to 2:1
    2018      1567948 :             if (!state.dataGlobal->WarmupFlag && !FirstHVACIteration) {
    2019       113112 :                 if (HXSupAirVolFlowRate != 0.0 && HXSecAirVolFlowRate != 0.0) {
    2020       113112 :                     if (((HXSupAirVolFlowRate / HXSecAirVolFlowRate) > 2.0) || ((HXSecAirVolFlowRate / HXSupAirVolFlowRate) > 2.0)) {
    2021            0 :                         ++this->UnBalancedErrCount;
    2022            0 :                         if (this->UnBalancedErrCount <= 2) {
    2023            0 :                             ShowSevereError(state,
    2024            0 :                                             format("{}: \"{}\" unbalanced air volume flow ratio through the heat exchanger is greater than 2:1.",
    2025            0 :                                                    HVAC::hxTypeNames[(int)this->type],
    2026            0 :                                                    this->Name));
    2027            0 :                             ShowContinueErrorTimeStamp(
    2028            0 :                                 state, format("...HX Supply air to Exhaust air flow ratio = {:.5R}.", HXSupAirVolFlowRate / HXSecAirVolFlowRate));
    2029              :                         } else {
    2030            0 :                             ShowRecurringWarningErrorAtEnd(
    2031              :                                 state,
    2032            0 :                                 format("{} \"{}\":  Unbalanced air volume flow ratio exceeds 2:1 warning continues. HX flow ratio statistics follow.",
    2033            0 :                                        HVAC::hxTypeNames[(int)this->type],
    2034            0 :                                        this->Name),
    2035            0 :                                 this->UnBalancedErrIndex,
    2036            0 :                                 HXSupAirVolFlowRate / HXSecAirVolFlowRate,
    2037            0 :                                 HXSupAirVolFlowRate / HXSecAirVolFlowRate);
    2038              :                         }
    2039              :                     }
    2040              :                 }
    2041              :             }
    2042              :             // Calculate average volumetric flow rate of the two air streams
    2043      1567948 :             HXAvgAirVolFlowRate = (HXSecAirVolFlowRate + HXSupAirVolFlowRate) / 2.0;
    2044      1567948 :             HXAirVolFlowRatio = HXAvgAirVolFlowRate / this->NomSupAirVolFlow;
    2045              :             // Average air volume flow rate must be between 50% and 130% of nominal supply air volume flow
    2046      1567948 :             if (HXAirVolFlowRatio > 1.3 || HXAirVolFlowRatio < 0.5) {
    2047        98403 :                 if (!state.dataGlobal->WarmupFlag && !FirstHVACIteration) {
    2048        13926 :                     ++this->LowFlowErrCount;
    2049        13926 :                     if (this->LowFlowErrCount == 1) {
    2050           10 :                         ShowWarningError(state, format("{} \"{}\"", HVAC::hxTypeNames[(int)this->type], this->Name));
    2051           20 :                         ShowContinueError(state, "Average air volume flow rate is <50% or >130% of the nominal HX supply air volume flow rate.");
    2052           10 :                         ShowContinueErrorTimeStamp(state, format("Air volume flow rate ratio = {:.3R}.", HXAirVolFlowRatio));
    2053              :                     } else {
    2054       111328 :                         ShowRecurringWarningErrorAtEnd(
    2055              :                             state,
    2056        27832 :                             format(
    2057              :                                 "{} \"{}\":  Average air volume flow rate is <50% or >130% warning continues. Air flow rate ratio statistics follow.",
    2058        13916 :                                 HVAC::hxTypeNames[(int)this->type],
    2059        13916 :                                 this->Name),
    2060        13916 :                             this->LowFlowErrIndex,
    2061              :                             HXAirVolFlowRatio,
    2062              :                             HXAirVolFlowRatio);
    2063              :                     }
    2064              :                 }
    2065              :             }
    2066              : 
    2067              :             // Determine heat exchanger effectiveness using avg air volume flow rate based on actual inlet air density
    2068              :             // Linearly interpolate and extrapolate (within limits) from effectiveness input values
    2069      1567948 :             RhoSup = Psychrometrics::PsyRhoAirFnPbTdbW(state, state.dataEnvrn->OutBaroPress, this->SupInTemp, this->SupInHumRat);
    2070      1567948 :             RhoSec = Psychrometrics::PsyRhoAirFnPbTdbW(state, state.dataEnvrn->OutBaroPress, this->SecInTemp, this->SecInHumRat);
    2071      1567948 :             HXSupAirVolFlowRate = this->SupOutMassFlow / RhoSup;
    2072      1567948 :             HXSecAirVolFlowRate = this->SecOutMassFlow / RhoSec;
    2073      1567948 :             HXAvgAirVolFlowRate = (HXSecAirVolFlowRate + HXSupAirVolFlowRate) / 2.0;
    2074      1567948 :             HXAirVolFlowRatio = HXAvgAirVolFlowRate / this->NomSupAirVolFlow;
    2075              : 
    2076      1567948 :             if (this->SupInTemp < this->SecInTemp) {
    2077              :                 // Use heating effectiveness values
    2078       716508 :                 this->SensEffectiveness = this->HeatEffectSensible100;
    2079       716508 :                 if (this->HeatEffectSensibleCurveIndex > 0) {
    2080       174300 :                     this->SensEffectiveness *= Curve::CurveValue(state, this->HeatEffectSensibleCurveIndex, HXAirVolFlowRatio);
    2081              :                 }
    2082       716508 :                 this->LatEffectiveness = this->HeatEffectLatent100;
    2083       716508 :                 if (this->HeatEffectLatentCurveIndex > 0) {
    2084       170748 :                     this->LatEffectiveness *= Curve::CurveValue(state, this->HeatEffectLatentCurveIndex, HXAirVolFlowRatio);
    2085              :                 }
    2086              :             } else {
    2087              :                 // Use cooling effectiveness values
    2088       851440 :                 this->SensEffectiveness = this->CoolEffectSensible100;
    2089       851440 :                 if (this->CoolEffectSensibleCurveIndex > 0) {
    2090       421917 :                     this->SensEffectiveness *= Curve::CurveValue(state, this->CoolEffectSensibleCurveIndex, HXAirVolFlowRatio);
    2091              :                 }
    2092       851440 :                 this->LatEffectiveness = this->CoolEffectLatent100;
    2093       851440 :                 if (this->CoolEffectLatentCurveIndex > 0) {
    2094       402667 :                     this->LatEffectiveness *= Curve::CurveValue(state, this->CoolEffectLatentCurveIndex, HXAirVolFlowRatio);
    2095              :                 }
    2096              :             }
    2097              : 
    2098              :             //     Keep effectiveness between 0 and 1.0 ??
    2099              :             //     HXOpSensEffect = MAX(MIN(HXOpSensEffect,1.0),0.0)
    2100              :             //     HXOpLatEffect =  MAX(MIN(HXOpLatEffect,1.0),0.0)
    2101      1567948 :             if (this->SensEffectiveness < 0.0) {
    2102              :                 //   The model should at least guard against negative numbers
    2103            0 :                 this->SensEffectiveness = 0.0;
    2104            0 :                 if (!this->SensEffectivenessFlag) {
    2105            0 :                     ShowWarningError(
    2106              :                         state,
    2107            0 :                         format(
    2108              :                             "HeatExchanger:AirToAir:SensibleAndLatent =\"{}\" sensible effectiveness is less than zero. Check the following inputs.",
    2109            0 :                             this->Name));
    2110            0 :                     if (this->SupInTemp < this->SecInTemp) {
    2111            0 :                         ShowContinueError(state, format("...Sensible Effectiveness at 100% Heating Air Flow = {:.2R}", this->HeatEffectSensible100));
    2112            0 :                         ShowContinueError(state, "...Sensible effectiveness reset to zero and the simulation continues.");
    2113              :                     } else {
    2114            0 :                         ShowContinueError(state, format("...Sensible Effectiveness at 100% Cooling Air Flow = {:.2R}", this->CoolEffectSensible100));
    2115            0 :                         ShowContinueError(state, "...Sensible effectiveness reset to zero and the simulation continues.");
    2116              :                     }
    2117            0 :                     ShowContinueError(state, format("...Heat Exchanger Air Volume Flow Ratio = {:.2R}", HXAirVolFlowRatio));
    2118            0 :                     this->SensEffectivenessFlag = true;
    2119              :                 }
    2120              :             }
    2121      1567948 :             if (this->LatEffectiveness < 0.0) {
    2122              :                 // The model should at least guard against negative numbers
    2123            0 :                 this->LatEffectiveness = 0.0;
    2124            0 :                 if (!this->LatEffectivenessFlag) {
    2125            0 :                     ShowWarningError(
    2126              :                         state,
    2127            0 :                         format("HeatExchanger:AirToAir:SensibleAndLatent =\"{}\" latent effectiveness is less than zero. Check the following inputs.",
    2128            0 :                                this->Name));
    2129            0 :                     if (this->SupInTemp < this->SecInTemp) {
    2130            0 :                         ShowContinueError(state, format("...Latent Effectiveness at 100% Heating Air Flow = {:.2R}", this->HeatEffectLatent100));
    2131            0 :                         ShowContinueError(state, "...Latent effectiveness reset to zero and the simulation continues.");
    2132              :                     } else {
    2133            0 :                         ShowContinueError(state, format("...Latent Effectiveness at 100% Cooling Air Flow = {:.2R}", this->CoolEffectLatent100));
    2134            0 :                         ShowContinueError(state, "...Latent effectiveness reset to zero and the simulation continues.");
    2135              :                     }
    2136            0 :                     ShowContinueError(state, format("...Heat Exchanger Air Volume Flow Ratio = {:.2R}", HXAirVolFlowRatio));
    2137            0 :                     this->LatEffectivenessFlag = true;
    2138              :                 }
    2139              :             }
    2140              :             // Use the effectiveness to calculate the air conditions exiting the heat exchanger (all air flow through the HX)
    2141              :             // Include EATR and OACF in the following calculations at some point
    2142              : 
    2143      1567948 :             CSup = this->SupOutMassFlow * Psychrometrics::PsyCpAirFnW(this->SupInHumRat);
    2144      1567948 :             CSec = this->SecOutMassFlow * Psychrometrics::PsyCpAirFnW(this->SecInHumRat);
    2145      1567948 :             CMin = min(CSup, CSec);
    2146              : 
    2147      1567948 :             this->SupOutTemp = this->SupInTemp + this->SensEffectiveness * CMin / CSup * (this->SecInTemp - this->SupInTemp);
    2148      1567948 :             this->SupOutHumRat = this->SupInHumRat + this->LatEffectiveness * CMin / CSup * (this->SecInHumRat - this->SupInHumRat);
    2149      1567948 :             this->SupOutEnth = Psychrometrics::PsyHFnTdbW(this->SupOutTemp, this->SupOutHumRat);
    2150              : 
    2151              :             //   Check for saturation in supply outlet and reset temp, then humidity ratio at constant enthalpy
    2152      1567948 :             if (Psychrometrics::PsyTsatFnHPb(state, this->SupOutEnth, state.dataEnvrn->OutBaroPress) > this->SupOutTemp) {
    2153       115739 :                 this->SupOutTemp = Psychrometrics::PsyTsatFnHPb(state, this->SupOutEnth, state.dataEnvrn->OutBaroPress);
    2154       115739 :                 this->SupOutHumRat = Psychrometrics::PsyWFnTdbH(state, this->SupOutTemp, this->SupOutEnth);
    2155              :             }
    2156      1567948 :             QSensTrans = CSup * (this->SupInTemp - this->SupOutTemp);
    2157      1567948 :             this->SecOutTemp = this->SecInTemp + QSensTrans / CSec;
    2158      1567948 :             QTotTrans = this->SupOutMassFlow * (this->SupInEnth - this->SupOutEnth);
    2159      1567948 :             this->SecOutEnth = this->SecInEnth + QTotTrans / this->SecOutMassFlow;
    2160      1567948 :             this->SecOutHumRat = Psychrometrics::PsyWFnTdbH(state, this->SecOutTemp, this->SecOutEnth);
    2161              :             //   Control the supply air outlet temperature to a setpoint for Heating Mode only
    2162              :             //   (ControlFraction = 0 HX fully bypassed, ControlFraction = 1 air passed entirely through HX)
    2163              :             //   (supply air stream bypass mass flow rate proportional to ControlFraction except when frost control is active)
    2164      1567948 :             if (this->ControlToTemperatureSetPoint) {
    2165      1291504 :                 if ((this->SupInTemp - this->SupOutTemp) != 0.0) {
    2166      1252090 :                     if ((this->SupOutTemp > HXTempSetPoint && this->SupInTemp < HXTempSetPoint) ||
    2167      1085327 :                         (this->SupInTemp > HXTempSetPoint && this->SupOutTemp < HXTempSetPoint)) {
    2168       314256 :                         ControlFraction = max(0.0, min(1.0, std::abs((this->SupInTemp - HXTempSetPoint) / (this->SupInTemp - this->SupOutTemp))));
    2169       937834 :                     } else if ((this->SupInTemp < this->SupOutTemp && this->SupOutTemp < HXTempSetPoint) ||
    2170       599027 :                                (this->SupInTemp > this->SupOutTemp && this->SupOutTemp > HXTempSetPoint)) {
    2171       869806 :                         ControlFraction = 1.0;
    2172              :                     } else {
    2173        68028 :                         ControlFraction = 0.0;
    2174              :                     }
    2175              :                 } else {
    2176              :                     //     ELSE fully bypass HX to maintain supply outlet temp as high as possible
    2177        39414 :                     ControlFraction = 0.0;
    2178              :                 }
    2179      1291504 :                 if (this->ExchConfig == HXConfigurationType::Rotary) {
    2180              :                     //       Rotary HX's never get bypassed, rotational speed is modulated
    2181       706781 :                     this->SensEffectiveness *= ControlFraction;
    2182       706781 :                     this->LatEffectiveness *= ControlFraction;
    2183              :                 } else { // HX is a plate heat exchanger, bypass air to control SA temperature
    2184       584723 :                     Error = 1.0;
    2185       584723 :                     Iter = 0.0;
    2186       584723 :                     MassFlowSupIn = this->SupInMassFlow;
    2187       584723 :                     MassFlowSupOut = this->SupOutMassFlow;
    2188       584723 :                     MassFlowSupBypass = this->SupBypassMassFlow;
    2189       584723 :                     MassFlowSecIn = this->SecInMassFlow;
    2190       584723 :                     TempSupIn = this->SupInTemp;
    2191       584723 :                     TempSupOut = this->SupOutTemp;
    2192       584723 :                     HumRatSupIn = this->SupInHumRat;
    2193       584723 :                     TempSecIn = this->SecInTemp;
    2194       938423 :                     while ((std::abs(Error) > ErrorTol && Iter < 10 && ControlFraction < 1.0) || Iter == 1) {
    2195       410623 :                         MassFlowSupOut = MassFlowSupIn * ControlFraction;
    2196       410623 :                         MassFlowSupBypass = MassFlowSupIn * (1.0 - ControlFraction);
    2197       410623 :                         HXSupAirVolFlowRate = MassFlowSupOut / RhoSup;
    2198       410623 :                         HXAvgAirVolFlowRate = (HXSecAirVolFlowRate + HXSupAirVolFlowRate) / 2.0;
    2199       410623 :                         HXAirVolFlowRatio = HXAvgAirVolFlowRate / this->NomSupAirVolFlow;
    2200       410623 :                         CSup = MassFlowSupOut * Psychrometrics::PsyCpAirFnW(HumRatSupIn);
    2201       410623 :                         CMin = min(CSup, CSec);
    2202       410623 :                         if (TempSupIn < TempSecIn) {
    2203              :                             //          Use heating effectiveness values
    2204        67838 :                             this->SensEffectiveness = this->HeatEffectSensible100;
    2205        67838 :                             if (this->HeatEffectSensibleCurveIndex > 0) {
    2206        65435 :                                 this->SensEffectiveness *= Curve::CurveValue(state, this->HeatEffectSensibleCurveIndex, HXAirVolFlowRatio);
    2207              :                             }
    2208        67838 :                             this->LatEffectiveness = this->HeatEffectLatent100;
    2209        67838 :                             if (this->HeatEffectLatentCurveIndex > 0) {
    2210        65435 :                                 this->LatEffectiveness *= Curve::CurveValue(state, this->HeatEffectLatentCurveIndex, HXAirVolFlowRatio);
    2211              :                             }
    2212              :                         } else {
    2213              :                             //          Use cooling effectiveness values
    2214       342785 :                             this->SensEffectiveness = this->CoolEffectSensible100;
    2215       342785 :                             if (this->CoolEffectSensibleCurveIndex > 0) {
    2216        34232 :                                 this->SensEffectiveness *= Curve::CurveValue(state, this->CoolEffectSensibleCurveIndex, HXAirVolFlowRatio);
    2217              :                             }
    2218       342785 :                             this->LatEffectiveness = this->CoolEffectLatent100;
    2219       342785 :                             if (this->CoolEffectLatentCurveIndex > 0) {
    2220        34232 :                                 this->LatEffectiveness *= Curve::CurveValue(state, this->CoolEffectLatentCurveIndex, HXAirVolFlowRatio);
    2221              :                             }
    2222              :                         }
    2223              : 
    2224       410623 :                         if (this->SensEffectiveness < 0.0) {
    2225              :                             //   The model should at least guard against negative numbers
    2226            0 :                             this->SensEffectiveness = 0.0;
    2227            0 :                             if (!this->SensEffectivenessFlag) {
    2228            0 :                                 ShowWarningError(state,
    2229            0 :                                                  format("HeatExchanger:AirToAir:SensibleAndLatent =\"{}\" sensible effectiveness is less than zero. "
    2230              :                                                         "Check the following inputs.",
    2231            0 :                                                         this->Name));
    2232            0 :                                 if (this->SupInTemp < this->SecInTemp) {
    2233            0 :                                     ShowContinueError(
    2234            0 :                                         state, format("...Sensible Effectiveness at 100% Heating Air Flow = {:.2R}", this->HeatEffectSensible100));
    2235            0 :                                     ShowContinueError(state, "...Sensible effectiveness reset to zero and the simulation continues.");
    2236              :                                 } else {
    2237            0 :                                     ShowContinueError(
    2238            0 :                                         state, format("...Sensible Effectiveness at 100% Cooling Air Flow = {:.2R}", this->CoolEffectSensible100));
    2239            0 :                                     ShowContinueError(state, "...Sensible effectiveness reset to zero and the simulation continues.");
    2240              :                                 }
    2241            0 :                                 ShowContinueError(state, format("...Heat Exchanger Air Volume Flow Ratio = {:.2R}", HXAirVolFlowRatio));
    2242            0 :                                 this->SensEffectivenessFlag = true;
    2243              :                             }
    2244              :                         }
    2245       410623 :                         if (this->LatEffectiveness < 0.0) {
    2246              :                             // The model should at least guard against negative numbers
    2247            0 :                             this->LatEffectiveness = 0.0;
    2248            0 :                             if (!this->LatEffectivenessFlag) {
    2249            0 :                                 ShowWarningError(state,
    2250            0 :                                                  format("HeatExchanger:AirToAir:SensibleAndLatent =\"{}\" latent effectiveness is less than zero. "
    2251              :                                                         "Check the following inputs.",
    2252            0 :                                                         this->Name));
    2253            0 :                                 if (this->SupInTemp < this->SecInTemp) {
    2254            0 :                                     ShowContinueError(state,
    2255            0 :                                                       format("...Latent Effectiveness at 100% Heating Air Flow = {:.2R}", this->HeatEffectLatent100));
    2256            0 :                                     ShowContinueError(state, "...Latent effectiveness reset to zero and the simulation continues.");
    2257              :                                 } else {
    2258            0 :                                     ShowContinueError(state,
    2259            0 :                                                       format("...Latent Effectiveness at 100% Cooling Air Flow = {:.2R}", this->CoolEffectLatent100));
    2260            0 :                                     ShowContinueError(state, "...Latent effectiveness reset to zero and the simulation continues.");
    2261              :                                 }
    2262            0 :                                 ShowContinueError(state, format("...Heat Exchanger Air Volume Flow Ratio = {:.2R}", HXAirVolFlowRatio));
    2263            0 :                                 this->LatEffectivenessFlag = true;
    2264              :                             }
    2265              :                         }
    2266              : 
    2267       410623 :                         if (CSup == 0.0) {
    2268              :                             //          IF CSup = 0, then supply air mass flow rate = 0 and HX is fully bypassed. Fix divide by 0 error below DO loop.
    2269        56923 :                             CSup = 1.0;
    2270        56923 :                             CMin = 0.0;
    2271        56923 :                             break;
    2272              :                         }
    2273       353700 :                         TempSupOut = (MassFlowSupOut * (TempSupIn + this->SensEffectiveness * CMin / CSup * (TempSecIn - TempSupIn)) +
    2274       353700 :                                       MassFlowSupBypass * TempSupIn) /
    2275              :                                      MassFlowSupIn;
    2276       353700 :                         Error = (TempSupOut - HXTempSetPoint);
    2277              :                         //         IF supply inlet temp = supply outlet temp, fully bypass HX - ELSE control to SP
    2278       353700 :                         if (TempSupIn != TempSupOut) {
    2279       353700 :                             ControlFraction = max(0.0, min(1.0, std::abs(ControlFraction * (TempSupIn - HXTempSetPoint) / (TempSupIn - TempSupOut))));
    2280            0 :                         } else if (std::abs(TempSupOut - HXTempSetPoint) < ErrorTol) {
    2281              :                             //           IF TempSupIn = TempSupOut then TempSecIn = TempSupIn (ControlFraction = ?)
    2282              :                             //           Do nothing, variables in ELSE below have already been calculated
    2283            0 :                             break;
    2284              :                         } else {
    2285              :                             //           or HX is fully bypassed (ControlFraction = 0) which actually should be caught in IF(CSup .EQ. 0.0)THEN above.
    2286            0 :                             ControlFraction = 0.0;
    2287            0 :                             MassFlowSupOut = MassFlowSupIn * ControlFraction;
    2288            0 :                             MassFlowSupBypass = MassFlowSupIn * (1.0 - ControlFraction);
    2289            0 :                             CSup = 1.0;
    2290            0 :                             CMin = 0.0;
    2291            0 :                             break;
    2292              :                         }
    2293       353700 :                         ++Iter;
    2294              :                     }
    2295              : 
    2296       584723 :                     this->SupInMassFlow = MassFlowSupIn;
    2297       584723 :                     this->SupOutMassFlow = MassFlowSupOut;
    2298       584723 :                     this->SupBypassMassFlow = MassFlowSupBypass;
    2299       584723 :                     this->SecInMassFlow = MassFlowSecIn;
    2300       584723 :                     this->SupInTemp = TempSupIn;
    2301       584723 :                     this->SupOutTemp = TempSupOut;
    2302       584723 :                     this->SupInHumRat = HumRatSupIn;
    2303       584723 :                     this->SecInTemp = TempSecIn;
    2304              : 
    2305              :                 } // ENDIF for "IF (thisExch%ExchConfig == 'ROTARY') THEN"
    2306      1291504 :                 this->SupOutTemp = this->SupInTemp + this->SensEffectiveness * CMin / CSup * (this->SecInTemp - this->SupInTemp);
    2307      1291504 :                 this->SupOutHumRat = this->SupInHumRat + this->LatEffectiveness * CMin / CSup * (this->SecInHumRat - this->SupInHumRat);
    2308      1291504 :                 this->SupOutEnth = Psychrometrics::PsyHFnTdbW(this->SupOutTemp, this->SupOutHumRat);
    2309              : 
    2310              :                 //     Check for saturation in supply outlet and reset temp, then humidity ratio at constant enthalpy
    2311      1291504 :                 if (Psychrometrics::PsyTsatFnHPb(state, this->SupOutEnth, state.dataEnvrn->OutBaroPress) > this->SupOutTemp) {
    2312       167343 :                     this->SupOutTemp = Psychrometrics::PsyTsatFnHPb(state, this->SupOutEnth, state.dataEnvrn->OutBaroPress);
    2313       167343 :                     this->SupOutHumRat = Psychrometrics::PsyWFnTdbH(state, this->SupOutTemp, this->SupOutEnth);
    2314              :                 }
    2315              : 
    2316      1291504 :                 QSensTrans = CSup * (this->SupInTemp - this->SupOutTemp);
    2317      1291504 :                 this->SecOutTemp = this->SecInTemp + QSensTrans / CSec;
    2318      1291504 :                 QTotTrans = this->SupOutMassFlow * (this->SupInEnth - this->SupOutEnth);
    2319      1291504 :                 this->SecOutEnth = this->SecInEnth + QTotTrans / this->SecOutMassFlow;
    2320      1291504 :                 this->SecOutHumRat = Psychrometrics::PsyWFnTdbH(state, this->SecOutTemp, this->SecOutEnth);
    2321              : 
    2322              :             } // ENDIF for "IF(thisExch%ControlToTemperatureSetPoint .AND... THEN, ELSE"
    2323              : 
    2324      1567948 :             if (fanOp == HVAC::FanOp::Cycling) {
    2325            0 :                 this->SupInMassFlow *= AirSidePLR;
    2326            0 :                 this->SupOutMassFlow *= AirSidePLR;
    2327            0 :                 this->SecInMassFlow *= AirSidePLR;
    2328            0 :                 this->SecOutMassFlow *= AirSidePLR;
    2329            0 :                 this->SupBypassMassFlow *= AirSidePLR;
    2330            0 :                 this->SecBypassMassFlow *= AirSidePLR;
    2331      1567948 :             } else if (fanOp == HVAC::FanOp::Continuous) {
    2332      1567948 :                 this->SupOutTemp = this->SupOutTemp * AirSidePLR + this->SupInTemp * (1.0 - AirSidePLR);
    2333      1567948 :                 this->SupOutHumRat = this->SupOutHumRat * AirSidePLR + this->SupInHumRat * (1.0 - AirSidePLR);
    2334      1567948 :                 this->SupOutEnth = this->SupOutEnth * AirSidePLR + this->SupOutEnth * (1.0 - AirSidePLR);
    2335      1567948 :                 this->SecOutTemp = this->SecOutTemp * AirSidePLR + this->SecInTemp * (1.0 - AirSidePLR);
    2336      1567948 :                 this->SecOutHumRat = this->SecOutHumRat * AirSidePLR + this->SecInHumRat * (1.0 - AirSidePLR);
    2337      1567948 :                 this->SecOutEnth = this->SecOutEnth * AirSidePLR + this->SecOutEnth * (1.0 - AirSidePLR);
    2338              :             }
    2339              : 
    2340      1567948 :             if ((this->FrostControlType == FrostControlOption::MinimumExhaustTemperature && this->SecOutTemp < this->ThresholdTemperature) ||
    2341      1485532 :                 (this->FrostControlType == FrostControlOption::ExhaustAirRecirculation && this->SupInTemp <= this->ThresholdTemperature) ||
    2342      1485532 :                 (this->FrostControlType == FrostControlOption::ExhaustOnly && this->SupInTemp <= this->ThresholdTemperature)) {
    2343        82416 :                 this->FrostControl(state);
    2344        82416 :                 FrostControlFlag = true;
    2345              :             }
    2346              : 
    2347              :             // check for saturation in secondary outlet
    2348      1567948 :             TempSecOutSat = Psychrometrics::PsyTsatFnHPb(state, this->SecOutEnth, state.dataEnvrn->OutBaroPress);
    2349      1567948 :             if (TempSecOutSat > this->SecOutTemp) {
    2350        80496 :                 this->SecOutTemp = TempSecOutSat;
    2351        80496 :                 this->SecOutHumRat = Psychrometrics::PsyWFnTdbH(state, this->SecOutTemp, this->SecOutEnth);
    2352              :             }
    2353              : 
    2354              :             // calculate outlet conditions by mixing bypass air stream with air that went through the
    2355              :             // heat exchanger core.  Perform this mixing only when no frost control is used or
    2356              :             // heat exchanger is not in frost control mode.  Mixing similar to this is performed
    2357              :             // in the frost control subroutine when in frost control mode.
    2358      1567948 :             if (!FrostControlFlag) {
    2359      1485532 :                 this->SupOutEnth = (this->SupOutMassFlow * this->SupOutEnth + this->SupBypassMassFlow * this->SupInEnth) / this->SupInMassFlow;
    2360      1485532 :                 this->SupOutHumRat = (this->SupOutMassFlow * this->SupOutHumRat + this->SupBypassMassFlow * this->SupInHumRat) / this->SupInMassFlow;
    2361      1485532 :                 this->SupOutTemp = Psychrometrics::PsyTdbFnHW(this->SupOutEnth, this->SupOutHumRat);
    2362      1485532 :                 this->SupOutMassFlow = this->SupInMassFlow;
    2363      1485532 :                 this->SecOutEnth = (this->SecOutMassFlow * this->SecOutEnth + this->SecBypassMassFlow * this->SecInEnth) / this->SecInMassFlow;
    2364      1485532 :                 this->SecOutHumRat = (this->SecOutMassFlow * this->SecOutHumRat + this->SecBypassMassFlow * this->SecInHumRat) / this->SecInMassFlow;
    2365      1485532 :                 this->SecOutTemp = Psychrometrics::PsyTdbFnHW(this->SecOutEnth, this->SecOutHumRat);
    2366      1485532 :                 this->SecOutMassFlow = this->SecInMassFlow;
    2367              :             }
    2368              : 
    2369      1567948 :             this->ElecUseRate = this->NomElecPower;
    2370              : 
    2371              :         } // ENDIF for "IF (UnitOn) THEN"
    2372              : 
    2373              :         // Calculate heat transfer from the unit using the final supply inlet and supply outlet air conditions
    2374      2460883 :         CSup = this->SupOutMassFlow * Psychrometrics::PsyCpAirFnW(this->SupInHumRat);
    2375      2460883 :         SensHeatRecRate = CSup * (this->SupOutTemp - this->SupInTemp);
    2376      2460883 :         TotHeatRecRate = this->SupOutMassFlow * (this->SupOutEnth - this->SupInEnth);
    2377      2460883 :         LatHeatRecRate = TotHeatRecRate - SensHeatRecRate;
    2378              : 
    2379              :         // Set report variables based on sign of recovery rate
    2380      2460883 :         if (SensHeatRecRate > 0.0) {
    2381       675321 :             this->SensHeatingRate = SensHeatRecRate;
    2382       675321 :             this->SensCoolingRate = 0.0;
    2383              :         } else {
    2384      1785562 :             this->SensHeatingRate = 0.0;
    2385      1785562 :             this->SensCoolingRate = std::abs(SensHeatRecRate);
    2386              :         }
    2387      2460883 :         if (LatHeatRecRate > 0.0) {
    2388       727950 :             this->LatHeatingRate = LatHeatRecRate;
    2389       727950 :             this->LatCoolingRate = 0.0;
    2390              :         } else {
    2391      1732933 :             this->LatHeatingRate = 0.0;
    2392      1732933 :             this->LatCoolingRate = std::abs(LatHeatRecRate);
    2393              :         }
    2394      2460883 :         if (TotHeatRecRate > 0.0) {
    2395       733059 :             this->TotHeatingRate = TotHeatRecRate;
    2396       733059 :             this->TotCoolingRate = 0.0;
    2397              :         } else {
    2398      1727824 :             this->TotHeatingRate = 0.0;
    2399      1727824 :             this->TotCoolingRate = std::abs(TotHeatRecRate);
    2400              :         }
    2401      2460883 :     }
    2402              : 
    2403       672529 :     void HeatExchCond::CalcDesiccantBalancedHeatExch(
    2404              :         EnergyPlusData &state,
    2405              :         bool const HXUnitOn,                           // flag to simulate heat exchanger heat recovery
    2406              :         bool const FirstHVACIteration,                 // First HVAC iteration flag
    2407              :         HVAC::FanOp const fanOp,                       // Supply air fan operating mode (1=cycling, 2=constant)
    2408              :         Real64 const PartLoadRatio,                    // Part load ratio requested of DX compressor
    2409              :         int const CompanionCoilIndex,                  // index of companion cooling coil
    2410              :         int const CompanionCoilType,                   // type of cooling coil
    2411              :         bool const RegenInletIsOANode,                 // Flag to determine if regen side inlet is OANode, if so this air stream cycles
    2412              :         ObjexxFCL::Optional_bool_const EconomizerFlag, // economizer flag pass by air loop or OA sys
    2413              :         ObjexxFCL::Optional_bool_const HighHumCtrlFlag // high humidity control flag passed by airloop or OA sys
    2414              :     )
    2415              :     {
    2416              : 
    2417              :         // SUBROUTINE INFORMATION:
    2418              :         //       AUTHOR         Mangesh Basarkar, FSEC
    2419              :         //       DATE WRITTEN   January 2007
    2420              :         //       MODIFIED       R. Raustad - FSEC, Feb 2009 - added economizer flags
    2421              :         //                      Both the economizer and high humidity control flags can disable the HX
    2422              :         //       RE-ENGINEERED  na
    2423              : 
    2424              :         // PURPOSE OF THIS SUBROUTINE:
    2425              :         //  Calculate the outlet conditions for a balanced air-to-air desiccant heat exchanger
    2426              :         //  given the inlet conditions and face velocity. Performance map is provided by user.
    2427              : 
    2428              :         // METHODOLOGY EMPLOYED:
    2429              :         //  This is an empirical heat exchanger model. The model uses heat exchanger performance data to
    2430              :         //  calculate the air temperature and humidity ratio of the leaving supply and secondary air streams.
    2431              :         //  Humidity control can enable/disable heat recovery through the use of the HXUnitOn Subroutine argument.
    2432              : 
    2433              :         // Using/Aliasing
    2434              :         using DataLoopNode::SensedNodeFlagValue;
    2435              : 
    2436              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    2437              :         bool UnitOn;                   // unit on flag
    2438              :         Real64 RhoStd;                 // standard air density at actual pressure, 20C dry-bulb temp and 0.0 absolute humidity [kg/m3]
    2439              :         Real64 CSup;                   // supply air heat capacity rate [W/K]
    2440              :         Real64 CSec;                   // secondary air heat capacity rate [W/K]
    2441              :         Real64 TempSecOutSat;          // secondary air outlet temperature at saturation (at EnthsSecOut) [C]
    2442              :         Real64 SensHeatRecRate;        // sensible heat recovery rate to supply air (heating +, cooling -)
    2443              :         Real64 TotHeatRecRate;         // total heat recovery rate to supply air (heating +, cooling -)
    2444              :         Real64 ProcessSensHeatRecRate; // process sensible heat recovery rate (heating +, cooling -)
    2445              :         Real64 ProcessTotHeatRecRate;  // process total heat recovery rate (heating +, cooling -)
    2446              :         Real64 ProcessLatHeatRecRate;  // process latent heat recovery rate (heating [humidify] +, cooling [dehumidify] -)
    2447              : 
    2448              :         Real64 BalFaceVelActual;        // operating face velocity [m/s]
    2449       672529 :         Real64 FullLoadSupOutTemp(0);   // empirical model supply outlet temperature [C]
    2450       672529 :         Real64 FullLoadSupOutHumRat(0); // empirical model supply outlet humidity ratio [kg/kg]
    2451              :         Real64 FullLoadDeltaT;          // empirical model heat exchanger delta temperature [C]
    2452              :         Real64 FullLoadDeltaW;          // empirical model heat exchanger delta humidity ratio [kg/kg]
    2453              :         Real64 T_RegenInTemp;           // empirical model supply (regen) inlet temperature for temperature equation [C]
    2454              :         Real64 T_RegenInHumRat;         // empirical model supply (regen) inlet humidity ratio for temperature equation [kg/kg]
    2455              :         Real64 T_ProcInTemp;            // empirical model secondary (process) inlet temperature for temperature equation [C]
    2456              :         Real64 T_ProcInHumRat;          // empirical model secondary (process) inlet humidity ratio for temperature equation [kg/kg]
    2457              :         Real64 T_FaceVel;               // empirical model face velocity for temperature equation [m/s]
    2458              :         Real64 H_RegenInTemp;           // empirical model supply (regen) inlet temperature for humidity ratio equation [C]
    2459              :         Real64 H_RegenInHumRat;         // empirical model supply (regen) inlet humidity ratio for humidity ratio equation [kg/kg]
    2460              :         Real64 H_ProcInTemp;            // empirical model secondary (process) inlet temperature for humidity ratio equation [C]
    2461              :         Real64 H_ProcInHumRat;          // empirical model secondary (process) inlet humidity ratio for humidity ratio equation [kg/kg]
    2462              :         Real64 H_FaceVel;               // empirical model face velocity for humidity ratio equation [m/s]
    2463              :         Real64 MaxHumRatNeeded;         // maximum humidity ratio setpoint for balanced desiccant HX [kg/kg]
    2464              :         Real64 MinHumRatNeeded;         // minimum humidity ratio setpoint for balanced desiccant HX [kg/kg]
    2465              :         Real64 HXPartLoadRatio;         // local heat exchanger part-load ratio
    2466              :         Real64 TestSaturationEnthalpy;  // enthalpy used to test for regeneration outlet condition over saturation curve (J/kg)
    2467              :         Real64 AverageMassFlowRate;     // average of supply (regen) and secondary (process) mass flow rates [kg/s]
    2468              :         bool EconomizerActiveFlag;      // local representing the economizer status when PRESENT
    2469              :         bool HighHumCtrlActiveFlag;     // local representing high humidity control when PRESENT
    2470              : 
    2471              :         // Initialize local variables
    2472       672529 :         UnitOn = true;
    2473       672529 :         SensHeatRecRate = 0.0;
    2474       672529 :         TotHeatRecRate = 0.0;
    2475       672529 :         HXPartLoadRatio = PartLoadRatio;
    2476       672529 :         this->DefrostFraction = 0.0;
    2477       672529 :         this->ElecUseRate = 0.0;
    2478       672529 :         this->SupOutTemp = this->SupInTemp;
    2479       672529 :         this->SecOutTemp = this->SecInTemp;
    2480       672529 :         this->SupOutHumRat = this->SupInHumRat;
    2481       672529 :         this->SecOutHumRat = this->SecInHumRat;
    2482       672529 :         this->SupOutEnth = this->SupInEnth;
    2483       672529 :         this->SecOutEnth = this->SecInEnth;
    2484       672529 :         this->SupOutMassFlow = this->SupInMassFlow;
    2485       672529 :         this->SecOutMassFlow = this->SecInMassFlow;
    2486       672529 :         AverageMassFlowRate = (this->SupOutMassFlow + this->SecOutMassFlow) / 2.0;
    2487              : 
    2488       672529 :         if (present(EconomizerFlag)) {
    2489       479449 :             EconomizerActiveFlag = EconomizerFlag;
    2490              :         } else {
    2491       193080 :             EconomizerActiveFlag = false;
    2492              :         }
    2493              : 
    2494       672529 :         if (present(HighHumCtrlFlag)) {
    2495            0 :             HighHumCtrlActiveFlag = HighHumCtrlFlag;
    2496              :         } else {
    2497       672529 :             HighHumCtrlActiveFlag = false;
    2498              :         }
    2499              : 
    2500              :         // Unit is scheduled OFF, so bypass heat exchange calcs
    2501       672529 :         if (this->availSched->getCurrentVal() <= 0.0) {
    2502       103124 :             UnitOn = false;
    2503              :         }
    2504              :         // Determine if unit is ON or OFF based on air mass flow through the supply and secondary airstreams and operation flag
    2505       672529 :         if (this->SupInMassFlow <= HVAC::SmallMassFlow) {
    2506        98365 :             UnitOn = false;
    2507              :         }
    2508       672529 :         if (this->SecInMassFlow <= HVAC::SmallMassFlow) {
    2509        84712 :             UnitOn = false;
    2510              :         }
    2511       672529 :         if (HXPartLoadRatio == 0.0) {
    2512       461218 :             UnitOn = false;
    2513              :         }
    2514       672529 :         if (!HXUnitOn) {
    2515       573478 :             UnitOn = false;
    2516              :         }
    2517       672529 :         if ((EconomizerActiveFlag || HighHumCtrlActiveFlag) && this->EconoLockOut) {
    2518            0 :             UnitOn = false;
    2519              :         }
    2520              : 
    2521       672529 :         if (UnitOn) {
    2522        97303 :             constexpr std::string_view ThisSubTSat = "CalcDesiccantBalancedHeatExch:   TSat";
    2523        97303 :             constexpr std::string_view ThisSubSecOutHumRat = "CalcDesiccantBalancedHeatExch:   SecOutHumRat";
    2524        97303 :             constexpr std::string_view ThisSubTestSatSec = "CalcDesiccantBalancedHeatExch:   TestSatSec";
    2525              :             Real64 local_SupInMassFlow; // Supply side HX mass flow rate
    2526              :             Real64 local_SecInMassFlow; // Secondary side HX mass flow rate
    2527              : 
    2528              :             //   Use local variables to perform checks
    2529        97303 :             local_SecInMassFlow = this->SecInMassFlow;
    2530        97303 :             local_SupInMassFlow = this->SupInMassFlow;
    2531              : 
    2532              :             // In constant fan mode, process air mass flow rate is full flow and supply (regen) air cycles based on PLR.
    2533              :             // If supply (regen) inlet is OA node, regen mass flow rate is proportional to PLR.
    2534              :             // If both of the above is true then boost local variable up to full flow
    2535        97303 :             if ((fanOp == HVAC::FanOp::Continuous) && RegenInletIsOANode) {
    2536         1846 :                 local_SupInMassFlow /= HXPartLoadRatio;
    2537              :             }
    2538              :             // for cycling fan case, boost both local variables up to full flow
    2539        97303 :             if (fanOp == HVAC::FanOp::Cycling) {
    2540         5602 :                 local_SupInMassFlow /= HXPartLoadRatio; // supply = regen
    2541         5602 :                 local_SecInMassFlow /= HXPartLoadRatio; // secondary = process
    2542              :             }
    2543              : 
    2544              :             // Check for balanced flow condition
    2545        97303 :             this->CheckForBalancedFlow(state, local_SecInMassFlow, local_SupInMassFlow, FirstHVACIteration);
    2546              : 
    2547        97303 :             auto const &perf = state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex);
    2548              : 
    2549        97303 :             T_ProcInTemp = state.dataHeatRecovery->FullLoadOutAirTemp;
    2550        97303 :             T_ProcInHumRat = state.dataHeatRecovery->FullLoadOutAirHumRat;
    2551        97303 :             T_RegenInTemp = this->SupInTemp;
    2552        97303 :             T_RegenInHumRat = this->SupInHumRat;
    2553              : 
    2554              :             // Must use the same density used to convert volumetric flow rate to mass flow rate to get back to velocity
    2555        97303 :             RhoStd = state.dataEnvrn->StdRhoAir; // PsyRhoAirFnPbTdbW(StdBaroPress,20.0d0, 0.0d0)
    2556        97303 :             BalFaceVelActual = local_SupInMassFlow / (RhoStd * this->FaceArea);
    2557              : 
    2558        97303 :             T_FaceVel = BalFaceVelActual;
    2559              : 
    2560              :             //     Call model check routines only when HX is active, if coil is off these checks do not apply (no potential for heat transfer)
    2561              :             //     Check RH limits and warn user if out of bounds (T_* not modified in subroutine)
    2562              : 
    2563        97303 :             this->CheckModelBoundsRH_TempEq(state, T_RegenInTemp, T_RegenInHumRat, T_ProcInTemp, T_ProcInHumRat, FirstHVACIteration);
    2564              :             //     Check model boundaries and cap empirical model independent variables as needed (T_* may be modified on return from sub)
    2565        97303 :             this->CheckModelBoundsTempEq(state, T_RegenInTemp, T_RegenInHumRat, T_ProcInTemp, T_ProcInHumRat, T_FaceVel, FirstHVACIteration);
    2566              : 
    2567        97303 :             if (T_ProcInTemp != 0.0 && T_RegenInTemp != 0.0) {
    2568        97303 :                 FullLoadSupOutTemp = perf.B[0] + perf.B[1] * T_RegenInHumRat + perf.B[2] * T_RegenInTemp +
    2569        97303 :                                      perf.B[3] * (T_RegenInHumRat / T_RegenInTemp) + perf.B[4] * T_ProcInHumRat + perf.B[5] * T_ProcInTemp +
    2570        97303 :                                      perf.B[6] * (T_ProcInHumRat / T_ProcInTemp) + perf.B[7] * T_FaceVel;
    2571              : 
    2572              :                 // Check model boundary for supply (regen) temp and do not cap value if out of bounds, check that supply in temp > out temp
    2573        97303 :                 this->CheckModelBoundOutput_Temp(state, this->SupInTemp, FullLoadSupOutTemp, FirstHVACIteration);
    2574        97303 :                 FullLoadDeltaT = FullLoadSupOutTemp - this->SupInTemp;
    2575              :             } else {
    2576            0 :                 FullLoadDeltaT = 0.0;
    2577              :             }
    2578              : 
    2579        97303 :             H_ProcInTemp = state.dataHeatRecovery->FullLoadOutAirTemp;
    2580        97303 :             H_ProcInHumRat = state.dataHeatRecovery->FullLoadOutAirHumRat;
    2581        97303 :             H_RegenInTemp = this->SupInTemp;
    2582        97303 :             H_RegenInHumRat = this->SupInHumRat;
    2583        97303 :             H_FaceVel = BalFaceVelActual;
    2584              : 
    2585              :             //     Call model check routines only when HX is active, if coil is off these checks do not apply (no potential for heat transfer)
    2586              :             //     Check RH limits and warn user if out of bounds (H_* not modified in subroutine)
    2587              : 
    2588        97303 :             this->CheckModelBoundsRH_HumRatEq(state, H_RegenInTemp, H_RegenInHumRat, H_ProcInTemp, H_ProcInHumRat, FirstHVACIteration);
    2589              :             //     Check model boundaries and cap empirical model independent variables as needed (H_* may be modified on return from sub)
    2590        97303 :             this->CheckModelBoundsHumRatEq(state, H_RegenInTemp, H_RegenInHumRat, H_ProcInTemp, H_ProcInHumRat, H_FaceVel, FirstHVACIteration);
    2591              : 
    2592              :             //     Calc curve
    2593        97303 :             if (H_ProcInTemp != 0.0 && H_RegenInTemp != 0.0) {
    2594        97303 :                 FullLoadSupOutHumRat = perf.C[0] + perf.C[1] * H_RegenInHumRat + perf.C[2] * H_RegenInTemp +
    2595        97303 :                                        perf.C[3] * (H_RegenInHumRat / H_RegenInTemp) + perf.C[4] * H_ProcInHumRat + perf.C[5] * H_ProcInTemp +
    2596        97303 :                                        perf.C[6] * (H_ProcInHumRat / H_ProcInTemp) + perf.C[7] * H_FaceVel;
    2597              : 
    2598              :                 // Check model boundary for supply (regen) hum rat and do not cap value if out of bounds, check that supply in HR < out HR
    2599        97303 :                 this->CheckModelBoundOutput_HumRat(state, this->SupInHumRat, FullLoadSupOutHumRat, FirstHVACIteration);
    2600        97303 :                 FullLoadDeltaW = FullLoadSupOutHumRat - this->SupInHumRat;
    2601              :             } else {
    2602            0 :                 FullLoadDeltaW = 0.0;
    2603              :             }
    2604              : 
    2605              :             //     Check for saturation in the model's calculated supply outlet and reset temp, then humidity ratio at constant enthalpy
    2606              :             //     Reset delta T and delta W such that the model does not allow an outlet condition over saturation
    2607        97303 :             TestSaturationEnthalpy = Psychrometrics::PsyHFnTdbW(FullLoadSupOutTemp, FullLoadSupOutHumRat);
    2608        97303 :             if (Psychrometrics::PsyTsatFnHPb(state, TestSaturationEnthalpy, state.dataEnvrn->OutBaroPress, ThisSubTSat) > FullLoadSupOutTemp) {
    2609           60 :                 constexpr std::string_view ThisSubTSatFullLoadOutTemp = "CalcDesiccantBalancedHeatExch:   TSat-FullLoadOutTemp";
    2610           60 :                 constexpr std::string_view ThisSubTSatFullLoadOutHumRat = "CalcDesiccantBalancedHeatExch:   TSat-FullLoadOutHumRat";
    2611           60 :                 FullLoadSupOutTemp =
    2612           60 :                     Psychrometrics::PsyTsatFnHPb(state, TestSaturationEnthalpy, state.dataEnvrn->OutBaroPress, ThisSubTSatFullLoadOutTemp);
    2613           60 :                 FullLoadSupOutHumRat = Psychrometrics::PsyWFnTdbH(state, FullLoadSupOutTemp, TestSaturationEnthalpy, ThisSubTSatFullLoadOutHumRat);
    2614           60 :                 FullLoadDeltaT = FullLoadSupOutTemp - this->SupInTemp;
    2615           60 :                 FullLoadDeltaW = FullLoadSupOutHumRat - this->SupInHumRat;
    2616              :             }
    2617              : 
    2618        97303 :             if (!state.dataHeatRecovery->CalledFromParentObject) {
    2619              :                 //       calculate part-load ratio for HX
    2620            0 :                 MaxHumRatNeeded = state.dataLoopNodes->Node(this->SecOutletNode).HumRatMax;
    2621            0 :                 MinHumRatNeeded = state.dataLoopNodes->Node(this->SecOutletNode).HumRatMin;
    2622              :                 // Calculate partload fraction of dehumidification capacity required to meet setpoint
    2623              : 
    2624              :                 //       check the model output, if the regen delta W is positive, the process air stream is dehumidified
    2625            0 :                 if (FullLoadDeltaW > 0) {
    2626              :                     //         check for a setpoint, if no setpoint then PLR remains at 1
    2627            0 :                     if (MaxHumRatNeeded != SensedNodeFlagValue) {
    2628            0 :                         if (this->SecInHumRat > MaxHumRatNeeded && MaxHumRatNeeded > 0.0) {
    2629            0 :                             HXPartLoadRatio = (this->SecInHumRat - MaxHumRatNeeded) / FullLoadDeltaW;
    2630              :                         } else {
    2631            0 :                             HXPartLoadRatio = 0.0;
    2632              :                         }
    2633              :                     }
    2634              :                     //       check the model output, if the regen delta W is negative, the process air stream is humidified
    2635            0 :                 } else if (FullLoadDeltaW < 0) {
    2636              :                     //         check for a setpoint, if no setpoint then PLR remains at 1
    2637            0 :                     if (MinHumRatNeeded != SensedNodeFlagValue) {
    2638            0 :                         if (this->SecInHumRat < MinHumRatNeeded && MinHumRatNeeded > 0.0) {
    2639            0 :                             HXPartLoadRatio = (this->SecInHumRat - MinHumRatNeeded) / FullLoadDeltaW;
    2640              :                         } else {
    2641            0 :                             HXPartLoadRatio = 0.0;
    2642              :                         }
    2643              :                     }
    2644              :                 }
    2645              : 
    2646            0 :                 HXPartLoadRatio = max(0.0, HXPartLoadRatio);
    2647            0 :                 HXPartLoadRatio = min(1.0, HXPartLoadRatio);
    2648              : 
    2649        97303 :             } else if (CompanionCoilType > 0 && CompanionCoilIndex > -1) {
    2650        94459 :                 if (CompanionCoilType == HVAC::CoilDX_Cooling) {
    2651         2801 :                     HXPartLoadRatio = state.dataCoilCoolingDX->coilCoolingDXs[CompanionCoilIndex].partLoadRatioReport;
    2652        91658 :                 } else if (CompanionCoilType == HVAC::Coil_CoolingAirToAirVariableSpeed) {
    2653          477 :                     HXPartLoadRatio = state.dataVariableSpeedCoils->VarSpeedCoil(CompanionCoilIndex).PartLoadRatio;
    2654              :                 } else {
    2655        91181 :                     HXPartLoadRatio = state.dataDXCoils->DXCoilPartLoadRatio(CompanionCoilIndex);
    2656              :                 }
    2657              :             }
    2658              : 
    2659        97303 :             Real64 constexpr lowerLimit = 1.e-5;
    2660        97303 :             if (fanOp == HVAC::FanOp::Cycling || RegenInletIsOANode) {
    2661              :                 //       Supply (regen) air stream mass flow rate is cycling and proportional to PLR, outlet conditions are full load
    2662              :                 //       conditions
    2663         7448 :                 this->SupOutTemp = this->SupInTemp + FullLoadDeltaT;
    2664         7448 :                 this->SupOutHumRat = min(1.0, max(lowerLimit, this->SupInHumRat + FullLoadDeltaW));
    2665              :             } else {
    2666              :                 //       Supply (regen) air stream mass flow rate is constant and outlet conditions are averaged
    2667        89855 :                 this->SupOutTemp = this->SupInTemp + (FullLoadDeltaT * HXPartLoadRatio);
    2668        89855 :                 this->SupOutHumRat = min(1.0, max(lowerLimit, this->SupInHumRat + (FullLoadDeltaW * HXPartLoadRatio)));
    2669              :             }
    2670              : 
    2671              :             //     for a balanced flow HX, use average mass flow rate and actual node conditions to calculate CSup and CSec
    2672              :             //     the mass flow rate on the process and secondary side of HX may be imbalanced when the HX is used in the OA branch
    2673              :             //     use the average mass flow rate to avoid psych warnings, mass flow rates will converge at the end of the iteration
    2674              :             //     if the air mass flow rates do not converge, this model should not be used
    2675        97303 :             CSup = AverageMassFlowRate * Psychrometrics::PsyCpAirFnW(this->SupInHumRat);
    2676        97303 :             CSec = AverageMassFlowRate * Psychrometrics::PsyCpAirFnW(this->SecInHumRat);
    2677              : 
    2678        97303 :             this->SupOutEnth = Psychrometrics::PsyHFnTdbW(this->SupOutTemp, this->SupOutHumRat);
    2679              : 
    2680        97303 :             SensHeatRecRate = CSup * (this->SupOutTemp - this->SupInTemp);
    2681              : 
    2682        97303 :             TotHeatRecRate = AverageMassFlowRate * (this->SupOutEnth - this->SupInEnth);
    2683              : 
    2684              :             //     now calculate process side heat transfer
    2685              : 
    2686        97303 :             this->SecOutEnth = this->SecInEnth - TotHeatRecRate / AverageMassFlowRate;
    2687              : 
    2688        97303 :             this->SecOutTemp = this->SecInTemp - SensHeatRecRate / CSec;
    2689              : 
    2690        97303 :             this->SecOutHumRat = Psychrometrics::PsyWFnTdbH(state, this->SecOutTemp, this->SecOutEnth, ThisSubSecOutHumRat);
    2691              : 
    2692              :             // check for saturation in process (secondary) outlet
    2693              :             // The process outlet conditions should never be over the saturation curve for the balanced desiccant model
    2694              :             // although this may occur during warmup. This check is included here for consistency.
    2695        97303 :             TempSecOutSat = Psychrometrics::PsyTsatFnHPb(state, this->SecOutEnth, state.dataEnvrn->OutBaroPress, ThisSubTestSatSec);
    2696        97303 :             if (TempSecOutSat > this->SecOutTemp) {
    2697           85 :                 constexpr std::string_view ThisSubTSatSecOutHumRat = "CalcDesiccantBalancedHeatExch:   TSat-SecOutHumRat";
    2698           85 :                 this->SecOutTemp = TempSecOutSat;
    2699           85 :                 this->SecOutHumRat = Psychrometrics::PsyWFnTdbH(state, this->SecOutTemp, this->SecOutEnth, ThisSubTSatSecOutHumRat);
    2700              :             }
    2701              : 
    2702        97303 :             this->ElecUseRate = perf.NomElecPower * HXPartLoadRatio;
    2703              : 
    2704              :         } // ENDIF for "IF (UnitOn) THEN"
    2705              : 
    2706              :         // Report the process side heat transfer
    2707       672529 :         CSec = AverageMassFlowRate * Psychrometrics::PsyCpAirFnW(this->SecInHumRat);
    2708       672529 :         ProcessSensHeatRecRate = CSec * (this->SecOutTemp - this->SecInTemp);
    2709              : 
    2710       672529 :         ProcessTotHeatRecRate = this->SecOutMassFlow * (this->SecOutEnth - this->SecInEnth);
    2711              : 
    2712       672529 :         ProcessLatHeatRecRate = ProcessTotHeatRecRate - ProcessSensHeatRecRate;
    2713              : 
    2714              :         // Set report variables based on sign of recovery rate
    2715       672529 :         if (ProcessSensHeatRecRate > 0.0) {
    2716        96160 :             this->SensHeatingRate = ProcessSensHeatRecRate;
    2717        96160 :             this->SensCoolingRate = 0.0;
    2718              :         } else {
    2719       576369 :             this->SensHeatingRate = 0.0;
    2720       576369 :             this->SensCoolingRate = std::abs(ProcessSensHeatRecRate);
    2721              :         }
    2722       672529 :         if (ProcessLatHeatRecRate > 0.0) {
    2723          101 :             this->LatHeatingRate = ProcessLatHeatRecRate;
    2724          101 :             this->LatCoolingRate = 0.0;
    2725              :         } else {
    2726       672428 :             this->LatHeatingRate = 0.0;
    2727       672428 :             this->LatCoolingRate = std::abs(ProcessLatHeatRecRate);
    2728              :         }
    2729       672529 :         if (ProcessTotHeatRecRate > 0.0) {
    2730        62363 :             this->TotHeatingRate = ProcessTotHeatRecRate;
    2731        62363 :             this->TotCoolingRate = 0.0;
    2732              :         } else {
    2733       610166 :             this->TotHeatingRate = 0.0;
    2734       610166 :             this->TotCoolingRate = std::abs(ProcessTotHeatRecRate);
    2735              :         }
    2736       672529 :     }
    2737              : 
    2738        82416 :     void HeatExchCond::FrostControl(EnergyPlusData &state)
    2739              :     {
    2740              : 
    2741              :         // SUBROUTINE INFORMATION:
    2742              :         //       AUTHOR         Richard Raustad, FSEC
    2743              :         //       DATE WRITTEN   June 2003
    2744              :         //       MODIFIED       na
    2745              :         //       RE-ENGINEERED  na
    2746              : 
    2747              :         // PURPOSE OF THIS SUBROUTINE:
    2748              :         // Calculates fraction of timestep necessary to eliminate frost on ERV surface
    2749              :         // by comparing secondary outlet or outdoor temperature to a frost control threshold
    2750              :         // temperature.  Supply air and secondary air outlet conditions are calculated
    2751              :         // based on frost control method selected.
    2752              : 
    2753              :         // SUBROUTINE PARAMETER DEFINITIONS:
    2754        82416 :         Real64 constexpr ErrorTol(0.001); // error tolerance for iteration loop
    2755              : 
    2756              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    2757        82416 :         Real64 DFFraction = 0.0;    // fraction of timestep ERV is in frost control mode
    2758              :         Real64 Error;               // iteration loop error variable
    2759              :         Real64 Iter;                // iteration counter
    2760              :         Real64 QTotTrans;           // total heat transfer by ERV [W]
    2761              :         Real64 QSensTrans;          // sensible heat transfer by ERV [W]
    2762              :         Real64 HXSecAirVolFlowRate; // air volume flow rate of the secondary air stream through the heat exchanger [m3/sec]
    2763              :         Real64 HXSupAirVolFlowRate; // air volume flow rate of the supply air stream through the heat exchanger [m3/sec]
    2764              :         Real64 HXAvgAirVolFlowRate; // average air volume flow rate through the heat exchanger [m3/sec]
    2765              :         Real64 HXAirVolFlowRatio;   // nominal to actual air volume flow ratio
    2766              :         Real64 MassFlowSupIn;       // supply air mass flow rate at HX inlet
    2767              :         Real64 MassFlowSupOut;      // supply air mass flow rate through HX core outlet
    2768              :         Real64 MassFlowSupBypass;   // supply air bypass mass flow rate around HX core
    2769              :         Real64 TempSupIn;           // supply side temperature of air entering HX
    2770              :         Real64 TempSupOut;          // supply side temperature of air leaving HX core
    2771              :         Real64 HumRatSupIn;         // supply side humidity ratio of air entering HX
    2772              :         Real64 TempSecIn;           // secondary side temperature of air entering HX
    2773              :         Real64 TempSecOut;          // secondary side temperature of air leaving HX core
    2774              : 
    2775        82416 :         this->SupOutMassFlow = this->SupInMassFlow;
    2776        82416 :         this->SecOutMassFlow = this->SecInMassFlow;
    2777        82416 :         this->SupBypassMassFlow = 0.0;
    2778        82416 :         this->SecBypassMassFlow = 0.0;
    2779              :         // density of supply air [kg/m3]
    2780        82416 :         Real64 const RhoSup = Psychrometrics::PsyRhoAirFnPbTdbW(state, state.dataEnvrn->OutBaroPress, this->SupInTemp, this->SupInHumRat);
    2781              :         // density of secondary air [kg/m3]
    2782        82416 :         Real64 const RhoSec = Psychrometrics::PsyRhoAirFnPbTdbW(state, state.dataEnvrn->OutBaroPress, this->SecInTemp, this->SecInHumRat);
    2783              :         // mdot Cp of supply air [W/K]
    2784        82416 :         Real64 CSup = this->SupOutMassFlow * Psychrometrics::PsyCpAirFnW(this->SupInHumRat);
    2785              :         // mdot Cp of secondary air [W/K]
    2786        82416 :         Real64 const CSec = this->SecOutMassFlow * Psychrometrics::PsyCpAirFnW(this->SecInHumRat);
    2787              :         // minimum mdot Cp of supply or secondary air [W/K]
    2788        82416 :         Real64 CMin = min(CSup, CSec);
    2789              :         // threshold temperature below which frost control is active
    2790        82416 :         Real64 const TempThreshold = this->ThresholdTemperature;
    2791              : 
    2792        82416 :         if (this->ControlToTemperatureSetPoint) {
    2793              :             // Recalculate HX outlet conditions as if control to temperature setpoint was not activated,
    2794              :             // because defrost will override those results
    2795              : 
    2796        63441 :             HXSupAirVolFlowRate = this->SupOutMassFlow / RhoSup;
    2797        63441 :             HXSecAirVolFlowRate = this->SecOutMassFlow / RhoSec;
    2798        63441 :             HXAvgAirVolFlowRate = (HXSecAirVolFlowRate + HXSupAirVolFlowRate) / 2.0;
    2799        63441 :             HXAirVolFlowRatio = HXAvgAirVolFlowRate / this->NomSupAirVolFlow;
    2800        63441 :             this->SensEffectiveness = this->HeatEffectSensible100;
    2801        63441 :             if (this->HeatEffectSensibleCurveIndex > 0) {
    2802        62531 :                 this->SensEffectiveness *= Curve::CurveValue(state, this->HeatEffectSensibleCurveIndex, HXAirVolFlowRatio);
    2803              :             }
    2804        63441 :             this->LatEffectiveness = this->HeatEffectLatent100;
    2805        63441 :             if (this->HeatEffectLatentCurveIndex > 0) {
    2806        62531 :                 this->LatEffectiveness *= Curve::CurveValue(state, this->HeatEffectLatentCurveIndex, HXAirVolFlowRatio);
    2807              :             }
    2808        63441 :             this->SupOutTemp = this->SupInTemp + this->SensEffectiveness * CMin / CSup * (this->SecInTemp - this->SupInTemp);
    2809        63441 :             this->SupOutHumRat = this->SupInHumRat + this->LatEffectiveness * CMin / CSup * (this->SecInHumRat - this->SupInHumRat);
    2810        63441 :             this->SupOutEnth = Psychrometrics::PsyHFnTdbW(this->SupOutTemp, this->SupOutHumRat);
    2811              : 
    2812              :             //   Check for saturation in supply outlet and reset temp, then humidity ratio at constant enthalpy
    2813        63441 :             if (Psychrometrics::PsyTsatFnHPb(state, this->SupOutEnth, state.dataEnvrn->OutBaroPress) > this->SupOutTemp) {
    2814          108 :                 this->SupOutTemp = Psychrometrics::PsyTsatFnHPb(state, this->SupOutEnth, state.dataEnvrn->OutBaroPress);
    2815          108 :                 this->SupOutHumRat = Psychrometrics::PsyWFnTdbH(state, this->SupOutTemp, this->SupOutEnth);
    2816              :             }
    2817              : 
    2818        63441 :             QSensTrans = CSup * (this->SupInTemp - this->SupOutTemp);
    2819        63441 :             this->SecOutTemp = this->SecInTemp + QSensTrans / CSec;
    2820        63441 :             QTotTrans = this->SupOutMassFlow * (this->SupInEnth - this->SupOutEnth);
    2821        63441 :             this->SecOutEnth = this->SecInEnth + QTotTrans / this->SecOutMassFlow;
    2822        63441 :             this->SecOutHumRat = Psychrometrics::PsyWFnTdbH(state, this->SecOutTemp, this->SecOutEnth);
    2823              :         }
    2824              : 
    2825              :         // Check frost control by type
    2826              : 
    2827        82416 :         switch (this->FrostControlType) {
    2828        82416 :         case FrostControlOption::MinimumExhaustTemperature:
    2829              :             //   A plate HX will bypass air on the supply side to keep exhaust temp above a
    2830              :             //   threshold temperature and requires recalculating effectiveness based on
    2831              :             //   the reduced air flow rate. A rotary HX modulates rotational speed to try to keep the
    2832              :             //   exhaust air temperature above the threshold temperature. Assume that
    2833              :             //   sensible and latent effectiveness decrease proportionally with rotary HX speed.
    2834              : 
    2835        82416 :             DFFraction = max(0.0, min(1.0, SafeDiv((TempThreshold - this->SecOutTemp), (this->SecInTemp - this->SecOutTemp))));
    2836        82416 :             if (this->ExchConfig == HXConfigurationType::Rotary) {
    2837         6946 :                 this->SensEffectiveness *= (1.0 - DFFraction);
    2838         6946 :                 this->LatEffectiveness *= (1.0 - DFFraction);
    2839              :             } else { // HX is a plate heat exchanger, bypass air to eliminate frost
    2840        75470 :                 Error = 1.0;
    2841        75470 :                 Iter = 0.0;
    2842        75470 :                 MassFlowSupIn = this->SupInMassFlow;
    2843        75470 :                 MassFlowSupOut = this->SupOutMassFlow;
    2844        75470 :                 MassFlowSupBypass = this->SupBypassMassFlow;
    2845        75470 :                 TempSupIn = this->SupInTemp;
    2846        75470 :                 HumRatSupIn = this->SupInHumRat;
    2847        75470 :                 TempSecIn = this->SecInTemp;
    2848              : 
    2849       762258 :                 while (std::abs(Error) > ErrorTol && Iter < 10) {
    2850       686788 :                     MassFlowSupOut = MassFlowSupIn * (1.0 - DFFraction);
    2851       686788 :                     MassFlowSupBypass = MassFlowSupIn * DFFraction;
    2852       686788 :                     HXSupAirVolFlowRate = MassFlowSupOut / RhoSup;
    2853       686788 :                     HXSecAirVolFlowRate = this->SecOutMassFlow / RhoSec;
    2854       686788 :                     HXAvgAirVolFlowRate = (HXSecAirVolFlowRate + HXSupAirVolFlowRate) / 2.0;
    2855       686788 :                     HXAirVolFlowRatio = HXAvgAirVolFlowRate / this->NomSupAirVolFlow;
    2856       686788 :                     CSup = MassFlowSupOut * Psychrometrics::PsyCpAirFnW(HumRatSupIn);
    2857       686788 :                     CMin = min(CSup, CSec);
    2858       686788 :                     if (TempSupIn < TempSecIn) {
    2859              :                         //         Use heating effectiveness values
    2860       680935 :                         this->SensEffectiveness = this->HeatEffectSensible100;
    2861       680935 :                         if (this->HeatEffectSensibleCurveIndex > 0) {
    2862       680935 :                             this->SensEffectiveness *= Curve::CurveValue(state, this->HeatEffectSensibleCurveIndex, HXAirVolFlowRatio);
    2863              :                         }
    2864       680935 :                         this->LatEffectiveness = this->HeatEffectLatent100;
    2865       680935 :                         if (this->HeatEffectLatentCurveIndex > 0) {
    2866       680935 :                             this->LatEffectiveness *= Curve::CurveValue(state, this->HeatEffectLatentCurveIndex, HXAirVolFlowRatio);
    2867              :                         }
    2868              :                     } else {
    2869              :                         //         Use cooling effectiveness values
    2870         5853 :                         this->SensEffectiveness = this->CoolEffectSensible100;
    2871         5853 :                         if (this->CoolEffectSensibleCurveIndex > 0) {
    2872            0 :                             this->SensEffectiveness *= Curve::CurveValue(state, this->CoolEffectSensibleCurveIndex, HXAirVolFlowRatio);
    2873              :                         }
    2874         5853 :                         this->LatEffectiveness = this->CoolEffectLatent100;
    2875         5853 :                         if (this->CoolEffectLatentCurveIndex > 0) {
    2876            0 :                             this->LatEffectiveness *= Curve::CurveValue(state, this->CoolEffectLatentCurveIndex, HXAirVolFlowRatio);
    2877              :                         }
    2878              :                     }
    2879              :                     //         calculation of local variable Csup can be 0, guard against divide by 0.
    2880       686788 :                     TempSupOut = TempSupIn + this->SensEffectiveness * SafeDiv(CMin, CSup) * (TempSecIn - TempSupIn);
    2881       686788 :                     QSensTrans = CSup * (TempSupIn - TempSupOut);
    2882              :                     //         Csec cannot be 0 in this subroutine
    2883       686788 :                     TempSecOut = TempSecIn + QSensTrans / CSec;
    2884       686788 :                     Error = (TempSecOut - TempThreshold);
    2885              :                     //         recalculate DFFraction until convergence, guard against divide by 0 (unlikely).
    2886       686788 :                     DFFraction = max(0.0, min(1.0, DFFraction * SafeDiv((TempSecIn - TempSecOut), (TempSecIn - TempThreshold))));
    2887       686788 :                     ++Iter;
    2888              :                 }
    2889        75470 :                 this->SupInMassFlow = MassFlowSupIn;
    2890        75470 :                 this->SupOutMassFlow = MassFlowSupOut;
    2891        75470 :                 this->SupBypassMassFlow = MassFlowSupBypass;
    2892              :             }
    2893        82416 :             this->SupOutTemp = this->SupInTemp + this->SensEffectiveness * SafeDiv(CMin, CSup) * (this->SecInTemp - this->SupInTemp);
    2894        82416 :             this->SupOutHumRat = this->SupInHumRat + this->LatEffectiveness * SafeDiv(CMin, CSup) * (this->SecInHumRat - this->SupInHumRat);
    2895        82416 :             this->SupOutEnth = Psychrometrics::PsyHFnTdbW(this->SupOutTemp, this->SupOutHumRat);
    2896              : 
    2897              :             //   Check for saturation in supply outlet and reset temp, then humidity ratio at constant enthalpy
    2898        82416 :             if (Psychrometrics::PsyTsatFnHPb(state, this->SupOutEnth, state.dataEnvrn->OutBaroPress) > this->SupOutTemp) {
    2899          231 :                 this->SupOutTemp = Psychrometrics::PsyTsatFnHPb(state, this->SupOutEnth, state.dataEnvrn->OutBaroPress);
    2900          231 :                 this->SupOutHumRat = Psychrometrics::PsyWFnTdbH(state, this->SupOutTemp, this->SupOutEnth);
    2901              :             }
    2902              : 
    2903        82416 :             QSensTrans = CSup * (this->SupInTemp - this->SupOutTemp);
    2904        82416 :             this->SecOutTemp = this->SecInTemp + QSensTrans / CSec;
    2905        82416 :             QTotTrans = this->SupOutMassFlow * (this->SupInEnth - this->SupOutEnth);
    2906        82416 :             this->SecOutEnth = this->SecInEnth + QTotTrans / this->SecOutMassFlow;
    2907        82416 :             this->SecOutHumRat = Psychrometrics::PsyWFnTdbH(state, this->SecOutTemp, this->SecOutEnth);
    2908              : 
    2909              :             //   Perform mixing of core air stream and bypass air stream and set mass flow rates at outlet nodes
    2910        82416 :             this->SupOutEnth = (this->SupOutMassFlow * this->SupOutEnth + this->SupBypassMassFlow * this->SupInEnth) / this->SupInMassFlow;
    2911        82416 :             this->SupOutHumRat = (this->SupOutMassFlow * this->SupOutHumRat + this->SupBypassMassFlow * this->SupInHumRat) / this->SupInMassFlow;
    2912        82416 :             this->SupOutTemp = Psychrometrics::PsyTdbFnHW(this->SupOutEnth, this->SupOutHumRat);
    2913        82416 :             this->SupOutMassFlow = this->SupInMassFlow;
    2914        82416 :             this->SecOutEnth = (this->SecOutMassFlow * this->SecOutEnth + this->SecBypassMassFlow * this->SecInEnth) / this->SecInMassFlow;
    2915        82416 :             this->SecOutHumRat = (this->SecOutMassFlow * this->SecOutHumRat + this->SecBypassMassFlow * this->SecInHumRat) / this->SecInMassFlow;
    2916        82416 :             this->SecOutTemp = Psychrometrics::PsyTdbFnHW(this->SecOutEnth, this->SecOutHumRat);
    2917        82416 :             this->SecOutMassFlow = this->SecInMassFlow;
    2918        82416 :             break;
    2919              : 
    2920            0 :         case FrostControlOption::ExhaustAirRecirculation:
    2921              :             // Directing exhaust outlet air back across the HX core on the supply side
    2922              :             // Assume no heat exchange when in frost control mode, full heat exchange otherwise
    2923            0 :             DFFraction = max(0.0, min((this->InitialDefrostTime + this->RateofDefrostTimeIncrease * (TempThreshold - this->SupInTemp)), 1.0));
    2924              : 
    2925              :             //    Calculate derated heat transfer using outlet air conditions assuming no defrost (calculated earlier)
    2926              :             //    and (1-DefrostFraction)
    2927            0 :             QSensTrans = (1.0 - DFFraction) * CSup * (this->SupInTemp - this->SupOutTemp);
    2928            0 :             QTotTrans = (1.0 - DFFraction) * this->SupOutMassFlow * (this->SupInEnth - this->SupOutEnth);
    2929              : 
    2930            0 :             this->SupOutMassFlow = (1.0 - DFFraction) * this->SupInMassFlow + DFFraction * this->SecInMassFlow;
    2931              : 
    2932              :             //    Blend supply outlet condition of HX core with exhaust air inlet to get final supply air outlet conditions
    2933            0 :             this->SupOutTemp = ((1.0 - DFFraction) * this->SupInMassFlow * this->SupOutTemp + DFFraction * this->SecInMassFlow * this->SecInTemp) /
    2934            0 :                                this->SupOutMassFlow;
    2935              : 
    2936            0 :             this->SupOutHumRat =
    2937            0 :                 ((1.0 - DFFraction) * this->SupInMassFlow * this->SupOutHumRat + DFFraction * this->SecInMassFlow * this->SecInHumRat) /
    2938            0 :                 this->SupOutMassFlow;
    2939              : 
    2940            0 :             this->SupOutEnth = Psychrometrics::PsyHFnTdbW(this->SupOutTemp, this->SupOutHumRat);
    2941              :             //    No need to check for saturation after SA out and EA inlet are blended
    2942              : 
    2943              :             //    Derate effectiveness based on frost control time fraction for reporting purposes
    2944            0 :             this->SensEffectiveness *= (1.0 - DFFraction);
    2945            0 :             this->LatEffectiveness *= (1.0 - DFFraction);
    2946              : 
    2947              :             //    Secondary air outlet conditions are previously calculated as the conditions when not
    2948              :             //    in defrost, and this is what we want to report so no changes here.
    2949              :             //    Average SupInMassFlow and SecOutMassFlow rates have been reduced due to frost control
    2950              :             //      Equipment attached to the supply inlet node may have problems with our setting the
    2951              :             //      mass flow rate in the next statement. This is done only to simulate exhaust air recirc.
    2952            0 :             state.dataLoopNodes->Node(this->SupInletNode).MassFlowRate = this->SupInMassFlow * (1.0 - DFFraction);
    2953            0 :             this->SecOutMassFlow *= (1.0 - DFFraction);
    2954            0 :             break;
    2955              : 
    2956            0 :         case FrostControlOption::ExhaustOnly:
    2957              : 
    2958              :             //   Perform frost control by bypassing the supply air around the HX core during the defrost
    2959              :             //   time period. HX heat transfer is reduced proportionally to (1 - defrosttimefraction)
    2960              : 
    2961            0 :             DFFraction = max(0.0, min((this->InitialDefrostTime + this->RateofDefrostTimeIncrease * (TempThreshold - this->SupInTemp)), 1.0));
    2962              : 
    2963              :             //   Calculate derated heat transfer based on defrost time
    2964            0 :             QSensTrans = (1.0 - DFFraction) * CSup * (this->SupInTemp - this->SupOutTemp);
    2965            0 :             QTotTrans = (1.0 - DFFraction) * this->SupOutMassFlow * (this->SupInEnth - this->SupOutEnth);
    2966              : 
    2967              :             //   Calculate the air conditions leaving heat exchanger unit
    2968              :             //   Heat exchanger effectiveness is not derated, HX is fully bypassed during frost control
    2969              : 
    2970            0 :             this->SupBypassMassFlow = this->SupInMassFlow * DFFraction;
    2971            0 :             this->SupOutTemp = this->SupInTemp - QSensTrans / CSup;
    2972            0 :             this->SupOutEnth = this->SupInEnth - QTotTrans / this->SupOutMassFlow;
    2973            0 :             this->SupOutHumRat = Psychrometrics::PsyWFnTdbH(state, this->SupOutTemp, this->SupOutEnth);
    2974              : 
    2975            0 :             if (Psychrometrics::PsyTsatFnHPb(state, this->SupOutEnth, state.dataEnvrn->OutBaroPress) > this->SupOutTemp) {
    2976            0 :                 this->SupOutTemp = Psychrometrics::PsyTsatFnHPb(state, this->SupOutEnth, state.dataEnvrn->OutBaroPress);
    2977            0 :                 this->SupOutHumRat = Psychrometrics::PsyWFnTdbH(state, this->SupOutTemp, this->SupOutEnth);
    2978            0 :                 QSensTrans = CSup * (this->SupInTemp - this->SupOutTemp);
    2979              :                 // Should we be updating the sensible and latent effectiveness values also?
    2980              :             }
    2981              : 
    2982            0 :             this->SecOutEnth = this->SecInEnth + QTotTrans / this->SecOutMassFlow;
    2983            0 :             this->SecOutTemp = this->SecInTemp + QSensTrans / CSec;
    2984            0 :             this->SecOutHumRat = Psychrometrics::PsyWFnTdbH(state, this->SecOutTemp, this->SecOutEnth);
    2985            0 :             break;
    2986            0 :         default:
    2987            0 :             break; // :: None means don't do anything here, and ::Invalid is caught on GetInput
    2988              :         }
    2989              : 
    2990        82416 :         this->DefrostFraction = DFFraction;
    2991        82416 :     }
    2992              : 
    2993      3904968 :     void HeatExchCond::UpdateHeatRecovery(EnergyPlusData &state)
    2994              :     {
    2995              : 
    2996              :         // SUBROUTINE INFORMATION:
    2997              :         //       AUTHOR         Michael Wetter
    2998              :         //       DATE WRITTEN   March 1999
    2999              :         //       MODIFIED       Fred Buhl November 2000
    3000              :         //       RE-ENGINEERED  na
    3001              : 
    3002              :         // PURPOSE OF THIS SUBROUTINE:
    3003              :         // Moves heat exchanger output to the outlet nodes.
    3004              : 
    3005      3904968 :         int const SupInNode = this->SupInletNode;
    3006      3904968 :         int const SupOutNode = this->SupOutletNode;
    3007      3904968 :         int const SecInNode = this->SecInletNode;
    3008      3904968 :         int const SecOutNode = this->SecOutletNode;
    3009              : 
    3010      3904968 :         auto &thisSupInNode = state.dataLoopNodes->Node(SupInNode);
    3011      3904968 :         auto &thisSupOutNode = state.dataLoopNodes->Node(SupOutNode);
    3012      3904968 :         auto &thisSecInNode = state.dataLoopNodes->Node(SecInNode);
    3013      3904968 :         auto &thisSecOutNode = state.dataLoopNodes->Node(SecOutNode);
    3014              : 
    3015              :         // Set the outlet air nodes of the heat exchanger
    3016      3904968 :         thisSupOutNode.Temp = this->SupOutTemp;
    3017      3904968 :         thisSupOutNode.HumRat = this->SupOutHumRat;
    3018      3904968 :         thisSupOutNode.Enthalpy = this->SupOutEnth;
    3019      3904968 :         thisSupOutNode.MassFlowRate = this->SupOutMassFlow;
    3020      3904968 :         thisSecOutNode.Temp = this->SecOutTemp;
    3021      3904968 :         thisSecOutNode.HumRat = this->SecOutHumRat;
    3022      3904968 :         thisSecOutNode.Enthalpy = this->SecOutEnth;
    3023      3904968 :         thisSecOutNode.MassFlowRate = this->SecOutMassFlow;
    3024              : 
    3025              :         // Set the outlet nodes for properties that just pass through & not used
    3026      3904968 :         thisSupOutNode.Quality = thisSupInNode.Quality;
    3027      3904968 :         thisSupOutNode.Press = thisSupInNode.Press;
    3028      3904968 :         thisSupOutNode.MassFlowRateMin = thisSupInNode.MassFlowRateMin;
    3029      3904968 :         thisSupOutNode.MassFlowRateMax = thisSupInNode.MassFlowRateMax;
    3030      3904968 :         thisSupOutNode.MassFlowRateMinAvail = thisSupInNode.MassFlowRateMinAvail;
    3031      3904968 :         thisSupOutNode.MassFlowRateMaxAvail = thisSupInNode.MassFlowRateMaxAvail;
    3032      3904968 :         thisSecOutNode.Quality = thisSecInNode.Quality;
    3033      3904968 :         thisSecOutNode.Press = thisSecInNode.Press;
    3034      3904968 :         thisSecOutNode.MassFlowRateMin = thisSecInNode.MassFlowRateMin;
    3035      3904968 :         thisSecOutNode.MassFlowRateMax = thisSecInNode.MassFlowRateMax;
    3036      3904968 :         thisSecOutNode.MassFlowRateMinAvail = thisSecInNode.MassFlowRateMinAvail;
    3037      3904968 :         thisSecOutNode.MassFlowRateMaxAvail = thisSecInNode.MassFlowRateMaxAvail;
    3038              : 
    3039      3904968 :         if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
    3040        24438 :             thisSupOutNode.CO2 = thisSupInNode.CO2;
    3041        24438 :             thisSecOutNode.CO2 = thisSecInNode.CO2;
    3042              :         }
    3043      3904968 :         if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
    3044            0 :             thisSupOutNode.GenContam = thisSupInNode.GenContam;
    3045            0 :             thisSecOutNode.GenContam = thisSecInNode.GenContam;
    3046              :         }
    3047      3904968 :     }
    3048              : 
    3049      3904968 :     void HeatExchCond::ReportHeatRecovery(EnergyPlusData &state)
    3050              :     {
    3051              : 
    3052              :         // SUBROUTINE INFORMATION:
    3053              :         //       AUTHOR         Michael Wetter
    3054              :         //       DATE WRITTEN   March 1999
    3055              :         //       MODIFIED       F Buhl Nov 2000, D Shirey Feb/June 2003
    3056              :         //       RE-ENGINEERED  na
    3057              : 
    3058              :         // PURPOSE OF THIS SUBROUTINE:
    3059              :         // Fill remaining report variables
    3060              : 
    3061      3904968 :         Real64 const TimeStepSysSec = state.dataHVACGlobal->TimeStepSysSec;
    3062      3904968 :         this->ElecUseEnergy = this->ElecUseRate * TimeStepSysSec;
    3063      3904968 :         this->SensHeatingEnergy = this->SensHeatingRate * TimeStepSysSec;
    3064      3904968 :         this->LatHeatingEnergy = this->LatHeatingRate * TimeStepSysSec;
    3065      3904968 :         this->TotHeatingEnergy = this->TotHeatingRate * TimeStepSysSec;
    3066      3904968 :         this->SensCoolingEnergy = this->SensCoolingRate * TimeStepSysSec;
    3067      3904968 :         this->LatCoolingEnergy = this->LatCoolingRate * TimeStepSysSec;
    3068      3904968 :         this->TotCoolingEnergy = this->TotCoolingRate * TimeStepSysSec;
    3069              : 
    3070      3904968 :         state.dataHVACGlobal->AirToAirHXElecPower = this->ElecUseRate;
    3071      3904968 :     }
    3072              : 
    3073      2761929 :     Real64 SafeDiv(Real64 const a, Real64 const b)
    3074              :     {
    3075              : 
    3076              :         // SUBROUTINE INFORMATION:
    3077              :         //       AUTHOR         Michael Wetter
    3078              :         //       DATE WRITTEN   March 1999
    3079              :         //       MODIFIED       na
    3080              :         //       RE-ENGINEERED  na
    3081              : 
    3082              :         // PURPOSE OF THIS FUNCTION:
    3083              :         // Returns a / b while preventing division by zero
    3084              : 
    3085              :         // METHODOLOGY EMPLOYED:
    3086              :         // Check for small or zero values before performing division
    3087              : 
    3088      2761929 :         if (std::abs(b) < SMALL) {
    3089           22 :             return a / sign(SMALL, b);
    3090              :         } else {
    3091      2761907 :             return a / b;
    3092              :         }
    3093              :     }
    3094              : 
    3095       570512 :     Real64 CalculateEpsFromNTUandZ(EnergyPlusData &state,
    3096              :                                    Real64 const NTU,             // number of transfer units
    3097              :                                    Real64 const Z,               // capacity rate ratio
    3098              :                                    HXConfiguration const FlowArr // flow arrangement
    3099              :     )
    3100              :     {
    3101              : 
    3102              :         // SUBROUTINE INFORMATION:
    3103              :         //       AUTHOR         Michael Wetter
    3104              :         //       DATE WRITTEN   March 1999
    3105              :         //       MODIFIED       Fred Buhl November 2000
    3106              :         //       RE-ENGINEERED  na
    3107              : 
    3108              :         // PURPOSE OF THIS SUBROUTINE:
    3109              :         // Calculates eps, the exchanger effectiveness,
    3110              :         // from NTU, the number of transfer units,
    3111              :         // from Z, the capacity rate ratio, and
    3112              :         // from the flow arrangement
    3113              : 
    3114              :         // METHODOLOGY EMPLOYED:
    3115              :         // Uses the effectiveness - NTU heat exchanger formulas
    3116              : 
    3117              :         // REFERENCES:
    3118              :         // M. Wetter, Simulation Model Air-to-Air Plate Heat Exchanger
    3119              :         // LBNL Report 42354, 1999.
    3120              :         // Also see:
    3121              :         // ASHRAE HVAC 2 Toolkit, pages 4-3 through 4-5
    3122              : 
    3123              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    3124              :         Real64 Temp;      // temporary variable
    3125       570512 :         Real64 Eps = 0.0; // heat exchanger effectiveness, return value
    3126              : 
    3127              :         // check input validity
    3128       570512 :         if (Z < 0.0 || Z > 1.0) {
    3129            0 :             ShowFatalError(state, format("Variable Z ({:.2R}) out of range [0.0,1.0] in CalculateEpsFromNTUandZ", Z));
    3130              :         }
    3131              : 
    3132              :         // effectiveness
    3133       570512 :         if (NTU < SMALL) {
    3134            0 :             Eps = 0.0;
    3135       570512 :         } else if (Z < SMALL) { // Eps independent of flow arrangement
    3136            0 :             Eps = 1.0 - std::exp(-NTU);
    3137              :         } else {
    3138       570512 :             switch (FlowArr) {
    3139       559711 :             case HXConfiguration::CounterFlow: { // COUNTER FLOW
    3140       559711 :                 if (std::abs(Z - 1.0) < SMALL) {
    3141       147801 :                     Eps = NTU / (NTU + 1.0);
    3142              :                 } else {
    3143       411910 :                     Temp = std::exp(-NTU * (1.0 - Z));
    3144       411910 :                     Eps = (1.0 - Temp) / (1.0 - Z * Temp);
    3145              :                 }
    3146       559711 :             } break;
    3147            0 :             case HXConfiguration::ParallelFlow: { // PARALLEL FLOW
    3148            0 :                 Temp = (1.0 + Z);
    3149            0 :                 Eps = (1.0 - std::exp(-NTU * Temp)) / Temp;
    3150            0 :             } break;
    3151        10801 :             case HXConfiguration::CrossFlowBothUnmixed: { // CROSS FLOW BOTH UNMIXED
    3152        10801 :                 Temp = Z * std::pow(NTU, -0.22);
    3153        10801 :                 Eps = 1.0 - std::exp(std::expm1(-NTU * Temp) / Temp);
    3154        10801 :             } break;
    3155            0 :             case HXConfiguration::CrossFlowOther: { // CROSS FLOW, Cmax MIXED, Cmin UNMIXED
    3156            0 :                 Eps = (1.0 - std::exp(-Z * (1.0 - std::exp(-NTU)))) / Z;
    3157            0 :             } break;
    3158            0 :             default: {
    3159            0 :                 ShowFatalError(state, format("HeatRecovery: Illegal flow arrangement in CalculateEpsFromNTUandZ, Value={}", FlowArr));
    3160            0 :             } break;
    3161              :             }
    3162              :         }
    3163       570512 :         return Eps;
    3164              :     }
    3165              : 
    3166           81 :     void CalculateNTUfromEpsAndZ(EnergyPlusData &state,
    3167              :                                  Real64 &NTU,                   // number of transfer units
    3168              :                                  CalculateNTUBoundsErrors &Err, // error indicator
    3169              :                                  Real64 const Z,                // capacity rate ratio
    3170              :                                  HXConfiguration const FlowArr, // flow arrangement
    3171              :                                  Real64 const Eps               // heat exchanger effectiveness
    3172              :     )
    3173              :     {
    3174              : 
    3175              :         // SUBROUTINE INFORMATION:
    3176              :         //       AUTHOR         Michael Wetter
    3177              :         //       DATE WRITTEN   March 1999
    3178              :         //       MODIFIED       Fred Buhl November 2000
    3179              :         //       RE-ENGINEERED  na
    3180              : 
    3181              :         // PURPOSE OF THIS SUBROUTINE:
    3182              :         // Calculates NTU, the number of transfer units,
    3183              :         // based on eps, the exchanger effectiveness,
    3184              :         // Z, the capacity rate ratio, and
    3185              :         // from the flow arrangement
    3186              : 
    3187              :         // METHODOLOGY EMPLOYED:
    3188              :         // Uses the effectiveness - NTU heat exchanger formulas
    3189              : 
    3190              :         // REFERENCES:
    3191              :         // M. Wetter, Simulation Model Air-to-Air Plate Heat Exchanger
    3192              :         // LBNL Report 42354, 1999.
    3193              :         // Also see:
    3194              :         // ASHRAE HVAC 2 Toolkit, pages 4-3 through 4-5
    3195              : 
    3196           81 :         NTU = 0.0;
    3197              :         // check input validity
    3198           81 :         if (Z < 0.0 || Z > 1.0) {
    3199            0 :             Err = CalculateNTUBoundsErrors::MassFlowRatio;
    3200            0 :             return;
    3201              :         }
    3202              : 
    3203           81 :         if (FlowArr == HXConfiguration::ParallelFlow) {
    3204            0 :             if (Eps < 0.0 || Eps > 1.0 / (1.0 + Z)) {
    3205            0 :                 Err = CalculateNTUBoundsErrors::NominalEffectiveness1;
    3206            0 :                 return;
    3207              :             }
    3208           81 :         } else if (FlowArr == HXConfiguration::CrossFlowOther) {
    3209            0 :             if (Eps < 0.0 || Eps > (1.0 - std::exp(-Z)) / Z) {
    3210            0 :                 Err = CalculateNTUBoundsErrors::NominalEffectiveness2;
    3211            0 :                 return;
    3212              :             }
    3213              :             // check product (Eps*Z)
    3214            0 :             if (Eps * Z < 0.0 || Eps * Z > 1.0 - std::exp(Z * (SMALL - 1.0))) {
    3215            0 :                 Err = CalculateNTUBoundsErrors::Quantity;
    3216            0 :                 return;
    3217              :             }
    3218              :             // check product (Eps*Z)
    3219              :         } else {
    3220           81 :             if (Eps < 0.0 || Eps > 1.0) {
    3221            0 :                 Err = CalculateNTUBoundsErrors::NominalEffectiveness3;
    3222            0 :                 return;
    3223              :             }
    3224              :         }
    3225              : 
    3226           81 :         if (Eps < SMALL) { // no effectiveness. Set NTU = 0
    3227            0 :             NTU = 0.0;
    3228           81 :         } else if (Z < SMALL) { // Eps independent of flow arrangement
    3229            0 :             NTU = -std::log(1.0 - Eps);
    3230              :         } else {
    3231              :             // calculate based on configuration
    3232           81 :             switch (FlowArr) {
    3233           69 :             case HXConfiguration::CounterFlow: { // COUNTER FLOW
    3234           69 :                 if (std::abs(Z - 1.0) < SMALL) {
    3235           63 :                     NTU = Eps / (1.0 - Eps);
    3236              :                 } else {
    3237            6 :                     NTU = 1.0 / (Z - 1.0) * std::log((1.0 - Eps) / (1.0 - Eps * Z));
    3238              :                 }
    3239           69 :             } break;
    3240            0 :             case HXConfiguration::ParallelFlow: { // PARALLEL FLOW
    3241            0 :                 NTU = -std::log1p(-Eps - Eps * Z) / (Z + 1.0);
    3242            0 :             } break;
    3243           12 :             case HXConfiguration::CrossFlowBothUnmixed: { // CROSS FLOW BOTH UNMIXED
    3244           12 :                 NTU = GetNTUforCrossFlowBothUnmixed(state, Eps, Z);
    3245           12 :             } break;
    3246            0 :             case HXConfiguration::CrossFlowOther: { // CROSS FLOW, Cmax MIXED, Cmin UNMIXED
    3247            0 :                 NTU = -std::log1p(std::log(1.0 - Eps * Z) / Z);
    3248            0 :             } break;
    3249            0 :             default: {
    3250            0 :                 ShowFatalError(state, format("HeatRecovery: Illegal flow arrangement in CalculateNTUfromEpsAndZ, Value={}", FlowArr));
    3251            0 :             } break;
    3252              :             }
    3253              :         }
    3254              :     }
    3255              : 
    3256           12 :     Real64 GetNTUforCrossFlowBothUnmixed(EnergyPlusData &state,
    3257              :                                          Real64 const Eps, // heat exchanger effectiveness
    3258              :                                          Real64 const Z    // capacity rate ratio
    3259              :     )
    3260              :     {
    3261              : 
    3262              :         // FUNCTION INFORMATION:
    3263              :         //       AUTHOR         Michael Wetter
    3264              :         //       DATE WRITTEN   March 1999
    3265              :         //       MODIFIED       Fred Buhl November 2000
    3266              :         //       RE-ENGINEERED  na
    3267              : 
    3268              :         // PURPOSE OF THIS FUNCTION:
    3269              :         // Calculates the NTU value based on the exchanger effectiveness
    3270              :         // and the capacity ratio for cross flow exchanger, both
    3271              :         // streams unmixed
    3272              : 
    3273              :         // METHODOLOGY EMPLOYED:
    3274              :         // Uses a Regula Falsi solver function to numerically invert the formula
    3275              :         // giving effectiveness as a function of NTU and Z..
    3276              : 
    3277              :         // REFERENCES:
    3278              :         // M. Wetter, Simulation Model Air-to-Air Plate Heat Exchanger
    3279              :         // LBNL Report 42354, 1999.
    3280              :         // Also see:
    3281              :         // ASHRAE HVAC 2 Toolkit, pages 4-3 through 4-5
    3282              : 
    3283              :         // Return value
    3284              :         Real64 NTU; // result variable; number of transfer units
    3285              : 
    3286              :         // FUNCTION PARAMETER DEFINITIONS:
    3287           12 :         Real64 constexpr Acc(0.0001); // Accuracy of result
    3288           12 :         int constexpr MaxIte(500);    // Maximum number of iterations
    3289              : 
    3290              :         int SolFla;                  // Flag of solver
    3291           12 :         Real64 constexpr NTU0(0.0);  // lower bound for NTU
    3292           12 :         Real64 constexpr NTU1(50.0); // upper bound for NTU
    3293          324 :         auto f = [Eps, Z](Real64 const NTU) { return 1.0 - std::exp(std::expm1(-std::pow(NTU, 0.78) * Z) / Z * std::pow(NTU, 0.22)) - Eps; };
    3294           12 :         General::SolveRoot(state, Acc, MaxIte, SolFla, NTU, f, NTU0, NTU1);
    3295              : 
    3296           12 :         if (SolFla == -2) {
    3297            0 :             ShowFatalError(state, "HeatRecovery: Bad initial bounds for NTU in GetNTUforCrossFlowBothUnmixed");
    3298           12 :         } else if (SolFla == -1) {
    3299            0 :             ShowFatalError(state, "HeatRecovery: No convergence in solving for NTU in GetNTUforCrossFlowBothUnmixed");
    3300              :         }
    3301              : 
    3302           12 :         return NTU;
    3303              :     }
    3304              : 
    3305        97303 :     void HeatExchCond::CheckModelBoundsTempEq(EnergyPlusData &state,
    3306              :                                               Real64 &T_RegenInTemp,        // current regen inlet temperature (C) for regen outlet temp eqn
    3307              :                                               Real64 &T_RegenInHumRat,      // current regen inlet hum rat for regen outlet temp eqn
    3308              :                                               Real64 &T_ProcInTemp,         // current process inlet temperature (C) for regen outlet temp eqn
    3309              :                                               Real64 &T_ProcInHumRat,       // current process inlet hum rat for regen outlet temp eqn
    3310              :                                               Real64 &T_FaceVel,            // current process and regen face velocity (m/s)
    3311              :                                               bool const FirstHVACIteration // First HVAC iteration flag
    3312              :     ) const
    3313              :     {
    3314              : 
    3315              :         // SUBROUTINE INFORMATION:
    3316              :         //       AUTHOR         Mangesh Basarkar, FSEC
    3317              :         //       DATE WRITTEN   January 2007
    3318              :         //       MODIFIED       na
    3319              :         //       RE-ENGINEERED  na
    3320              : 
    3321              :         // PURPOSE OF THIS SUBROUTINE:
    3322              :         // To verify that the empirical model's independent variables are within the limits used during the
    3323              :         // development of the empirical model.
    3324              : 
    3325              :         // METHODOLOGY EMPLOYED:
    3326              :         // The empirical models used for simulating a desiccant enhanced cooling coil are based on a limited data set.
    3327              :         // Extrapolation of empirical models can cause instability and the independent variables may need to be limited.
    3328              :         // The range of each independent variable is provided by the user and are based on the limits of the
    3329              :         // empirical model. These limits are tested in this subroutine each time step and returned for use by the calling
    3330              :         // routine.
    3331              : 
    3332              :         // Using/Aliasing
    3333              :         using General::CreateSysTimeIntervalString;
    3334              : 
    3335              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    3336        97303 :         auto &thisError = state.dataHeatRecovery->error1;
    3337        97303 :         Real64 SysTimeElapsed = state.dataHVACGlobal->SysTimeElapsed;
    3338        97303 :         Real64 TimeStepSys = state.dataHVACGlobal->TimeStepSys;
    3339              : 
    3340              :         // current end time is compared with last to see if time step changed
    3341              : 
    3342              :         //   calculate end time of current time step
    3343        97303 :         thisError.CurrentEndTime = state.dataGlobal->CurrentTime + SysTimeElapsed;
    3344              : 
    3345              :         //   Print warning messages only when valid and only for the first occurrence. Let summary provide statistics.
    3346              :         //   Wait for next time step to print warnings. If simulation iterates, print out
    3347              :         //   the warning for the last iteration only. Must wait for next time step to accomplish this.
    3348              :         //   If a warning occurs and the simulation down shifts, the warning is not valid.
    3349        97303 :         if (thisError.CurrentEndTime > thisError.CurrentEndTimeLast && TimeStepSys >= thisError.TimeStepSysLast) {
    3350              : 
    3351              :             // print error for variables of regeneration outlet temperature equation
    3352              :             // Regen inlet temp for temp eqn
    3353         6541 :             if (state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_RegenInTempError.print) {
    3354           26 :                 ++state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_RegenInTempError.count;
    3355           26 :                 if (state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_RegenInTempError.count < 2) {
    3356            1 :                     ShowWarningError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_RegenInTempError.buffer1);
    3357            1 :                     ShowContinueError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_RegenInTempError.buffer2);
    3358            1 :                     ShowContinueError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_RegenInTempError.buffer3);
    3359            3 :                     ShowContinueError(state,
    3360              :                                       "...Using regeneration inlet air temperatures that are outside the regeneration outlet air temperature "
    3361              :                                       "equation model boundaries may adversely affect desiccant model performance.");
    3362              :                 } else {
    3363          200 :                     ShowRecurringWarningErrorAtEnd(state,
    3364           50 :                                                    format("{} \"{}\" - Regeneration inlet air temp used in regen outlet air temperature equation is "
    3365              :                                                           "out of range error continues...",
    3366           25 :                                                           state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).PerfType,
    3367           25 :                                                           state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).Name),
    3368           25 :                                                    state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_RegenInTempError.index,
    3369           25 :                                                    state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_RegenInTempError.last,
    3370           25 :                                                    state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_RegenInTempError.last);
    3371              :                 }
    3372              :             }
    3373              :             // Regen inlet humidity ratio for temp eqn
    3374         6541 :             if (state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_RegenInHumRatError.print) {
    3375            0 :                 ++state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_RegenInHumRatError.count;
    3376            0 :                 if (state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_RegenInHumRatError.count < 2) {
    3377            0 :                     ShowWarningError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_RegenInHumRatError.buffer1);
    3378            0 :                     ShowContinueError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_RegenInHumRatError.buffer2);
    3379            0 :                     ShowContinueError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_RegenInHumRatError.buffer3);
    3380            0 :                     ShowContinueError(state,
    3381              :                                       "...Using regeneration inlet air humidity ratios that are outside the regeneration outlet air temperature "
    3382              :                                       "equation model boundaries may adversely affect desiccant model performance.");
    3383              :                 } else {
    3384            0 :                     ShowRecurringWarningErrorAtEnd(state,
    3385            0 :                                                    format("{} \"{}\" - Regeneration inlet air humidity ratio used in regen outlet temperature "
    3386              :                                                           "equation is out of range error continues...",
    3387            0 :                                                           state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).PerfType,
    3388            0 :                                                           state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).Name),
    3389            0 :                                                    state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_RegenInHumRatError.index,
    3390            0 :                                                    state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_RegenInHumRatError.last,
    3391            0 :                                                    state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_RegenInHumRatError.last);
    3392              :                 }
    3393              :             }
    3394              :             // Process inlet temp for temp eqn
    3395         6541 :             if (state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_ProcInTempError.print) {
    3396            3 :                 ++state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_ProcInTempError.count;
    3397            3 :                 if (state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_ProcInTempError.count < 2) {
    3398            1 :                     ShowWarningError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_ProcInTempError.buffer1);
    3399            1 :                     ShowContinueError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_ProcInTempError.buffer2);
    3400            1 :                     ShowContinueError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_ProcInTempError.buffer3);
    3401            3 :                     ShowContinueError(state,
    3402              :                                       "...Using process inlet air temperatures that are outside the regeneration outlet air temperature equation "
    3403              :                                       "model boundaries may adversely affect desiccant model performance.");
    3404              :                 } else {
    3405           16 :                     ShowRecurringWarningErrorAtEnd(
    3406              :                         state,
    3407            4 :                         format(
    3408              :                             "{} \"{}\" - Process inlet air temperature used in regen outlet temperature equation is out of range error continues...",
    3409            2 :                             state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).PerfType,
    3410            2 :                             state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).Name),
    3411            2 :                         state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_ProcInTempError.index,
    3412            2 :                         state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_ProcInTempError.last,
    3413            2 :                         state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_ProcInTempError.last);
    3414              :                 }
    3415              :             }
    3416              :             // Process inlet humidity ratio for temp eqn
    3417         6541 :             if (state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_ProcInHumRatError.print) {
    3418            0 :                 ++state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_ProcInHumRatError.count;
    3419            0 :                 if (state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_ProcInHumRatError.count < 2) {
    3420            0 :                     ShowWarningError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_ProcInHumRatError.buffer1);
    3421            0 :                     ShowContinueError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_ProcInHumRatError.buffer2);
    3422            0 :                     ShowContinueError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_ProcInHumRatError.buffer3);
    3423            0 :                     ShowContinueError(state,
    3424              :                                       "...Using process inlet air humidity ratios that are outside the regeneration outlet air temperature equation "
    3425              :                                       "model boundaries may adversely affect desiccant model performance.");
    3426              :                 } else {
    3427            0 :                     ShowRecurringWarningErrorAtEnd(state,
    3428            0 :                                                    format("{} \"{}\" - Process inlet air humidity ratio used in regen outlet temperature equation is "
    3429              :                                                           "out of range error continues...",
    3430            0 :                                                           state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).PerfType,
    3431            0 :                                                           state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).Name),
    3432            0 :                                                    state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_ProcInHumRatError.index,
    3433            0 :                                                    state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_ProcInHumRatError.last,
    3434            0 :                                                    state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_ProcInHumRatError.last);
    3435              :                 }
    3436              :             }
    3437              :             // Process and regeneration face velocity for temp eqn
    3438         6541 :             if (state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_FaceVelError.print) {
    3439            0 :                 ++state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_FaceVelError.count;
    3440            0 :                 if (state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_FaceVelError.count < 2) {
    3441            0 :                     ShowWarningError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_FaceVelError.buffer1);
    3442            0 :                     ShowContinueError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_FaceVelError.buffer2);
    3443            0 :                     ShowContinueError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_FaceVelError.buffer3);
    3444            0 :                     ShowContinueError(state,
    3445              :                                       "...Using process and regeneration face velocities that are outside the regeneration outlet air temperature "
    3446              :                                       "equation model boundaries may adversely affect desiccant model performance.");
    3447              :                 } else {
    3448            0 :                     ShowRecurringWarningErrorAtEnd(state,
    3449            0 :                                                    format("{} \"{}\" - Process and regen inlet air face velocity used in regen outlet temperature "
    3450              :                                                           "equation is out of range error continues...",
    3451            0 :                                                           state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).PerfType,
    3452            0 :                                                           state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).Name),
    3453            0 :                                                    state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_FaceVelError.index,
    3454            0 :                                                    state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_FaceVelError.last,
    3455            0 :                                                    state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_FaceVelError.last);
    3456              :                 }
    3457              :             }
    3458              :         } // IF(CurrentEndTime .GT. CurrentEndTimeLast .AND. TimeStepSys .GE. TimeStepSysLast)THEN
    3459              : 
    3460              :         //   save last system time step and last end time of current time step (used to determine if warning is valid)
    3461        97303 :         thisError.TimeStepSysLast = TimeStepSys;
    3462        97303 :         thisError.CurrentEndTimeLast = thisError.CurrentEndTime;
    3463              : 
    3464              :         //   If regen and process inlet temperatures are the same the coil is off, do not print out of bounds warning for this case
    3465        97303 :         if (std::abs(T_RegenInTemp - T_ProcInTemp) < SMALL) {
    3466          670 :             state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_RegenInTempError.print = false;
    3467          670 :             state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_RegenInHumRatError.print = false;
    3468          670 :             state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_ProcInTempError.print = false;
    3469          670 :             state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_ProcInHumRatError.print = false;
    3470          670 :             state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_FaceVelError.print = false;
    3471          670 :             return;
    3472              :         }
    3473              : 
    3474              :         //   check boundaries of independent variables and post warnings to individual buffers to print at end of time step
    3475              :         // checking model bounds for variables of regeneration outlet temperature equation
    3476              :         // Regen inlet temp
    3477       192789 :         if (T_RegenInTemp < state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_MinRegenAirInTemp ||
    3478        96156 :             T_RegenInTemp > state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_MaxRegenAirInTemp) {
    3479          477 :             state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_RegenInTempError.last = T_RegenInTemp;
    3480          477 :             thisError.OutputChar = format("{:.2R}", T_RegenInTemp);
    3481          477 :             thisError.OutputCharLo = format("{:.2R}", state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_MinRegenAirInTemp);
    3482          477 :             thisError.OutputCharHi = format("{:.2R}", state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_MaxRegenAirInTemp);
    3483          477 :             if (T_RegenInTemp < state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_MinRegenAirInTemp) {
    3484          477 :                 T_RegenInTemp = state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_MinRegenAirInTemp;
    3485              :             }
    3486          477 :             if (T_RegenInTemp > state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_MaxRegenAirInTemp) {
    3487            0 :                 T_RegenInTemp = state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_MaxRegenAirInTemp;
    3488              :             }
    3489          477 :             if (!state.dataGlobal->WarmupFlag && !FirstHVACIteration) {
    3490           31 :                 state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_RegenInTempError.print = true;
    3491           62 :                 state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_RegenInTempError.buffer1 = format(
    3492              :                     "{} \"{}\" - Regeneration inlet air temperature used in regen outlet air temperature equation is outside model boundaries at {}.",
    3493           31 :                     state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).PerfType,
    3494           31 :                     state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).Name,
    3495           62 :                     thisError.OutputChar);
    3496           31 :                 state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_RegenInTempError.buffer2 =
    3497           62 :                     format("...Valid range = {} to {}. Occurrence info = {}, {} {}",
    3498           31 :                            thisError.OutputCharLo,
    3499           31 :                            thisError.OutputCharHi,
    3500           31 :                            state.dataEnvrn->EnvironmentName,
    3501           31 :                            state.dataEnvrn->CurMnDy,
    3502           93 :                            CreateSysTimeIntervalString(state));
    3503           31 :                 thisError.CharValue = format("{:.6R}", T_RegenInTemp);
    3504           31 :                 state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_RegenInTempError.buffer3 =
    3505           62 :                     format("...Regeneration outlet air temperature equation: regeneration inlet air temperature passed to the model = {}",
    3506           62 :                            thisError.CharValue);
    3507              :             } else {
    3508          446 :                 state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_RegenInTempError.print = false;
    3509              :             }
    3510              :         } else {
    3511        96156 :             state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_RegenInTempError.print = false;
    3512              :         }
    3513              :         // regen inlet humidity ratio
    3514       193266 :         if (T_RegenInHumRat < state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_MinRegenAirInHumRat ||
    3515        96633 :             T_RegenInHumRat > state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_MaxRegenAirInHumRat) {
    3516            0 :             state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_RegenInHumRatError.last = T_RegenInHumRat;
    3517            0 :             thisError.OutputChar = format("{:.6R}", T_RegenInHumRat);
    3518            0 :             thisError.OutputCharLo = format("{:.6R}", state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_MinRegenAirInHumRat);
    3519            0 :             thisError.OutputCharHi = format("{:.6R}", state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_MaxRegenAirInHumRat);
    3520            0 :             if (T_RegenInHumRat < state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_MinRegenAirInHumRat) {
    3521            0 :                 T_RegenInHumRat = state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_MinRegenAirInHumRat;
    3522              :             }
    3523            0 :             if (T_RegenInHumRat > state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_MaxRegenAirInHumRat) {
    3524            0 :                 T_RegenInHumRat = state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_MaxRegenAirInHumRat;
    3525              :             }
    3526            0 :             if (!state.dataGlobal->WarmupFlag && !FirstHVACIteration) {
    3527            0 :                 state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_RegenInHumRatError.print = true;
    3528            0 :                 state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_RegenInHumRatError.buffer1 =
    3529            0 :                     format("{} \"{}\" - Regeneration inlet air humidity ratio used in regen outlet air temperature equation is outside model "
    3530              :                            "boundaries at {}.",
    3531            0 :                            state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).PerfType,
    3532            0 :                            state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).Name,
    3533            0 :                            thisError.OutputChar);
    3534            0 :                 state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_RegenInHumRatError.buffer2 =
    3535            0 :                     format("...Valid range = {} to {}. Occurrence info = {}, {} {}",
    3536            0 :                            thisError.OutputCharLo,
    3537            0 :                            thisError.OutputCharHi,
    3538            0 :                            state.dataEnvrn->EnvironmentName,
    3539            0 :                            state.dataEnvrn->CurMnDy,
    3540            0 :                            CreateSysTimeIntervalString(state));
    3541            0 :                 thisError.CharValue = format("{:.6R}", T_RegenInHumRat);
    3542            0 :                 state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_RegenInHumRatError.buffer3 =
    3543            0 :                     format("...Regeneration outlet air temperature equation: regeneration inlet air humidity ratio passed to the model = {}",
    3544            0 :                            thisError.CharValue);
    3545              :             } else {
    3546            0 :                 state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_RegenInHumRatError.print = false;
    3547              :             }
    3548              :         } else {
    3549        96633 :             state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_RegenInHumRatError.print = false;
    3550              :         }
    3551              :         // process inlet temp
    3552       193266 :         if (T_ProcInTemp < state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_MinProcAirInTemp ||
    3553        96633 :             T_ProcInTemp > state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_MaxProcAirInTemp) {
    3554         3037 :             state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_ProcInTempError.last = T_ProcInTemp;
    3555         3037 :             thisError.OutputChar = format("{:.2R}", T_ProcInTemp);
    3556         3037 :             thisError.OutputCharLo = format("{:.2R}", state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_MinProcAirInTemp);
    3557         3037 :             thisError.OutputCharHi = format("{:.2R}", state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_MaxProcAirInTemp);
    3558         3037 :             if (T_ProcInTemp < state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_MinProcAirInTemp) {
    3559            0 :                 T_ProcInTemp = state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_MinProcAirInTemp;
    3560              :             }
    3561         3037 :             if (T_ProcInTemp > state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_MaxProcAirInTemp) {
    3562         3037 :                 T_ProcInTemp = state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_MaxProcAirInTemp;
    3563              :             }
    3564         3037 :             if (!state.dataGlobal->WarmupFlag && !FirstHVACIteration) {
    3565          125 :                 state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_ProcInTempError.print = true;
    3566              :                 //       Suppress warning message when process inlet temperature = 0 (DX coil is off)
    3567          125 :                 if (state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_ProcInTempError.last == 0.0) {
    3568            0 :                     state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_ProcInTempError.print = false;
    3569              :                 }
    3570          250 :                 state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_ProcInTempError.buffer1 = format(
    3571              :                     "{} \"{}\" - Process inlet air temperature used in regen outlet air temperature equation is outside model boundaries at {}.",
    3572          125 :                     state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).PerfType,
    3573          125 :                     state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).Name,
    3574          250 :                     thisError.OutputChar);
    3575          125 :                 state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_ProcInTempError.buffer2 =
    3576          250 :                     format("...Valid range = {} to {}. Occurrence info = {},{} {}",
    3577          125 :                            thisError.OutputCharLo,
    3578          125 :                            thisError.OutputCharHi,
    3579          125 :                            state.dataEnvrn->EnvironmentName,
    3580          125 :                            state.dataEnvrn->CurMnDy,
    3581          375 :                            CreateSysTimeIntervalString(state));
    3582          125 :                 thisError.CharValue = format("{:.6R}", T_ProcInTemp);
    3583          250 :                 state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_ProcInTempError.buffer3 = format(
    3584          250 :                     "...Regeneration outlet air temperature equation: process inlet air temperature passed to the model = {}", thisError.CharValue);
    3585              :             } else {
    3586         2912 :                 state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_ProcInTempError.print = false;
    3587              :             }
    3588              :         } else {
    3589        93596 :             state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_ProcInTempError.print = false;
    3590              :         }
    3591              :         // process inlet humidity ratio
    3592       193246 :         if (T_ProcInHumRat < state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_MinProcAirInHumRat ||
    3593        96613 :             T_ProcInHumRat > state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_MaxProcAirInHumRat) {
    3594           28 :             state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_ProcInHumRatError.last = T_ProcInHumRat;
    3595           28 :             thisError.OutputChar = format("{:.6R}", T_ProcInHumRat);
    3596           28 :             thisError.OutputCharLo = format("{:.6R}", state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_MinProcAirInHumRat);
    3597           28 :             thisError.OutputCharHi = format("{:.6R}", state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_MaxProcAirInHumRat);
    3598           28 :             if (T_ProcInHumRat < state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_MinProcAirInHumRat) {
    3599           20 :                 T_ProcInHumRat = state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_MinProcAirInHumRat;
    3600              :             }
    3601           28 :             if (T_ProcInHumRat > state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_MaxProcAirInHumRat) {
    3602            8 :                 T_ProcInHumRat = state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_MaxProcAirInHumRat;
    3603              :             }
    3604           28 :             if (!state.dataGlobal->WarmupFlag && !FirstHVACIteration) {
    3605            1 :                 state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_ProcInHumRatError.print = true;
    3606              :                 //       Suppress warning message when process inlet humrat = 0 (DX coil is off)
    3607            1 :                 if (state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_ProcInHumRatError.last == 0.0) {
    3608            0 :                     state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_ProcInHumRatError.print = false;
    3609              :                 }
    3610            2 :                 state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_ProcInHumRatError.buffer1 = format(
    3611              :                     "{} \"{}\" - Process inlet air humidity ratio used in regen outlet air temperature equation is outside model boundaries at {}.",
    3612            1 :                     state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).PerfType,
    3613            1 :                     state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).Name,
    3614            2 :                     thisError.OutputChar);
    3615            1 :                 state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_ProcInHumRatError.buffer2 =
    3616            2 :                     format("...Valid range = {} to {}. Occurrence info = {}, {} {}",
    3617            1 :                            thisError.OutputCharLo,
    3618            1 :                            thisError.OutputCharHi,
    3619            1 :                            state.dataEnvrn->EnvironmentName,
    3620            1 :                            state.dataEnvrn->CurMnDy,
    3621            3 :                            CreateSysTimeIntervalString(state));
    3622            1 :                 thisError.CharValue = format("{:.6R}", T_ProcInHumRat);
    3623            1 :                 state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_ProcInHumRatError.buffer3 =
    3624            2 :                     format("...Regeneration outlet air temperature equation: process inlet air humidity ratio passed to the model = {}",
    3625            2 :                            thisError.CharValue);
    3626              :             } else {
    3627           27 :                 state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_ProcInHumRatError.print = false;
    3628              :             }
    3629              :         } else {
    3630        96605 :             state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_ProcInHumRatError.print = false;
    3631              :         }
    3632              :         // regeneration and process face velocity
    3633       193266 :         if (T_FaceVel < state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_MinFaceVel ||
    3634        96633 :             T_FaceVel > state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_MaxFaceVel) {
    3635            0 :             state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_FaceVelError.last = T_FaceVel;
    3636            0 :             thisError.OutputChar = format("{:.6R}", T_FaceVel);
    3637            0 :             thisError.OutputCharLo = format("{:.6R}", state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_MinFaceVel);
    3638            0 :             thisError.OutputCharHi = format("{:.6R}", state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_MaxFaceVel);
    3639            0 :             if (T_FaceVel < state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_MinFaceVel) {
    3640            0 :                 T_FaceVel = state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_MinFaceVel;
    3641              :             }
    3642            0 :             if (T_FaceVel > state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_MaxFaceVel) {
    3643            0 :                 T_FaceVel = state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_MaxFaceVel;
    3644              :             }
    3645            0 :             if (!state.dataGlobal->WarmupFlag && !FirstHVACIteration) {
    3646            0 :                 state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_FaceVelError.print = true;
    3647            0 :                 state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_FaceVelError.buffer1 =
    3648            0 :                     format("{} \"{}\" - Process and regen inlet air face velocity used in regen outlet air temperature equation is outside model "
    3649              :                            "boundaries at {}.",
    3650            0 :                            state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).PerfType,
    3651            0 :                            state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).Name,
    3652            0 :                            thisError.OutputChar);
    3653            0 :                 state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_FaceVelError.buffer2 =
    3654            0 :                     format("...Valid range = {} to {}. Occurrence info = {}, {} {}",
    3655            0 :                            thisError.OutputCharLo,
    3656            0 :                            thisError.OutputCharHi,
    3657            0 :                            state.dataEnvrn->EnvironmentName,
    3658            0 :                            state.dataEnvrn->CurMnDy,
    3659            0 :                            CreateSysTimeIntervalString(state));
    3660            0 :                 thisError.CharValue = format("{:.6R}", T_FaceVel);
    3661            0 :                 state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_FaceVelError.buffer3 = format(
    3662            0 :                     "...Regeneration outlet air temperature equation: process and regen face velocity passed to the model = {}", thisError.CharValue);
    3663              :             } else {
    3664            0 :                 state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_FaceVelError.print = false;
    3665              :             }
    3666              :         } else {
    3667        96633 :             state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_FaceVelError.print = false;
    3668              :         }
    3669              :     }
    3670              : 
    3671        97303 :     void HeatExchCond::CheckModelBoundsHumRatEq(EnergyPlusData &state,
    3672              :                                                 Real64 &H_RegenInTemp,        // current regen inlet temperature (C) for regen outlet hum rat eqn
    3673              :                                                 Real64 &H_RegenInHumRat,      // current regen inlet hum rat for regen outlet hum rat eqn
    3674              :                                                 Real64 &H_ProcInTemp,         // current process inlet temperature (C) for regen outlet hum rat eqn
    3675              :                                                 Real64 &H_ProcInHumRat,       // current process inlet hum rat for regen outlet hum rat eqn
    3676              :                                                 Real64 &H_FaceVel,            // current process and regen face velocity (m/s)
    3677              :                                                 bool const FirstHVACIteration // First HVAC iteration flag
    3678              :     ) const
    3679              :     {
    3680              : 
    3681              :         // SUBROUTINE INFORMATION:
    3682              :         //       AUTHOR         Mangesh Basarkar, FSEC
    3683              :         //       DATE WRITTEN   January 2007
    3684              :         //       MODIFIED       na
    3685              :         //       RE-ENGINEERED  na
    3686              : 
    3687              :         // PURPOSE OF THIS SUBROUTINE:
    3688              :         // To verify that the empirical model's independent variables are within the limits used during the
    3689              :         // development of the empirical model.
    3690              : 
    3691              :         // METHODOLOGY EMPLOYED:
    3692              :         // The empirical models used for simulating a desiccant enhanced cooling coil are based on a limited data set.
    3693              :         // Extrapolation of empirical models can cause instability and the independent variables may need to be limited.
    3694              :         // The range of each independent variable is provided by the user and are based on the limits of the
    3695              :         // empirical model. These limits are tested in this subroutine each time step and returned for use by the calling
    3696              :         // routine.
    3697              : 
    3698              :         // Using/Aliasing
    3699              :         using General::CreateSysTimeIntervalString;
    3700              : 
    3701              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    3702        97303 :         auto &thisError = state.dataHeatRecovery->error2;
    3703              : 
    3704        97303 :         Real64 SysTimeElapsed = state.dataHVACGlobal->SysTimeElapsed;
    3705        97303 :         Real64 TimeStepSys = state.dataHVACGlobal->TimeStepSys;
    3706              :         // current end time is compared with last to see if time step changed
    3707              : 
    3708              :         //   calculate end time of current time step
    3709        97303 :         thisError.CurrentEndTime = state.dataGlobal->CurrentTime + SysTimeElapsed;
    3710              : 
    3711              :         //   Print warning messages only when valid and only for the first occurrence. Let summary provide statistics.
    3712              :         //   Wait for next time step to print warnings. If simulation iterates, print out
    3713              :         //   the warning for the last iteration only. Must wait for next time step to accomplish this.
    3714              :         //   If a warning occurs and the simulation down shifts, the warning is not valid.
    3715        97303 :         if (thisError.CurrentEndTime > thisError.CurrentEndTimeLast && TimeStepSys >= thisError.TimeStepSysLast) {
    3716              : 
    3717              :             // print error for variables of regeneration outlet humidity ratio equation
    3718              :             // Regen inlet temp for humidity ratio eqn
    3719         6541 :             if (state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_RegenInTempError.print) {
    3720           26 :                 ++state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_RegenInTempError.count;
    3721           26 :                 if (state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_RegenInTempError.count < 2) {
    3722            1 :                     ShowWarningError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_RegenInTempError.buffer1);
    3723            1 :                     ShowContinueError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_RegenInTempError.buffer2);
    3724            1 :                     ShowContinueError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_RegenInTempError.buffer3);
    3725            3 :                     ShowContinueError(state,
    3726              :                                       "...Using regeneration inlet air temperatures that are outside the regeneration inlet air temperature equation "
    3727              :                                       "model boundaries may adversely affect desiccant model performance.");
    3728              :                 } else {
    3729          200 :                     ShowRecurringWarningErrorAtEnd(state,
    3730           50 :                                                    format("{} \"{}\" - Regeneration inlet air temperature used in regen outlet air humidity ratio "
    3731              :                                                           "equation is out of range error continues...",
    3732           25 :                                                           state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).PerfType,
    3733           25 :                                                           state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).Name),
    3734           25 :                                                    state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_RegenInTempError.index,
    3735           25 :                                                    state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_RegenInTempError.last,
    3736           25 :                                                    state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_RegenInTempError.last);
    3737              :                 }
    3738              :             }
    3739              :             // Regen inlet humidity ratio for humidity ratio eqn
    3740         6541 :             if (state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_RegenInHumRatError.print) {
    3741            0 :                 ++state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_RegenInHumRatError.count;
    3742            0 :                 if (state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_RegenInHumRatError.count < 2) {
    3743            0 :                     ShowWarningError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_RegenInHumRatError.buffer1);
    3744            0 :                     ShowContinueError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_RegenInHumRatError.buffer2);
    3745            0 :                     ShowContinueError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_RegenInHumRatError.buffer3);
    3746            0 :                     ShowContinueError(state,
    3747              :                                       "...Using regeneration inlet air humidity ratios that are outside the regeneration outlet air humidity ratio "
    3748              :                                       "equation model boundaries may adversely affect desiccant model performance.");
    3749              :                 } else {
    3750            0 :                     ShowRecurringWarningErrorAtEnd(state,
    3751            0 :                                                    format("{} \"{}\" - Regeneration inlet air humidity ratio used in regen outlet air humidity ratio "
    3752              :                                                           "equation is out of range error continues...",
    3753            0 :                                                           state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).PerfType,
    3754            0 :                                                           state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).Name),
    3755            0 :                                                    state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_RegenInHumRatError.index,
    3756            0 :                                                    state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_RegenInHumRatError.last,
    3757            0 :                                                    state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_RegenInHumRatError.last);
    3758              :                 }
    3759              :             }
    3760              :             // Process inlet temp for humidity ratio eqn
    3761         6541 :             if (state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_ProcInTempError.print) {
    3762            3 :                 ++state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_ProcInTempError.count;
    3763            3 :                 if (state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_ProcInTempError.count < 2) {
    3764            1 :                     ShowWarningError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_ProcInTempError.buffer1);
    3765            1 :                     ShowContinueError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_ProcInTempError.buffer2);
    3766            1 :                     ShowContinueError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_ProcInTempError.buffer3);
    3767            3 :                     ShowContinueError(state,
    3768              :                                       "...Using process inlet air temperatures that are outside the regeneration outlet air humidity ratio equation "
    3769              :                                       "model may adversely affect desiccant model performance.");
    3770              :                 } else {
    3771           16 :                     ShowRecurringWarningErrorAtEnd(state,
    3772            4 :                                                    format("{} \"{}\" - Process inlet air temperature used in regen outlet air humidity ratio "
    3773              :                                                           "equation is out of range error continues...",
    3774            2 :                                                           state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).PerfType,
    3775            2 :                                                           state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).Name),
    3776            2 :                                                    state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_ProcInTempError.index,
    3777            2 :                                                    state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_ProcInTempError.last,
    3778            2 :                                                    state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_ProcInTempError.last);
    3779              :                 }
    3780              :             }
    3781              :             // Process inlet humidity ratio for humidity ratio eqn
    3782         6541 :             if (state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_ProcInHumRatError.print) {
    3783            0 :                 ++state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_ProcInHumRatError.count;
    3784            0 :                 if (state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_ProcInHumRatError.count < 2) {
    3785            0 :                     ShowWarningError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_ProcInHumRatError.buffer1);
    3786            0 :                     ShowContinueError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_ProcInHumRatError.buffer2);
    3787            0 :                     ShowContinueError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_ProcInHumRatError.buffer3);
    3788            0 :                     ShowContinueError(state,
    3789              :                                       "...Using process inlet air humidity ratios that are outside the regeneration outlet humidity ratio equation "
    3790              :                                       "model boundaries may adversely affect desiccant model performance.");
    3791              :                 } else {
    3792            0 :                     ShowRecurringWarningErrorAtEnd(state,
    3793            0 :                                                    format("{} \"{}\" - Process inlet air humidity ratio used in regen outlet air humidity ratio "
    3794              :                                                           "equation is out of range error continues...",
    3795            0 :                                                           state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).PerfType,
    3796            0 :                                                           state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).Name),
    3797            0 :                                                    state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_ProcInHumRatError.index,
    3798            0 :                                                    state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_ProcInHumRatError.last,
    3799            0 :                                                    state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_ProcInHumRatError.last);
    3800              :                 }
    3801              :             }
    3802              :             // Process and regeneration face velocity for humidity ratio eqn
    3803         6541 :             if (state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_FaceVelError.print) {
    3804            0 :                 ++state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_FaceVelError.count;
    3805            0 :                 if (state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_FaceVelError.count < 2) {
    3806            0 :                     ShowWarningError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_FaceVelError.buffer1);
    3807            0 :                     ShowContinueError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_FaceVelError.buffer2);
    3808            0 :                     ShowContinueError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_FaceVelError.buffer3);
    3809            0 :                     ShowContinueError(state,
    3810              :                                       "...Using process and regeneration face velocities that are outside the regeneration outlet air humidity ratio "
    3811              :                                       "equation model boundaries may adversely affect desiccant model performance.");
    3812              :                 } else {
    3813            0 :                     ShowRecurringWarningErrorAtEnd(state,
    3814            0 :                                                    format("{} \"{}\" - Process and regen face velocity used in regen outlet air humidity ratio "
    3815              :                                                           "equation is out of range error continues...",
    3816            0 :                                                           state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).PerfType,
    3817            0 :                                                           state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).Name),
    3818            0 :                                                    state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_FaceVelError.index,
    3819            0 :                                                    state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_FaceVelError.last,
    3820            0 :                                                    state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_FaceVelError.last);
    3821              :                 }
    3822              :             }
    3823              :         } // IF(CurrentEndTime .GT. CurrentEndTimeLast .AND. TimeStepSys .GE. TimeStepSysLast)THEN
    3824              : 
    3825              :         //   save last system time step and last end time of current time step (used to determine if warning is valid)
    3826        97303 :         thisError.TimeStepSysLast = TimeStepSys;
    3827        97303 :         thisError.CurrentEndTimeLast = thisError.CurrentEndTime;
    3828              : 
    3829              :         //   If regen and process inlet temperatures are the same the coil is off, do not print out of bounds warning for this case
    3830        97303 :         if (std::abs(H_RegenInTemp - H_ProcInTemp) < SMALL) {
    3831          670 :             state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_RegenInTempError.print = false;
    3832          670 :             state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_RegenInHumRatError.print = false;
    3833          670 :             state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_ProcInTempError.print = false;
    3834          670 :             state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_ProcInHumRatError.print = false;
    3835          670 :             state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_FaceVelError.print = false;
    3836          670 :             return;
    3837              :         }
    3838              : 
    3839              :         //   check boundaries of independent variables and post warnings to individual buffers to print at end of time step
    3840              :         // checking model bounds for variables of regeneration outlet humidity ratio equation
    3841              :         // Regen inlet temp
    3842       192789 :         if (H_RegenInTemp < state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_MinRegenAirInTemp ||
    3843        96156 :             H_RegenInTemp > state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_MaxRegenAirInTemp) {
    3844          477 :             state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_RegenInTempError.last = H_RegenInTemp;
    3845          477 :             thisError.OutputChar = format("{:.2R}", H_RegenInTemp);
    3846          477 :             thisError.OutputCharLo = format("{:.2R}", state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_MinRegenAirInTemp);
    3847          477 :             thisError.OutputCharHi = format("{:.2R}", state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_MaxRegenAirInTemp);
    3848          477 :             if (H_RegenInTemp < state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_MinRegenAirInTemp) {
    3849          477 :                 H_RegenInTemp = state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_MinRegenAirInTemp;
    3850              :             }
    3851          477 :             if (H_RegenInTemp > state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_MaxRegenAirInTemp) {
    3852            0 :                 H_RegenInTemp = state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_MaxRegenAirInTemp;
    3853              :             }
    3854          477 :             if (!state.dataGlobal->WarmupFlag && !FirstHVACIteration) {
    3855           31 :                 state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_RegenInTempError.print = true;
    3856           31 :                 state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_RegenInTempError.buffer1 =
    3857           62 :                     format("{} \"{}\" - Regeneration inlet air temperature used in regen outlet air humidity ratio equation is outside model "
    3858              :                            "boundaries at {}.",
    3859           31 :                            state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).PerfType,
    3860           31 :                            state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).Name,
    3861           62 :                            thisError.OutputChar);
    3862           31 :                 state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_RegenInTempError.buffer2 =
    3863           62 :                     format("...Valid range = {} to {}. Occurrence info = {}, {} , {}",
    3864           31 :                            thisError.OutputCharLo,
    3865           31 :                            thisError.OutputCharHi,
    3866           31 :                            state.dataEnvrn->EnvironmentName,
    3867           31 :                            state.dataEnvrn->CurMnDy,
    3868           93 :                            CreateSysTimeIntervalString(state));
    3869           31 :                 thisError.CharValue = format("{:.2R}", H_RegenInTemp);
    3870           31 :                 state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_RegenInTempError.buffer3 =
    3871           62 :                     format("...Regeneration outlet air humidity ratio equation: regeneration inlet air temperature passed to the model = {}",
    3872           62 :                            thisError.CharValue);
    3873              :             } else {
    3874          446 :                 state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_RegenInTempError.print = false;
    3875              :             }
    3876              :         } else {
    3877        96156 :             state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_RegenInTempError.print = false;
    3878              :         }
    3879              :         // regen inlet humidity ratio
    3880       193266 :         if (H_RegenInHumRat < state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_MinRegenAirInHumRat ||
    3881        96633 :             H_RegenInHumRat > state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_MaxRegenAirInHumRat) {
    3882            0 :             state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_RegenInHumRatError.last = H_RegenInHumRat;
    3883            0 :             thisError.OutputChar = format("{:.6R}", H_RegenInHumRat);
    3884            0 :             thisError.OutputCharLo = format("{:.6R}", state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_MinRegenAirInHumRat);
    3885            0 :             thisError.OutputCharHi = format("{:.6R}", state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_MaxRegenAirInHumRat);
    3886            0 :             if (H_RegenInHumRat < state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_MinRegenAirInHumRat) {
    3887            0 :                 H_RegenInHumRat = state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_MinRegenAirInHumRat;
    3888              :             }
    3889            0 :             if (H_RegenInHumRat > state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_MaxRegenAirInHumRat) {
    3890            0 :                 H_RegenInHumRat = state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_MaxRegenAirInHumRat;
    3891              :             }
    3892            0 :             if (!state.dataGlobal->WarmupFlag && !FirstHVACIteration) {
    3893            0 :                 state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_RegenInHumRatError.print = true;
    3894            0 :                 state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_RegenInHumRatError.buffer1 =
    3895            0 :                     format("{} \"{}\" - Regeneration inlet air humidity ratio used in regen outlet air humidity ratio equation is outside model "
    3896              :                            "boundaries at {}.",
    3897            0 :                            state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).PerfType,
    3898            0 :                            state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).Name,
    3899            0 :                            thisError.OutputChar);
    3900            0 :                 state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_RegenInHumRatError.buffer2 =
    3901            0 :                     format("...Valid range = {} to {}. Occurrence info = {}, {} {}",
    3902            0 :                            thisError.OutputCharLo,
    3903            0 :                            thisError.OutputCharHi,
    3904            0 :                            state.dataEnvrn->EnvironmentName,
    3905            0 :                            state.dataEnvrn->CurMnDy,
    3906            0 :                            CreateSysTimeIntervalString(state));
    3907            0 :                 thisError.CharValue = format("{:.6R}", H_RegenInHumRat);
    3908            0 :                 state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_RegenInHumRatError.buffer3 =
    3909            0 :                     format("...Regeneration outlet air humidity ratio equation: regeneration inlet air humidity ratio passed to the model = {}",
    3910            0 :                            thisError.CharValue);
    3911              :             } else {
    3912            0 :                 state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_RegenInHumRatError.print = false;
    3913              :             }
    3914              :         } else {
    3915        96633 :             state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_RegenInHumRatError.print = false;
    3916              :         }
    3917              :         // process inlet temp
    3918       193266 :         if (H_ProcInTemp < state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_MinProcAirInTemp ||
    3919        96633 :             H_ProcInTemp > state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_MaxProcAirInTemp) {
    3920         3037 :             state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_ProcInTempError.last = H_ProcInTemp;
    3921         3037 :             thisError.OutputChar = format("{:.2R}", H_ProcInTemp);
    3922         3037 :             thisError.OutputCharLo = format("{:.2R}", state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_MinProcAirInTemp);
    3923         3037 :             thisError.OutputCharHi = format("{:.2R}", state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_MaxProcAirInTemp);
    3924         3037 :             if (H_ProcInTemp < state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_MinProcAirInTemp) {
    3925            0 :                 H_ProcInTemp = state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_MinProcAirInTemp;
    3926              :             }
    3927         3037 :             if (H_ProcInTemp > state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_MaxProcAirInTemp) {
    3928         3037 :                 H_ProcInTemp = state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_MaxProcAirInTemp;
    3929              :             }
    3930         3037 :             if (!state.dataGlobal->WarmupFlag && !FirstHVACIteration) {
    3931          125 :                 state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_ProcInTempError.print = true;
    3932              :                 //       Suppress warning message when process inlet temperature = 0 (DX coil is off)
    3933          125 :                 if (state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_ProcInTempError.last == 0.0) {
    3934            0 :                     state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_ProcInTempError.print = false;
    3935              :                 }
    3936          250 :                 state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_ProcInTempError.buffer1 = format(
    3937              :                     "{} \"{}\" - Process inlet air temperature used in regen outlet air humidity ratio equation is outside model boundaries at {}.",
    3938          125 :                     state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).PerfType,
    3939          125 :                     state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).Name,
    3940          250 :                     thisError.OutputChar);
    3941          125 :                 state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_ProcInTempError.buffer2 =
    3942          250 :                     format("...Valid range = {} to {}. Occurrence info = {}, {} {}",
    3943          125 :                            thisError.OutputCharLo,
    3944          125 :                            thisError.OutputCharHi,
    3945          125 :                            state.dataEnvrn->EnvironmentName,
    3946          125 :                            state.dataEnvrn->CurMnDy,
    3947          375 :                            CreateSysTimeIntervalString(state));
    3948          125 :                 thisError.CharValue = format("{:.6R}", H_ProcInTemp);
    3949          125 :                 state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_ProcInTempError.buffer3 =
    3950          250 :                     format("...Regeneration outlet air humidity ratio equation: process inlet air temperature passed to the model = {}",
    3951          250 :                            thisError.CharValue);
    3952              :             } else {
    3953         2912 :                 state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_ProcInTempError.print = false;
    3954              :             }
    3955              :         } else {
    3956        93596 :             state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_ProcInTempError.print = false;
    3957              :         }
    3958              :         // process inlet humidity ratio
    3959       193246 :         if (H_ProcInHumRat < state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_MinProcAirInHumRat ||
    3960        96613 :             H_ProcInHumRat > state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_MaxProcAirInHumRat) {
    3961           28 :             state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_ProcInHumRatError.last = H_ProcInHumRat;
    3962           28 :             thisError.OutputChar = format("{:.6R}", H_ProcInHumRat);
    3963           28 :             thisError.OutputCharLo = format("{:.6R}", state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_MinProcAirInHumRat);
    3964           28 :             thisError.OutputCharHi = format("{:.6R}", state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_MaxProcAirInHumRat);
    3965           28 :             if (H_ProcInHumRat < state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_MinProcAirInHumRat) {
    3966           20 :                 H_ProcInHumRat = state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_MinProcAirInHumRat;
    3967              :             }
    3968           28 :             if (H_ProcInHumRat > state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_MaxProcAirInHumRat) {
    3969            8 :                 H_ProcInHumRat = state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_MaxProcAirInHumRat;
    3970              :             }
    3971           28 :             if (!state.dataGlobal->WarmupFlag && !FirstHVACIteration) {
    3972            1 :                 state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_ProcInHumRatError.print = true;
    3973              :                 //       Suppress warning message when process inlet humrat = 0 (DX coil is off)
    3974            1 :                 if (state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_ProcInHumRatError.last == 0.0) {
    3975            0 :                     state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_ProcInHumRatError.print = false;
    3976              :                 }
    3977            1 :                 state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_ProcInHumRatError.buffer1 =
    3978            2 :                     format("{} \"{}\" - Process inlet air humidity ratio used in regen outlet air humidity ratio equation is outside model "
    3979              :                            "boundaries at {}.",
    3980            1 :                            state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).PerfType,
    3981            1 :                            state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).Name,
    3982            2 :                            thisError.OutputChar);
    3983            1 :                 state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_ProcInHumRatError.buffer2 =
    3984            2 :                     format("...Valid range = {} to {}. Occurrence info = {}, {}, {}",
    3985            1 :                            thisError.OutputCharLo,
    3986            1 :                            thisError.OutputCharHi,
    3987            1 :                            state.dataEnvrn->EnvironmentName,
    3988            1 :                            state.dataEnvrn->CurMnDy,
    3989            3 :                            CreateSysTimeIntervalString(state));
    3990            1 :                 thisError.CharValue = format("{:.6R}", H_ProcInHumRat);
    3991            1 :                 state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_ProcInHumRatError.buffer3 =
    3992            2 :                     format("...Regeneration outlet air humidity ratio equation: process inlet air humidity ratio passed to the model = {}",
    3993            2 :                            thisError.CharValue);
    3994              :             } else {
    3995           27 :                 state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_ProcInHumRatError.print = false;
    3996              :             }
    3997              :         } else {
    3998        96605 :             state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_ProcInHumRatError.print = false;
    3999              :         }
    4000              :         // regeneration and process face velocity
    4001       193266 :         if (H_FaceVel < state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_MinFaceVel ||
    4002        96633 :             H_FaceVel > state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_MaxFaceVel) {
    4003            0 :             state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_FaceVelError.last = H_FaceVel;
    4004            0 :             thisError.OutputChar = format("{:.6R}", H_FaceVel);
    4005            0 :             thisError.OutputCharLo = format("{:.6R}", state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_MinFaceVel);
    4006            0 :             thisError.OutputCharHi = format("{:.6R}", state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_MaxFaceVel);
    4007            0 :             if (H_FaceVel < state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_MinFaceVel) {
    4008            0 :                 H_FaceVel = state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_MinFaceVel;
    4009              :             }
    4010            0 :             if (H_FaceVel > state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_MaxFaceVel) {
    4011            0 :                 H_FaceVel = state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_MaxFaceVel;
    4012              :             }
    4013            0 :             if (!state.dataGlobal->WarmupFlag && !FirstHVACIteration) {
    4014            0 :                 state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_FaceVelError.print = true;
    4015            0 :                 state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_FaceVelError.buffer1 =
    4016            0 :                     format("{} \"{}\" - Process and regen inlet air face velocity used in regen outlet air humidity ratio equation is outside model "
    4017              :                            "boundaries at {}.",
    4018            0 :                            state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).PerfType,
    4019            0 :                            state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).Name,
    4020            0 :                            thisError.OutputChar);
    4021            0 :                 state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_FaceVelError.buffer2 =
    4022            0 :                     format("...Valid range = {} to {}. Occurrence info = {}, {}, {}",
    4023            0 :                            thisError.OutputCharLo,
    4024            0 :                            thisError.OutputCharHi,
    4025            0 :                            state.dataEnvrn->EnvironmentName,
    4026            0 :                            state.dataEnvrn->CurMnDy,
    4027            0 :                            CreateSysTimeIntervalString(state));
    4028            0 :                 thisError.CharValue = format("{:.6R}", H_FaceVel);
    4029            0 :                 state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_FaceVelError.buffer3 =
    4030            0 :                     format("...Regeneration outlet air humidity ratio equation: process and regeneration face velocity passed to the model = {}",
    4031            0 :                            thisError.CharValue);
    4032              :             } else {
    4033            0 :                 state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_FaceVelError.print = false;
    4034              :             }
    4035              :         } else {
    4036        96633 :             state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_FaceVelError.print = false;
    4037              :         }
    4038              :     }
    4039              : 
    4040        97303 :     void HeatExchCond::CheckModelBoundOutput_Temp(EnergyPlusData &state,
    4041              :                                                   Real64 const RegenInTemp,     // current regen inlet temp passed to eqn
    4042              :                                                   Real64 &RegenOutTemp,         // current regen outlet temp from eqn
    4043              :                                                   bool const FirstHVACIteration // First HVAC iteration flag
    4044              :     ) const
    4045              :     {
    4046              : 
    4047              :         // SUBROUTINE INFORMATION:
    4048              :         //       AUTHOR         Mangesh Basarkar, FSEC
    4049              :         //       DATE WRITTEN   January 2007
    4050              :         //       MODIFIED       June 2007, R. Raustad, changed requirement that regen outlet temp be less than inlet temp
    4051              :         //       RE-ENGINEERED  na
    4052              : 
    4053              :         // PURPOSE OF THIS SUBROUTINE:
    4054              :         // To verify that the empirical model's independent variables are within the limits used during the
    4055              :         // development of the empirical model.
    4056              : 
    4057              :         // METHODOLOGY EMPLOYED:
    4058              :         // The empirical models used for simulating a desiccant enhanced cooling coil are based on a limited data set.
    4059              :         // Extrapolation of empirical models can cause instability and the independent variables may need to be limited.
    4060              :         // The range of each independent variable is provided by the user and are based on the limits of the
    4061              :         // empirical model. These limits are tested in this subroutine each time step and returned for use by the calling
    4062              :         // routine.
    4063              : 
    4064              :         // Using/Aliasing
    4065              :         using General::CreateSysTimeIntervalString;
    4066              : 
    4067              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    4068        97303 :         auto &thisError = state.dataHeatRecovery->error3;
    4069              : 
    4070        97303 :         Real64 SysTimeElapsed = state.dataHVACGlobal->SysTimeElapsed;
    4071        97303 :         Real64 TimeStepSys = state.dataHVACGlobal->TimeStepSys;
    4072              :         // current end time is compared with last to see if time step changed
    4073              : 
    4074              :         //   calculate end time of current time step
    4075        97303 :         thisError.CurrentEndTime = state.dataGlobal->CurrentTime + SysTimeElapsed;
    4076              : 
    4077              :         //   Print warning messages only when valid and only for the first occurrence. Let summary provide statistics.
    4078              :         //   Wait for next time step to print warnings. If simulation iterates, print out
    4079              :         //   the warning for the last iteration only. Must wait for next time step to accomplish this.
    4080              :         //   If a warning occurs and the simulation down shifts, the warning is not valid.
    4081        97303 :         if (thisError.CurrentEndTime > thisError.CurrentEndTimeLast && TimeStepSys >= thisError.TimeStepSysLast) {
    4082              : 
    4083              :             // print error when regeneration outlet temperature is greater than regen inlet temperature
    4084         6541 :             if (state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutTempFailedError.print) {
    4085           26 :                 ++state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutTempFailedError.count;
    4086           26 :                 if (state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutTempFailedError.count < 2) {
    4087            1 :                     ShowWarningError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutTempFailedError.buffer1);
    4088            1 :                     ShowContinueError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutTempFailedError.buffer2);
    4089            3 :                     ShowContinueError(state,
    4090              :                                       "...Regeneration outlet air temperature should always be less than or equal to regen inlet air temperature. "
    4091              :                                       "Verify correct model coefficients.");
    4092              :                 } else {
    4093          200 :                     ShowRecurringWarningErrorAtEnd(
    4094              :                         state,
    4095           50 :                         format("{} \"{}\" - Regeneration outlet air temperature above regen inlet air temperature error continues...",
    4096           25 :                                state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).PerfType,
    4097           25 :                                state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).Name),
    4098           25 :                         state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutTempFailedError.index,
    4099           25 :                         state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutTempFailedError.last,
    4100           25 :                         state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutTempFailedError.last);
    4101              :                 }
    4102              :             }
    4103              : 
    4104              :             // print error for variables of regeneration outlet temperature
    4105         6541 :             if (state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutTempError.print) {
    4106            0 :                 ++state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutTempError.count;
    4107            0 :                 if (state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutTempError.count < 2) {
    4108            0 :                     ShowWarningError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutTempError.buffer1);
    4109            0 :                     ShowContinueError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutTempError.buffer2);
    4110            0 :                     ShowContinueError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutTempError.buffer3);
    4111            0 :                     ShowContinueError(state,
    4112              :                                       "...Regeneration outlet air temperature should always be less than or equal to regen inlet air temperature. "
    4113              :                                       "Verify correct model coefficients.");
    4114              :                 } else {
    4115            0 :                     ShowRecurringWarningErrorAtEnd(
    4116              :                         state,
    4117            0 :                         format("{} \"{}\" - Regeneration outlet air temperature should be less than regen inlet air temperature error continues...",
    4118            0 :                                state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).PerfType,
    4119            0 :                                state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).Name),
    4120            0 :                         state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutTempError.index,
    4121            0 :                         state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutTempError.last,
    4122            0 :                         state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutTempError.last);
    4123              :                 }
    4124              :             }
    4125              :         } // IF(CurrentEndTime .GT. CurrentEndTimeLast .AND. TimeStepSys .GE. TimeStepSysLast)THEN
    4126              : 
    4127              :         //   save last system time step and last end time of current time step (used to determine if warning is valid)
    4128        97303 :         thisError.TimeStepSysLast = TimeStepSys;
    4129        97303 :         thisError.CurrentEndTimeLast = thisError.CurrentEndTime;
    4130              : 
    4131              :         // checking model regeneration outlet temperature to always be less than or equal to regeneration inlet temperature
    4132        97303 :         if (RegenOutTemp > RegenInTemp) {
    4133          473 :             state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutTempFailedError.last = RegenOutTemp;
    4134          473 :             thisError.OutputChar = format("{:.2R}", RegenOutTemp);
    4135          473 :             thisError.OutputCharHi = format("{:.2R}", RegenInTemp);
    4136              :             //      IF(RegenOutTemp .GT. RegenInTemp)THEN
    4137              :             //        RegenOutTemp = RegenInTemp
    4138              :             //      END IF
    4139          473 :             if (!state.dataGlobal->WarmupFlag && !FirstHVACIteration) {
    4140           31 :                 state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutTempFailedError.print = true;
    4141           31 :                 state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutTempFailedError.buffer1 =
    4142           62 :                     format("{} \"{}\" - Regeneration outlet air temperature is greater than inlet temperature at {}.",
    4143           31 :                            state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).PerfType,
    4144           31 :                            state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).Name,
    4145           62 :                            thisError.OutputChar);
    4146           31 :                 state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutTempFailedError.buffer2 =
    4147           62 :                     format("...Regen inlet air temperature = {}. Occurrence info = {}, {}, {}",
    4148           31 :                            thisError.OutputCharHi,
    4149           31 :                            state.dataEnvrn->EnvironmentName,
    4150           31 :                            state.dataEnvrn->CurMnDy,
    4151           93 :                            CreateSysTimeIntervalString(state));
    4152           31 :                 thisError.CharValue = format("{:.6R}", RegenOutTemp);
    4153           62 :                 state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutTempFailedError.buffer3 = format(
    4154           62 :                     "...Regen outlet air temperature equation: regeneration outlet air temperature allowed from the model = {}", thisError.CharValue);
    4155              :             } else {
    4156          442 :                 state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutTempError.print = false;
    4157              :             }
    4158              :         } else {
    4159        96830 :             state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutTempError.print = false;
    4160              :         }
    4161              : 
    4162              :         //   check boundaries of regen outlet temperature and post warnings to individual buffers to print at end of time step
    4163              :         // checking model bounds for regeneration outlet temperature
    4164       194606 :         if (RegenOutTemp < state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).MinRegenAirOutTemp ||
    4165        97303 :             RegenOutTemp > state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).MaxRegenAirOutTemp) {
    4166            0 :             state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutTempError.last = RegenOutTemp;
    4167            0 :             thisError.OutputChar = format("{:.2R}", RegenOutTemp);
    4168            0 :             thisError.OutputCharLo = format("{:.2R}", state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).MinRegenAirOutTemp);
    4169            0 :             thisError.OutputCharHi = format("{:.2R}", state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).MaxRegenAirOutTemp);
    4170            0 :             if (RegenOutTemp < state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).MinRegenAirOutTemp) {
    4171            0 :                 RegenOutTemp = state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).MinRegenAirOutTemp;
    4172              :             }
    4173            0 :             if (RegenOutTemp > state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).MaxRegenAirOutTemp) {
    4174            0 :                 RegenOutTemp = state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).MaxRegenAirOutTemp;
    4175              :             }
    4176            0 :             if (!state.dataGlobal->WarmupFlag && !FirstHVACIteration) {
    4177            0 :                 state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutTempError.print = true;
    4178            0 :                 state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutTempError.buffer1 =
    4179            0 :                     format("{} \"{}\" - Regeneration outlet air temperature equation is outside model boundaries at {}.",
    4180            0 :                            state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).PerfType,
    4181            0 :                            state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).Name,
    4182            0 :                            thisError.OutputChar);
    4183            0 :                 state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutTempError.buffer2 =
    4184            0 :                     format("...Valid range = {} to {}. Occurrence info = {}, {}, {}",
    4185            0 :                            thisError.OutputCharLo,
    4186            0 :                            thisError.OutputCharHi,
    4187            0 :                            state.dataEnvrn->EnvironmentName,
    4188            0 :                            state.dataEnvrn->CurMnDy,
    4189            0 :                            CreateSysTimeIntervalString(state));
    4190            0 :                 thisError.CharValue = format("{:.6R}", RegenOutTemp);
    4191            0 :                 state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutTempError.buffer3 = format(
    4192            0 :                     "...Regen outlet air temperature equation: regeneration outlet air temperature allowed from the model = {}", thisError.CharValue);
    4193              :             } else {
    4194            0 :                 state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutTempError.print = false;
    4195              :             }
    4196              :         } else {
    4197        97303 :             state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutTempError.print = false;
    4198              :         }
    4199        97303 :     }
    4200              : 
    4201        97303 :     void HeatExchCond::CheckModelBoundOutput_HumRat(EnergyPlusData &state,
    4202              :                                                     Real64 const RegenInHumRat,   // current regen inlet hum rat passed to eqn
    4203              :                                                     Real64 &RegenOutHumRat,       // current regen outlet hum rat from eqn
    4204              :                                                     bool const FirstHVACIteration // First HVAC iteration flag
    4205              :     ) const
    4206              :     {
    4207              : 
    4208              :         // SUBROUTINE INFORMATION:
    4209              :         //       AUTHOR         Mangesh Basarkar, FSEC
    4210              :         //       DATE WRITTEN   January 2007
    4211              :         //       MODIFIED       June 2007, R. Raustad, changed requirement that regen outlet temp be less than inlet temp
    4212              :         //       RE-ENGINEERED  na
    4213              : 
    4214              :         // PURPOSE OF THIS SUBROUTINE:
    4215              :         // To verify that the empirical model's independent variables are within the limits used during the
    4216              :         // development of the empirical model.
    4217              : 
    4218              :         // METHODOLOGY EMPLOYED:
    4219              :         // The empirical models used for simulating a desiccant enhanced cooling coil are based on a limited data set.
    4220              :         // Extrapolation of empirical models can cause instability and the independent variables may need to be limited.
    4221              :         // The range of each independent variable is provided by the user and are based on the limits of the
    4222              :         // empirical model. These limits are tested in this subroutine each time step and returned for use by the calling
    4223              :         // routine.
    4224              :         // REFERENCES:
    4225              :         // na
    4226              : 
    4227              :         // Using/Aliasing
    4228              :         using General::CreateSysTimeIntervalString;
    4229              : 
    4230              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    4231        97303 :         auto &thisError = state.dataHeatRecovery->error4; // (THIS_AUTO_OK)
    4232              : 
    4233        97303 :         Real64 SysTimeElapsed = state.dataHVACGlobal->SysTimeElapsed;
    4234        97303 :         Real64 TimeStepSys = state.dataHVACGlobal->TimeStepSys;
    4235              : 
    4236              :         // current end time is compared with last to see if time step changed
    4237              : 
    4238              :         //   calculate end time of current time step
    4239        97303 :         thisError.CurrentEndTime = state.dataGlobal->CurrentTime + SysTimeElapsed;
    4240              : 
    4241              :         //   Print warning messages only when valid and only for the first occurrence. Let summary provide statistics.
    4242              :         //   Wait for next time step to print warnings. If simulation iterates, print out
    4243              :         //   the warning for the last iteration only. Must wait for next time step to accomplish this.
    4244              :         //   If a warning occurs and the simulation down shifts, the warning is not valid.
    4245        97303 :         if (thisError.CurrentEndTime > thisError.CurrentEndTimeLast && TimeStepSys >= thisError.TimeStepSysLast) {
    4246              : 
    4247              :             // print error when regeneration outlet humidity ratio is less than regeneration inlet humidity ratio
    4248         6541 :             if (state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutHumRatFailedErr.print) {
    4249            0 :                 ++state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutHumRatFailedErr.count;
    4250            0 :                 if (state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutHumRatFailedErr.count < 2) {
    4251            0 :                     ShowWarningError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutHumRatFailedErr.buffer1);
    4252            0 :                     ShowContinueError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutHumRatFailedErr.buffer2);
    4253            0 :                     ShowContinueError(state,
    4254              :                                       "...Regeneration outlet air humidity ratio should always be greater than or equal to regen inlet air humidity "
    4255              :                                       "ratio. Verify correct model coefficients.");
    4256              :                 } else {
    4257            0 :                     ShowRecurringWarningErrorAtEnd(state,
    4258            0 :                                                    format("{} \"{}\" - Regeneration outlet air humidity ratio should be greater than regen inlet air "
    4259              :                                                           "humidity ratio error continues...",
    4260            0 :                                                           state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).PerfType,
    4261            0 :                                                           state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).Name),
    4262            0 :                                                    state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutHumRatFailedErr.index,
    4263            0 :                                                    state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutHumRatFailedErr.last,
    4264            0 :                                                    state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutHumRatFailedErr.last);
    4265              :                 }
    4266              :             }
    4267              : 
    4268              :             // print error for regeneration outlet humidity ratio
    4269         6541 :             if (state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutHumRatError.print) {
    4270            0 :                 ++state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutHumRatError.count;
    4271            0 :                 if (state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutHumRatError.count < 2) {
    4272            0 :                     ShowWarningError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutHumRatError.buffer1);
    4273            0 :                     ShowContinueError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutHumRatError.buffer2);
    4274            0 :                     ShowContinueError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutHumRatError.buffer3);
    4275            0 :                     ShowContinueError(
    4276              :                         state,
    4277              :                         "...Regeneration outlet air humidity ratio outside model boundaries may adversely affect desiccant model performance.");
    4278              :                 } else {
    4279            0 :                     ShowRecurringWarningErrorAtEnd(state,
    4280            0 :                                                    format("{} \"{}\" - Regeneration outlet air humidity ratio is out of range error continues...",
    4281            0 :                                                           state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).PerfType,
    4282            0 :                                                           state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).Name),
    4283            0 :                                                    state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutHumRatError.index,
    4284            0 :                                                    state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutHumRatError.last,
    4285            0 :                                                    state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutHumRatError.last);
    4286              :                 }
    4287              :             }
    4288              :         } // IF(CurrentEndTime .GT. CurrentEndTimeLast .AND. TimeStepSys .GE. TimeStepSysLast)THEN
    4289              : 
    4290              :         //   save last system time step and last end time of current time step (used to determine if warning is valid)
    4291        97303 :         thisError.TimeStepSysLast = TimeStepSys;
    4292        97303 :         thisError.CurrentEndTimeLast = thisError.CurrentEndTime;
    4293              : 
    4294              :         // checking for regeneration outlet humidity ratio less than or equal to regeneration inlet humidity ratio
    4295        97303 :         if (RegenOutHumRat < RegenInHumRat) {
    4296            0 :             state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutHumRatFailedErr.last = RegenOutHumRat;
    4297            0 :             thisError.OutputChar = format("{:.6R}", RegenOutHumRat);
    4298            0 :             thisError.OutputCharHi = format("{:.6R}", RegenInHumRat);
    4299              :             //      IF(RegenOutHumRat .LT. RegenInHumRat)THEN
    4300              :             //        RegenOutHumRat = RegenInHumRat
    4301              :             //      END IF
    4302            0 :             if (!state.dataGlobal->WarmupFlag && !FirstHVACIteration) {
    4303            0 :                 state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutHumRatFailedErr.print = true;
    4304            0 :                 state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutHumRatFailedErr.buffer1 =
    4305            0 :                     format("{} \"{}\" - Regeneration outlet air humidity ratio is less than the inlet air humidity ratio at {}.",
    4306            0 :                            state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).PerfType,
    4307            0 :                            state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).Name,
    4308            0 :                            thisError.OutputChar);
    4309            0 :                 state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutHumRatFailedErr.buffer2 =
    4310            0 :                     format("...Regen inlet air humidity ratio = {}. Occurrence info = {}, {}, {}",
    4311            0 :                            thisError.OutputCharHi,
    4312            0 :                            state.dataEnvrn->EnvironmentName,
    4313            0 :                            state.dataEnvrn->CurMnDy,
    4314            0 :                            CreateSysTimeIntervalString(state));
    4315            0 :                 thisError.CharValue = format("{:.6R}", RegenOutHumRat);
    4316            0 :                 state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutHumRatFailedErr.buffer3 =
    4317            0 :                     format("...Regen outlet air humidity ratio equation: regeneration outlet air humidity ratio allowed from the model = {}",
    4318            0 :                            thisError.CharValue);
    4319              :             } else {
    4320            0 :                 state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutHumRatFailedErr.print = false;
    4321              :             }
    4322              :         } else {
    4323        97303 :             state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutHumRatFailedErr.print = false;
    4324              :         }
    4325              : 
    4326              :         //   check boundaries of regen outlet humrat and post warnings to individual buffers to print at end of time step
    4327              :         // checking model bounds for regeneration outlet humidity ratio
    4328       194606 :         if (RegenOutHumRat < state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).MinRegenAirOutHumRat ||
    4329        97303 :             RegenOutHumRat > state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).MaxRegenAirOutHumRat) {
    4330            0 :             state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutHumRatError.last = RegenOutHumRat;
    4331            0 :             thisError.OutputChar = format("{:.6R}", RegenOutHumRat);
    4332            0 :             thisError.OutputCharLo = format("{:.6R}", state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).MinRegenAirOutHumRat);
    4333            0 :             thisError.OutputCharHi = format("{:.6R}", state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).MaxRegenAirOutHumRat);
    4334            0 :             if (RegenOutHumRat < state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).MinRegenAirOutHumRat) {
    4335            0 :                 RegenOutHumRat = state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).MinRegenAirOutHumRat;
    4336              :             }
    4337            0 :             if (RegenOutHumRat > state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).MaxRegenAirOutHumRat) {
    4338            0 :                 RegenOutHumRat = state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).MaxRegenAirOutHumRat;
    4339              :             }
    4340            0 :             if (!state.dataGlobal->WarmupFlag && !FirstHVACIteration) {
    4341            0 :                 state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutHumRatError.print = true;
    4342            0 :                 state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutHumRatError.buffer1 =
    4343            0 :                     format("{} \"{}\" - Regeneration outlet air humidity ratio is outside model boundaries at {}.",
    4344            0 :                            state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).PerfType,
    4345            0 :                            state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).Name,
    4346            0 :                            thisError.OutputChar);
    4347            0 :                 state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutHumRatError.buffer2 =
    4348            0 :                     format("...Valid range = {} to {}. Occurrence info = {}, {}, {}",
    4349            0 :                            thisError.OutputCharLo,
    4350            0 :                            thisError.OutputCharHi,
    4351            0 :                            state.dataEnvrn->EnvironmentName,
    4352            0 :                            state.dataEnvrn->CurMnDy,
    4353            0 :                            CreateSysTimeIntervalString(state));
    4354            0 :                 thisError.CharValue = format("{:.6R}", RegenOutHumRat);
    4355            0 :                 state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutHumRatError.buffer3 =
    4356            0 :                     format("...Regen outlet air humidity ratio equation: regeneration outlet air humidity ratio allowed from the model = {}",
    4357            0 :                            thisError.CharValue);
    4358              :             } else {
    4359            0 :                 state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutHumRatError.print = false;
    4360              :             }
    4361              :         } else {
    4362        97303 :             state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutHumRatError.print = false;
    4363              :         }
    4364        97303 :     }
    4365              : 
    4366        97303 :     void HeatExchCond::CheckModelBoundsRH_TempEq(EnergyPlusData &state,
    4367              :                                                  Real64 const T_RegenInTemp,   // current regen inlet temperature passed to eqn
    4368              :                                                  Real64 const T_RegenInHumRat, // current regen inlet hum rat passed to eqn
    4369              :                                                  Real64 const T_ProcInTemp,    // current process inlet temperature passed to eqn
    4370              :                                                  Real64 const T_ProcInHumRat,  // current regen outlet hum rat from eqn
    4371              :                                                  bool const FirstHVACIteration // first HVAC iteration flag
    4372              :     ) const
    4373              :     {
    4374              : 
    4375              :         // SUBROUTINE INFORMATION:
    4376              :         //       AUTHOR         Richard Raustad, FSEC
    4377              :         //       DATE WRITTEN   January 2007
    4378              :         //       MODIFIED       na
    4379              :         //       RE-ENGINEERED  na
    4380              : 
    4381              :         // PURPOSE OF THIS SUBROUTINE:
    4382              :         // To verify that the empirical model's independent variables result in a relative humidity that is within the range
    4383              :         // of relative humidities used when creating the empirical model. Both the regeneration and process inlet are tested.
    4384              : 
    4385              :         // METHODOLOGY EMPLOYED:
    4386              :         // The empirical models used for simulating a desiccant enhanced cooling coil are based on a limited data set.
    4387              :         // Extrapolation of empirical models can cause instability and the independent variables may need to be limited.
    4388              :         // In addition, the range of relative humidities in the original data set may influence the output of the
    4389              :         // empirical model. This subroutine tests the relative humidities passed to the empirical model and warns the
    4390              :         // user if these relative humidities are out of bounds based on the limits set by the user.
    4391              :         // REFERENCES:
    4392              :         // na
    4393              : 
    4394              :         // Using/Aliasing
    4395              :         using General::CreateSysTimeIntervalString;
    4396              : 
    4397              :         using Psychrometrics::PsyRhFnTdbWPb;
    4398              : 
    4399        97303 :         Real64 SysTimeElapsed = state.dataHVACGlobal->SysTimeElapsed;
    4400        97303 :         Real64 TimeStepSys = state.dataHVACGlobal->TimeStepSys;
    4401        97303 :         auto &RegenInletRH = state.dataHeatRecovery->RegenInletRH2;
    4402        97303 :         auto &ProcInletRH = state.dataHeatRecovery->ProcInletRH2;
    4403        97303 :         auto &thisError = state.dataHeatRecovery->error6;
    4404              :         // current end time is compared with last to see if time step changed
    4405              : 
    4406        97303 :         if (state.dataGlobal->WarmupFlag || FirstHVACIteration) {
    4407        92918 :             return;
    4408              :         }
    4409              : 
    4410              :         //   calculate end time of current time step
    4411         4385 :         thisError.CurrentEndTime = state.dataGlobal->CurrentTime + SysTimeElapsed;
    4412              : 
    4413              :         //   Print warning messages only when valid and only for the first occurrence. Let summary provide statistics.
    4414              :         //   Wait for next time step to print warnings. If simulation iterates, print out
    4415              :         //   the warning for the last iteration only. Must wait for next time step to accomplish this.
    4416              :         //   If a warning occurs and the simulation down shifts, the warning is not valid.
    4417         4385 :         if (thisError.CurrentEndTime > thisError.CurrentEndTimeLast && TimeStepSys >= thisError.TimeStepSysLast) {
    4418              : 
    4419              :             // print error when regeneration inlet relative humidity is outside model boundaries
    4420          321 :             if (state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenInRelHumTempErr.print) {
    4421           26 :                 ++state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenInRelHumTempErr.count;
    4422           26 :                 if (state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenInRelHumTempErr.count < 2) {
    4423            1 :                     ShowWarningError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenInRelHumTempErr.buffer1);
    4424            1 :                     ShowContinueError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenInRelHumTempErr.buffer2);
    4425            1 :                     ShowContinueError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenInRelHumTempErr.buffer3);
    4426            3 :                     ShowContinueError(state,
    4427              :                                       "...Using regeneration inlet air relative humidities that are outside the regeneration outlet temperature "
    4428              :                                       "equation model boundaries may adversely affect desiccant model performance. Verify correct model "
    4429              :                                       "coefficients.");
    4430              :                 } else {
    4431          200 :                     ShowRecurringWarningErrorAtEnd(state,
    4432           50 :                                                    format("{} \"{}\" - Regeneration inlet air relative humidity related to regen outlet air "
    4433              :                                                           "temperature equation is outside model boundaries error continues...",
    4434           25 :                                                           state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).PerfType,
    4435           25 :                                                           state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).Name),
    4436           25 :                                                    state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenInRelHumTempErr.index,
    4437           25 :                                                    state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenInRelHumTempErr.last,
    4438           25 :                                                    state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenInRelHumTempErr.last);
    4439              :                 }
    4440              :             }
    4441              : 
    4442              :             // print error when process inlet relative humidity is outside model boundaries
    4443          321 :             if (state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).procInRelHumTempErr.print) {
    4444           26 :                 ++state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).procInRelHumTempErr.count;
    4445           26 :                 if (state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).procInRelHumTempErr.count < 2) {
    4446            1 :                     ShowWarningError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).procInRelHumTempErr.buffer1);
    4447            1 :                     ShowContinueError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).procInRelHumTempErr.buffer2);
    4448            1 :                     ShowContinueError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).procInRelHumTempErr.buffer3);
    4449            3 :                     ShowContinueError(state,
    4450              :                                       "...Using process inlet air relative humidities that are outside the regeneration outlet temperature equation "
    4451              :                                       "model boundaries may adversely affect desiccant model performance. Verify correct model coefficients.");
    4452              :                 } else {
    4453          200 :                     ShowRecurringWarningErrorAtEnd(state,
    4454           50 :                                                    format("{} \"{}\" - Process inlet air relative humidity related to regen outlet air temperature "
    4455              :                                                           "equation is outside model boundaries error continues...",
    4456           25 :                                                           state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).PerfType,
    4457           25 :                                                           state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).Name),
    4458           25 :                                                    state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).procInRelHumTempErr.index,
    4459           25 :                                                    state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).procInRelHumTempErr.last,
    4460           25 :                                                    state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).procInRelHumTempErr.last);
    4461              :                 }
    4462              :             }
    4463              : 
    4464              :         } // IF(CurrentEndTime .GT. CurrentEndTimeLast .AND. TimeStepSys .GE. TimeStepSysLast)THEN
    4465              : 
    4466              :         //     save last system time step and last end time of current time step (used to determine if warning is valid)
    4467         4385 :         thisError.TimeStepSysLast = TimeStepSys;
    4468         4385 :         thisError.CurrentEndTimeLast = thisError.CurrentEndTime;
    4469              : 
    4470              :         //     Check that condition is not above saturation curve prior to next calc (PsyRhFnTdbWPb) to avoid psyc routine errors
    4471              :         //                           *
    4472              :         //                          *
    4473              :         //                  x------*---------- T_HumRat
    4474              :         //                  |    *
    4475              :         //                  |  *
    4476              :         //                  *----------------- PsyWFnTdpPb(Tdp,Pb)
    4477              :         //               *  |
    4478              :         //                  |
    4479              :         //                T_Temp
    4480         8770 :         if (T_RegenInHumRat > Psychrometrics::PsyWFnTdpPb(state, T_RegenInTemp, state.dataEnvrn->OutBaroPress) ||
    4481         8770 :             T_ProcInHumRat > Psychrometrics::PsyWFnTdpPb(state, T_ProcInTemp, state.dataEnvrn->OutBaroPress)) {
    4482              :             //       reset RH print flags just in case
    4483            0 :             state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenInRelHumTempErr.print = false;
    4484            0 :             state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).procInRelHumTempErr.print = false;
    4485            0 :             return;
    4486              :         }
    4487              : 
    4488              :         //     If regen and process inlet temperatures are the same the coil is off, do not print out of bounds warning for this case
    4489         4385 :         if (std::abs(T_RegenInTemp - T_ProcInTemp) < SMALL) {
    4490           29 :             state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenInRelHumTempErr.print = false;
    4491           29 :             state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).procInRelHumTempErr.print = false;
    4492           29 :             return;
    4493              :         }
    4494              : 
    4495         4356 :         RegenInletRH = PsyRhFnTdbWPb(state, T_RegenInTemp, T_RegenInHumRat, state.dataEnvrn->OutBaroPress);
    4496         4356 :         ProcInletRH = min(1.0, PsyRhFnTdbWPb(state, T_ProcInTemp, T_ProcInHumRat, state.dataEnvrn->OutBaroPress));
    4497              : 
    4498              :         // checking if regeneration inlet relative humidity is within model boundaries
    4499         8712 :         if (RegenInletRH < state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_MinRegenAirInRelHum ||
    4500         4356 :             RegenInletRH > state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_MaxRegenAirInRelHum) {
    4501           31 :             state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenInRelHumTempErr.last = RegenInletRH * 100.0;
    4502           31 :             thisError.OutputChar = format("{:.1R}", RegenInletRH * 100.0);
    4503           31 :             thisError.OutputCharLo = format("{:.1R}", state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_MinRegenAirInRelHum * 100.0);
    4504           31 :             thisError.OutputCharHi = format("{:.1R}", state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_MaxRegenAirInRelHum * 100.0);
    4505           31 :             state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenInRelHumTempErr.print = true;
    4506              : 
    4507           31 :             state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenInRelHumTempErr.buffer1 =
    4508           62 :                 format("{} \"{}\" - Regeneration inlet air relative humidity related to regen outlet air temperature equation is outside model "
    4509              :                        "boundaries at {}.",
    4510           31 :                        state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).PerfType,
    4511           31 :                        state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).Name,
    4512           62 :                        thisError.OutputChar);
    4513           31 :             state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenInRelHumTempErr.buffer2 =
    4514           62 :                 format("...Model limit on regeneration inlet air relative humidity is {} to {}.", thisError.OutputCharLo, thisError.OutputCharHi);
    4515           62 :             state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenInRelHumTempErr.buffer3 = format(
    4516           93 :                 "...Occurrence info = {}, {}, {}", state.dataEnvrn->EnvironmentName, state.dataEnvrn->CurMnDy, CreateSysTimeIntervalString(state));
    4517              :         } else {
    4518         4325 :             state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenInRelHumTempErr.print = false;
    4519              :         }
    4520              : 
    4521              :         // checking if process inlet relative humidity is within model boundaries
    4522         8561 :         if (ProcInletRH < state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_MinProcAirInRelHum ||
    4523         4205 :             ProcInletRH > state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_MaxProcAirInRelHum) {
    4524          151 :             state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).procInRelHumTempErr.last = ProcInletRH * 100.0;
    4525          151 :             thisError.OutputChar = format("{:.1R}", ProcInletRH * 100.0);
    4526          151 :             thisError.OutputCharLo = format("{:.1R}", state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_MinProcAirInRelHum * 100.0);
    4527          151 :             thisError.OutputCharHi = format("{:.1R}", state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_MaxProcAirInRelHum * 100.0);
    4528          151 :             state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).procInRelHumTempErr.print = true;
    4529              : 
    4530          302 :             state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).procInRelHumTempErr.buffer1 = format(
    4531              :                 "{} \"{}\" - Process inlet air relative humidity related to regen outlet air temperature equation is outside model boundaries at {}.",
    4532          151 :                 state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).PerfType,
    4533          151 :                 state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).Name,
    4534          302 :                 thisError.OutputChar);
    4535          151 :             state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).procInRelHumTempErr.buffer2 =
    4536          302 :                 format("...Model limit on process inlet air relative humidity is {} to {}.", thisError.OutputCharLo, thisError.OutputCharHi);
    4537          302 :             state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).procInRelHumTempErr.buffer3 = format(
    4538          453 :                 "...Occurrence info = {}, {}, {}", state.dataEnvrn->EnvironmentName, state.dataEnvrn->CurMnDy, CreateSysTimeIntervalString(state));
    4539              :         } else {
    4540         4205 :             state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).procInRelHumTempErr.print = false;
    4541              :         }
    4542              :     }
    4543              : 
    4544        97303 :     void HeatExchCond::CheckModelBoundsRH_HumRatEq(EnergyPlusData &state,
    4545              :                                                    Real64 const H_RegenInTemp,   // current regen inlet temperature passed to eqn
    4546              :                                                    Real64 const H_RegenInHumRat, // current regen inlet hum rat passed to eqn
    4547              :                                                    Real64 const H_ProcInTemp,    // current process inlet temperature passed to eqn
    4548              :                                                    Real64 const H_ProcInHumRat,  // current process inlet hum rat passed to eqn
    4549              :                                                    bool const FirstHVACIteration // first HVAC iteration flag
    4550              :     ) const
    4551              :     {
    4552              : 
    4553              :         // SUBROUTINE INFORMATION:
    4554              :         //       AUTHOR         Richard Raustad, FSEC
    4555              :         //       DATE WRITTEN   January 2007
    4556              :         //       MODIFIED       na
    4557              :         //       RE-ENGINEERED  na
    4558              : 
    4559              :         // PURPOSE OF THIS SUBROUTINE:
    4560              :         // To verify that the empirical model's independent variables result in a relative humidity that is within the range
    4561              :         // of relative humidities used when creating the empirical model. Both the regeneration and process inlet are tested.
    4562              : 
    4563              :         // METHODOLOGY EMPLOYED:
    4564              :         // The empirical models used for simulating a desiccant enhanced cooling coil are based on a limited data set.
    4565              :         // Extrapolation of empirical models can cause instability and the independent variables may need to be limited.
    4566              :         // In addition, the range of relative humidities in the original data set may influence the output of the
    4567              :         // empirical model. This subroutine tests the relative humidities passed to the empirical model and warns the
    4568              :         // user if these relative humidities are out of bounds based on the limits set by the user.
    4569              : 
    4570              :         // Using/Aliasing
    4571              :         using General::CreateSysTimeIntervalString;
    4572              : 
    4573              :         using Psychrometrics::PsyRhFnTdbWPb;
    4574              : 
    4575              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    4576        97303 :         Real64 SysTimeElapsed = state.dataHVACGlobal->SysTimeElapsed;
    4577        97303 :         Real64 TimeStepSys = state.dataHVACGlobal->TimeStepSys;
    4578        97303 :         auto &RegenInletRH = state.dataHeatRecovery->RegenInletRH;
    4579        97303 :         auto &ProcInletRH = state.dataHeatRecovery->ProcInletRH;
    4580        97303 :         auto &thisError = state.dataHeatRecovery->error5;
    4581              :         // current end time is compared with last to see if time step changed
    4582              : 
    4583        97303 :         if (state.dataGlobal->WarmupFlag || FirstHVACIteration) {
    4584        92918 :             return;
    4585              :         }
    4586              : 
    4587              :         //   calculate end time of current time step
    4588         4385 :         thisError.CurrentEndTime = state.dataGlobal->CurrentTime + SysTimeElapsed;
    4589              : 
    4590              :         //   Print warning messages only when valid and only for the first occurrence. Let summary provide statistics.
    4591              :         //   Wait for next time step to print warnings. If simulation iterates, print out
    4592              :         //   the warning for the last iteration only. Must wait for next time step to accomplish this.
    4593              :         //   If a warning occurs and the simulation down shifts, the warning is not valid.
    4594         4385 :         if (thisError.CurrentEndTime > thisError.CurrentEndTimeLast && TimeStepSys >= thisError.TimeStepSysLast) {
    4595              : 
    4596              :             // print error when regeneration inlet relative humidity is outside model boundaries
    4597          321 :             if (state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenInRelHumHumRatErr.print) {
    4598           26 :                 ++state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenInRelHumHumRatErr.count;
    4599           26 :                 if (state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenInRelHumHumRatErr.count < 2) {
    4600            1 :                     ShowWarningError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenInRelHumHumRatErr.buffer1);
    4601            1 :                     ShowContinueError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenInRelHumHumRatErr.buffer2);
    4602            1 :                     ShowContinueError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenInRelHumHumRatErr.buffer3);
    4603            3 :                     ShowContinueError(state,
    4604              :                                       "...Using regeneration inlet air relative humidities that are outside the regeneration outlet humidity ratio "
    4605              :                                       "equation model boundaries may adversely affect desiccant model performance. Verify correct model "
    4606              :                                       "coefficients.");
    4607              :                 } else {
    4608          200 :                     ShowRecurringWarningErrorAtEnd(state,
    4609           50 :                                                    format("{} \"{}\" - Regeneration inlet air relative humidity related to regen outlet air humidity "
    4610              :                                                           "ratio equation is outside model boundaries error continues...",
    4611           25 :                                                           state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).PerfType,
    4612           25 :                                                           state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).Name),
    4613           25 :                                                    state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenInRelHumHumRatErr.index,
    4614           25 :                                                    state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenInRelHumHumRatErr.last,
    4615           25 :                                                    state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenInRelHumHumRatErr.last);
    4616              :                 }
    4617              :             }
    4618              : 
    4619              :             // print error when process inlet relative humidity is outside model boundaries
    4620          321 :             if (state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).procInRelHumHumRatErr.print) {
    4621           26 :                 ++state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).procInRelHumHumRatErr.count;
    4622           26 :                 if (state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).procInRelHumHumRatErr.count < 2) {
    4623            1 :                     ShowWarningError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).procInRelHumHumRatErr.buffer1);
    4624            1 :                     ShowContinueError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).procInRelHumHumRatErr.buffer2);
    4625            1 :                     ShowContinueError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).procInRelHumHumRatErr.buffer3);
    4626            3 :                     ShowContinueError(state,
    4627              :                                       "...Using process inlet air relative humidities that are outside the regeneration outlet humidity ratio "
    4628              :                                       "equation model boundaries may adversely affect desiccant model performance. Verify correct model "
    4629              :                                       "coefficients.");
    4630              :                 } else {
    4631          200 :                     ShowRecurringWarningErrorAtEnd(state,
    4632           50 :                                                    format("{} \"{}\" - Process inlet air relative humidity related to regen outlet air humidity "
    4633              :                                                           "ratio equation is outside model boundaries error continues...",
    4634           25 :                                                           state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).PerfType,
    4635           25 :                                                           state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).Name),
    4636           25 :                                                    state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).procInRelHumHumRatErr.index,
    4637           25 :                                                    state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).procInRelHumHumRatErr.last,
    4638           25 :                                                    state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).procInRelHumHumRatErr.last);
    4639              :                 }
    4640              :             }
    4641              : 
    4642              :         } // IF(CurrentEndTime .GT. CurrentEndTimeLast .AND. TimeStepSys .GE. TimeStepSysLast)THEN
    4643              : 
    4644              :         //     save last system time step and last end time of current time step (used to determine if warning is valid)
    4645         4385 :         thisError.TimeStepSysLast = TimeStepSys;
    4646         4385 :         thisError.CurrentEndTimeLast = thisError.CurrentEndTime;
    4647              : 
    4648              :         //     Check that condition is not above saturation curve prior to next calc (PsyRhFnTdbWPb) to avoid psyc routine errors
    4649              :         //                           *
    4650              :         //                          *
    4651              :         //                  x------*---------- H_HumRat
    4652              :         //                  |    *
    4653              :         //                  |  *
    4654              :         //                  *----------------- PsyWFnTdpPb(Tdp,Pb)
    4655              :         //               *  |
    4656              :         //                  |
    4657              :         //                H_Temp
    4658         8770 :         if (H_RegenInHumRat > Psychrometrics::PsyWFnTdpPb(state, H_RegenInTemp, state.dataEnvrn->OutBaroPress) ||
    4659         8770 :             H_ProcInHumRat > Psychrometrics::PsyWFnTdpPb(state, H_ProcInTemp, state.dataEnvrn->OutBaroPress)) {
    4660              :             //       reset RH print flags just in case
    4661            0 :             state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenInRelHumHumRatErr.print = false;
    4662            0 :             state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).procInRelHumHumRatErr.print = false;
    4663            0 :             return;
    4664              :         }
    4665              : 
    4666              :         //     If regen and process inlet temperatures are the same the coil is off, do not print out of bounds warning for this case
    4667         4385 :         if (std::abs(H_RegenInTemp - H_ProcInTemp) < SMALL) {
    4668           29 :             state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenInRelHumHumRatErr.print = false;
    4669           29 :             state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).procInRelHumHumRatErr.print = false;
    4670           29 :             return;
    4671              :         }
    4672              : 
    4673         4356 :         RegenInletRH = PsyRhFnTdbWPb(state, H_RegenInTemp, H_RegenInHumRat, state.dataEnvrn->OutBaroPress);
    4674         4356 :         ProcInletRH = min(1.0, PsyRhFnTdbWPb(state, H_ProcInTemp, H_ProcInHumRat, state.dataEnvrn->OutBaroPress));
    4675              : 
    4676              :         // checking if regeneration inlet relative humidity is within model boundaries
    4677         8712 :         if (RegenInletRH < state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_MinRegenAirInRelHum ||
    4678         4356 :             RegenInletRH > state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_MaxRegenAirInRelHum) {
    4679           31 :             state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenInRelHumHumRatErr.last = RegenInletRH * 100.0;
    4680           31 :             thisError.OutputChar = format("{:.1R}", RegenInletRH * 100.0);
    4681           31 :             thisError.OutputCharLo = format("{:.1R}", state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_MinRegenAirInRelHum * 100.0);
    4682           31 :             thisError.OutputCharHi = format("{:.1R}", state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_MaxRegenAirInRelHum * 100.0);
    4683           31 :             state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenInRelHumHumRatErr.print = true;
    4684              : 
    4685           31 :             state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenInRelHumHumRatErr.buffer1 =
    4686           62 :                 format("{} \"{}\" - Regeneration inlet air relative humidity related to regen outlet air humidity ratio equation is outside model "
    4687              :                        "boundaries at {}.",
    4688           31 :                        state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).PerfType,
    4689           31 :                        state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).Name,
    4690           62 :                        thisError.OutputChar);
    4691           31 :             state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenInRelHumHumRatErr.buffer2 =
    4692           62 :                 format("...Model limit on regeneration inlet air relative humidity is {} to {}.", thisError.OutputCharLo, thisError.OutputCharHi);
    4693           62 :             state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenInRelHumHumRatErr.buffer3 = format(
    4694           93 :                 "...Occurrence info = {}, {}, {}", state.dataEnvrn->EnvironmentName, state.dataEnvrn->CurMnDy, CreateSysTimeIntervalString(state));
    4695              :         } else {
    4696         4325 :             state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenInRelHumHumRatErr.print = false;
    4697              :         }
    4698              : 
    4699              :         // checking if process inlet relative humidity is within model boundaries
    4700         8561 :         if (ProcInletRH < state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_MinProcAirInRelHum ||
    4701         4205 :             ProcInletRH > state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_MaxProcAirInRelHum) {
    4702          151 :             state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).procInRelHumHumRatErr.last = ProcInletRH * 100.0;
    4703          151 :             thisError.OutputChar = format("{:.1R}", ProcInletRH * 100.0);
    4704          151 :             thisError.OutputCharLo = format("{:.1R}", state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_MinProcAirInRelHum * 100.0);
    4705          151 :             thisError.OutputCharHi = format("{:.1R}", state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_MaxProcAirInRelHum * 100.0);
    4706          151 :             state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).procInRelHumHumRatErr.print = true;
    4707              : 
    4708          151 :             state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).procInRelHumHumRatErr.buffer1 =
    4709          302 :                 format("{} \"{}\" - Process inlet air relative humidity related to regen outlet air humidity ratio equation is outside model "
    4710              :                        "boundaries at {}.",
    4711          151 :                        state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).PerfType,
    4712          151 :                        state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).Name,
    4713          302 :                        thisError.OutputChar);
    4714          151 :             state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).procInRelHumHumRatErr.buffer2 =
    4715          302 :                 format("...Model limit on process inlet air relative humidity is {} to {}.", thisError.OutputCharLo, thisError.OutputCharHi);
    4716          302 :             state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).procInRelHumHumRatErr.buffer3 = format(
    4717          453 :                 "...Occurrence info = {}, {}, {}", state.dataEnvrn->EnvironmentName, state.dataEnvrn->CurMnDy, CreateSysTimeIntervalString(state));
    4718              :         } else {
    4719         4205 :             state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).procInRelHumHumRatErr.print = false;
    4720              :         }
    4721              :     }
    4722              : 
    4723        97303 :     void HeatExchCond::CheckForBalancedFlow(EnergyPlusData &state,
    4724              :                                             Real64 const ProcessInMassFlow, // current process inlet air mass flow rate (m3/s)
    4725              :                                             Real64 const RegenInMassFlow,   // current regeneration inlet air mass flow rate (m3/s)
    4726              :                                             bool const FirstHVACIteration   // first HVAC iteration flag
    4727              :     ) const
    4728              :     {
    4729              : 
    4730              :         // SUBROUTINE INFORMATION:
    4731              :         //       AUTHOR         Richard Raustad, FSEC
    4732              :         //       DATE WRITTEN   June 2007
    4733              :         //       MODIFIED       na
    4734              :         //       RE-ENGINEERED  na
    4735              : 
    4736              :         // PURPOSE OF THIS SUBROUTINE:
    4737              :         // To verify that the balanced flow desiccant heat exchanger has the same regeneration and process air flow rates.
    4738              : 
    4739              :         // METHODOLOGY EMPLOYED:
    4740              :         // Check that the regeneration and process air mass flow rates are within 2%.
    4741              :         // REFERENCES:
    4742              :         // na
    4743              : 
    4744              :         // Using/Aliasing
    4745              :         using General::CreateSysTimeIntervalString;
    4746              : 
    4747        97303 :         auto &thisError = state.dataHeatRecovery->error7;
    4748              : 
    4749        97303 :         Real64 SysTimeElapsed = state.dataHVACGlobal->SysTimeElapsed;
    4750        97303 :         Real64 TimeStepSys = state.dataHVACGlobal->TimeStepSys;
    4751              : 
    4752              :         // current end time is compared with last to see if time step changed
    4753              :         Real64 ABSImbalancedFlow; // absolute value of process and regeneration air flow imbalance fraction
    4754              : 
    4755        97303 :         if (state.dataGlobal->WarmupFlag || FirstHVACIteration) {
    4756        92918 :             return;
    4757              :         }
    4758              : 
    4759              :         //   calculate end time of current time step
    4760         4385 :         thisError.CurrentEndTime = state.dataGlobal->CurrentTime + SysTimeElapsed;
    4761              : 
    4762              :         //   Print warning messages only when valid and only for the first occurrence. Let summary provide statistics.
    4763              :         //   Wait for next time step to print warnings. If simulation iterates, print out
    4764              :         //   the warning for the last iteration only. Must wait for next time step to accomplish this.
    4765              :         //   If a warning occurs and the simulation down shifts, the warning is not valid.
    4766         4385 :         if (thisError.CurrentEndTime > thisError.CurrentEndTimeLast && TimeStepSys >= thisError.TimeStepSysLast) {
    4767              : 
    4768              :             // print error when regeneration inlet relative humidity is outside model boundaries
    4769          321 :             if (state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).imbalancedFlowErr.print) {
    4770            0 :                 ++state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).imbalancedFlowErr.count;
    4771            0 :                 if (state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).imbalancedFlowErr.count < 2) {
    4772            0 :                     ShowWarningError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).imbalancedFlowErr.buffer1);
    4773            0 :                     ShowContinueError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).imbalancedFlowErr.buffer2);
    4774            0 :                     ShowContinueError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).imbalancedFlowErr.buffer3);
    4775              :                     //           CALL ShowContinueError(state, '...Using regeneration inlet air relative humidities that are outside the regeneration
    4776              :                     //           '&
    4777              :                     //                 //'outlet humidity ratio equation model boundaries may adversely affect desiccant model performance. '&
    4778              :                     //                 //'Verify correct model coefficients.')
    4779              :                 } else {
    4780            0 :                     ShowRecurringWarningErrorAtEnd(state,
    4781            0 :                                                    format("{} \"{}\" - unbalanced air flow rate is limited to 2% error continues with the imbalanced "
    4782              :                                                           "fraction statistics reported...",
    4783            0 :                                                           HVAC::hxTypeNames[(int)this->type],
    4784            0 :                                                           this->Name),
    4785            0 :                                                    state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).imbalancedFlowErr.index,
    4786            0 :                                                    state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).imbalancedFlowErr.last,
    4787            0 :                                                    state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).imbalancedFlowErr.last);
    4788              :                 }
    4789              :             }
    4790              : 
    4791              :         } // IF(CurrentEndTime .GT. CurrentEndTimeLast .AND. TimeStepSys .GE. TimeStepSysLast)THEN
    4792              : 
    4793              :         //     save last system time step and last end time of current time step (used to determine if warning is valid)
    4794         4385 :         thisError.TimeStepSysLast = TimeStepSys;
    4795         4385 :         thisError.CurrentEndTimeLast = thisError.CurrentEndTime;
    4796              : 
    4797              :         // checking if regeneration inlet relative humidity is within model boundaries
    4798         4385 :         ABSImbalancedFlow = std::abs(RegenInMassFlow - ProcessInMassFlow) / RegenInMassFlow;
    4799         4385 :         if (ABSImbalancedFlow > 0.02) {
    4800            0 :             state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).imbalancedFlowErr.last = ABSImbalancedFlow;
    4801            0 :             thisError.OutputCharLo = format("{:.6R}", RegenInMassFlow);
    4802            0 :             thisError.OutputCharHi = format("{:.6R}", ProcessInMassFlow);
    4803            0 :             state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).imbalancedFlowErr.print = true;
    4804              : 
    4805            0 :             state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).imbalancedFlowErr.buffer1 =
    4806            0 :                 format("{} \"{}\" - unbalanced air flow rate is limited to 2%.", HVAC::hxTypeNames[(int)this->type], this->Name);
    4807            0 :             state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).imbalancedFlowErr.buffer2 = format(
    4808            0 :                 "...Regeneration air mass flow rate is {} and process air mass flow rate is {}.", thisError.OutputCharLo, thisError.OutputCharHi);
    4809            0 :             state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).imbalancedFlowErr.buffer3 = format(
    4810            0 :                 "...Occurrence info = {}, {}, {}", state.dataEnvrn->EnvironmentName, state.dataEnvrn->CurMnDy, CreateSysTimeIntervalString(state));
    4811              :         } else {
    4812         4385 :             state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).imbalancedFlowErr.print = false;
    4813              :         }
    4814              :     }
    4815              : 
    4816          122 :     int GetSupplyInletNode(EnergyPlusData &state,
    4817              :                            std::string const &HXName, // must match HX names for the state.dataHeatRecovery->ExchCond type
    4818              :                            bool &ErrorsFound          // set to true if problem
    4819              :     )
    4820              :     {
    4821              : 
    4822              :         // FUNCTION INFORMATION:
    4823              :         //       AUTHOR         Richard Raustad
    4824              :         //       DATE WRITTEN   February 2007
    4825              :         //       MODIFIED       na
    4826              :         //       RE-ENGINEERED  na
    4827              : 
    4828              :         // PURPOSE OF THIS FUNCTION:
    4829              :         // This function looks up the given HX and returns the supply air inlet node number.
    4830              :         // If incorrect HX name is given, ErrorsFound is returned as true and node number as zero.
    4831              : 
    4832              :         // Obtains and Allocates heat exchanger related parameters from input file
    4833          122 :         if (state.dataHeatRecovery->GetInputFlag) { // First time subroutine has been entered
    4834           11 :             GetHeatRecoveryInput(state);
    4835           11 :             state.dataHeatRecovery->GetInputFlag = false;
    4836              :         }
    4837              : 
    4838          122 :         int const WhichHX = Util::FindItemInList(HXName, state.dataHeatRecovery->ExchCond);
    4839          122 :         if (WhichHX != 0) {
    4840          122 :             return state.dataHeatRecovery->ExchCond(WhichHX).SupInletNode;
    4841              :         } else {
    4842            0 :             ShowSevereError(state, format("GetSupplyInletNode: Could not find heat exchanger = \"{}\"", HXName));
    4843            0 :             ErrorsFound = true;
    4844            0 :             return 0;
    4845              :         }
    4846              :     }
    4847              : 
    4848           15 :     int GetSupplyOutletNode(EnergyPlusData &state,
    4849              :                             std::string const &HXName, // must match HX names for the state.dataHeatRecovery->ExchCond type
    4850              :                             bool &ErrorsFound          // set to true if problem
    4851              :     )
    4852              :     {
    4853              : 
    4854              :         // FUNCTION INFORMATION:
    4855              :         //       AUTHOR         Richard Raustad
    4856              :         //       DATE WRITTEN   February 2007
    4857              :         //       MODIFIED       na
    4858              :         //       RE-ENGINEERED  na
    4859              : 
    4860              :         // PURPOSE OF THIS FUNCTION:
    4861              :         // This function looks up the given HX and returns the supply air outlet node number.
    4862              :         // If incorrect HX name is given, ErrorsFound is returned as true and node number as zero.
    4863              : 
    4864              :         // Obtains and Allocates heat exchanger related parameters from input file
    4865           15 :         if (state.dataHeatRecovery->GetInputFlag) { // First time subroutine has been entered
    4866            0 :             GetHeatRecoveryInput(state);
    4867            0 :             state.dataHeatRecovery->GetInputFlag = false;
    4868              :         }
    4869              : 
    4870           15 :         int const WhichHX = Util::FindItemInList(HXName, state.dataHeatRecovery->ExchCond);
    4871           15 :         if (WhichHX != 0) {
    4872           15 :             return state.dataHeatRecovery->ExchCond(WhichHX).SupOutletNode;
    4873              :         } else {
    4874            0 :             ShowSevereError(state, format("GetSupplyOutletNode: Could not find heat exchanger = \"{}\"", HXName));
    4875            0 :             ErrorsFound = true;
    4876            0 :             return 0;
    4877              :         }
    4878              :     }
    4879              : 
    4880          122 :     int GetSecondaryInletNode(EnergyPlusData &state,
    4881              :                               std::string const &HXName, // must match HX names for the state.dataHeatRecovery->ExchCond type
    4882              :                               bool &ErrorsFound          // set to true if problem
    4883              :     )
    4884              :     {
    4885              : 
    4886              :         // FUNCTION INFORMATION:
    4887              :         //       AUTHOR         Richard Raustad
    4888              :         //       DATE WRITTEN   February 2007
    4889              :         //       MODIFIED       na
    4890              :         //       RE-ENGINEERED  na
    4891              : 
    4892              :         // PURPOSE OF THIS FUNCTION:
    4893              :         // This function looks up the given HX and returns the secondary air inlet node number.
    4894              :         // If incorrect HX name is given, ErrorsFound is returned as true and node number as zero.
    4895              : 
    4896              :         // Obtains and Allocates heat exchanger related parameters from input file
    4897          122 :         if (state.dataHeatRecovery->GetInputFlag) { // First time subroutine has been entered
    4898            2 :             GetHeatRecoveryInput(state);
    4899            2 :             state.dataHeatRecovery->GetInputFlag = false;
    4900              :         }
    4901              : 
    4902          122 :         int const WhichHX = Util::FindItemInList(HXName, state.dataHeatRecovery->ExchCond);
    4903          122 :         if (WhichHX != 0) {
    4904          122 :             return state.dataHeatRecovery->ExchCond(WhichHX).SecInletNode;
    4905              :         } else {
    4906            0 :             ShowSevereError(state, format("GetSecondaryInletNode: Could not find heat exchanger = \"{}\"", HXName));
    4907            0 :             ErrorsFound = true;
    4908            0 :             return 0;
    4909              :         }
    4910              :     }
    4911              : 
    4912           15 :     int GetSecondaryOutletNode(EnergyPlusData &state,
    4913              :                                std::string const &HXName, // must match HX names for the state.dataHeatRecovery->ExchCond type
    4914              :                                bool &ErrorsFound          // set to true if problem
    4915              :     )
    4916              :     {
    4917              : 
    4918              :         // FUNCTION INFORMATION:
    4919              :         //       AUTHOR         Richard Raustad
    4920              :         //       DATE WRITTEN   February 2007
    4921              :         //       MODIFIED       na
    4922              :         //       RE-ENGINEERED  na
    4923              : 
    4924              :         // PURPOSE OF THIS FUNCTION:
    4925              :         // This function looks up the given HX assisted cooling coil and returns the secondary air outlet node number.
    4926              :         // If incorrect HX name is given, ErrorsFound is returned as true and node number as zero.
    4927              : 
    4928              :         // Obtains and Allocates heat exchanger related parameters from input file
    4929           15 :         if (state.dataHeatRecovery->GetInputFlag) { // First time subroutine has been entered
    4930            0 :             GetHeatRecoveryInput(state);
    4931            0 :             state.dataHeatRecovery->GetInputFlag = false;
    4932              :         }
    4933              : 
    4934           15 :         int const WhichHX = Util::FindItemInList(HXName, state.dataHeatRecovery->ExchCond);
    4935           15 :         if (WhichHX != 0) {
    4936           15 :             return state.dataHeatRecovery->ExchCond(WhichHX).SecOutletNode;
    4937              :         } else {
    4938            0 :             ShowSevereError(state, format("GetSecondaryOutletNode: Could not find heat exchanger = \"{}\"", HXName));
    4939            0 :             ErrorsFound = true;
    4940            0 :             return 0;
    4941              :         }
    4942              :     }
    4943              : 
    4944          107 :     Real64 GetSupplyAirFlowRate(EnergyPlusData &state,
    4945              :                                 std::string const &HXName, // must match HX names for the state.dataHeatRecovery->ExchCond type
    4946              :                                 bool &ErrorsFound          // set to true if problem
    4947              :     )
    4948              :     {
    4949              : 
    4950              :         // FUNCTION INFORMATION:
    4951              :         //       AUTHOR         Richard Raustad
    4952              :         //       DATE WRITTEN   October 2007
    4953              :         //       MODIFIED       na
    4954              :         //       RE-ENGINEERED  na
    4955              : 
    4956              :         // PURPOSE OF THIS FUNCTION:
    4957              :         // This function looks up the given Generic HX and the volumetric air flow rate.
    4958              :         // If incorrect HX name is given, ErrorsFound is returned as true and air flow rate as zero.
    4959              : 
    4960              :         // Obtains and Allocates heat exchanger related parameters from input file
    4961          107 :         if (state.dataHeatRecovery->GetInputFlag) { // First time subroutine has been entered
    4962            0 :             GetHeatRecoveryInput(state);
    4963            0 :             state.dataHeatRecovery->GetInputFlag = false;
    4964              :         }
    4965              : 
    4966          107 :         int const WhichHX = Util::FindItemInList(HXName, state.dataHeatRecovery->ExchCond);
    4967          107 :         if (WhichHX != 0) {
    4968          107 :             return state.dataHeatRecovery->ExchCond(WhichHX).NomSupAirVolFlow;
    4969              :         } else {
    4970            0 :             ShowSevereError(state, format("GetSupplyAirFlowRate: Could not find heat exchanger = \"{}\"", HXName));
    4971            0 :             ShowContinueError(state, "... Supply Air Flow Rate returned as 0.");
    4972            0 :             ErrorsFound = true;
    4973            0 :             return 0.0;
    4974              :         }
    4975              :     }
    4976              : 
    4977          107 :     HVAC::HXType GetHeatExchangerObjectTypeNum(EnergyPlusData &state,
    4978              :                                                std::string const &HXName, // must match HX names for the state.dataHeatRecovery->ExchCond type
    4979              :                                                bool &ErrorsFound          // set to true if problem
    4980              :     )
    4981              :     {
    4982              : 
    4983              :         // FUNCTION INFORMATION:
    4984              :         //       AUTHOR         Richard Raustad
    4985              :         //       DATE WRITTEN   October 2007
    4986              :         //       MODIFIED       na
    4987              :         //       RE-ENGINEERED  na
    4988              : 
    4989              :         // PURPOSE OF THIS FUNCTION:
    4990              :         // This function looks up the given Generic HX and the volumetric air flow rate.
    4991              :         // If incorrect HX name is given, ErrorsFound is returned as true and air flow rate as zero.
    4992              : 
    4993              :         // Obtains and Allocates heat exchanger related parameters from input file
    4994          107 :         if (state.dataHeatRecovery->GetInputFlag) { // First time subroutine has been entered
    4995            5 :             GetHeatRecoveryInput(state);
    4996            5 :             state.dataHeatRecovery->GetInputFlag = false;
    4997              :         }
    4998              : 
    4999          107 :         int const WhichHX = Util::FindItemInList(HXName, state.dataHeatRecovery->ExchCond);
    5000          107 :         if (WhichHX != 0) {
    5001          107 :             return state.dataHeatRecovery->ExchCond(WhichHX).type;
    5002              :         } else {
    5003            0 :             ShowSevereError(state, format("GetHeatExchangerObjectTypeNum: Could not find heat exchanger = \"{}\"", HXName));
    5004            0 :             ErrorsFound = true;
    5005            0 :             return HVAC::HXType::Invalid;
    5006              :         }
    5007              :     }
    5008              : 
    5009              : } // namespace HeatRecovery
    5010              : 
    5011              : } // namespace EnergyPlus
        

Generated by: LCOV version 2.0-1