LCOV - code coverage report
Current view: top level - EnergyPlus - HeatRecovery.cc (source / functions) Hit Total Coverage
Test: lcov.output.filtered Lines: 1735 2645 65.6 %
Date: 2023-01-17 19:17:23 Functions: 30 31 96.8 %

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

Generated by: LCOV version 1.13