LCOV - code coverage report
Current view: top level - EnergyPlus - HeatRecovery.cc (source / functions) Hit Total Coverage
Test: lcov.output.filtered Lines: 1766 2654 66.5 %
Date: 2024-08-24 18:31:18 Functions: 28 28 100.0 %

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

Generated by: LCOV version 1.14