LCOV - code coverage report
Current view: top level - EnergyPlus - PlantHeatExchangerFluidToFluid.cc (source / functions) Coverage Total Hit
Test: lcov.output.filtered Lines: 44.1 % 956 422
Test Date: 2025-05-22 16:09:37 Functions: 100.0 % 14 14

            Line data    Source code
       1              : // EnergyPlus, Copyright (c) 1996-2025, The Board of Trustees of the University of Illinois,
       2              : // The Regents of the University of California, through Lawrence Berkeley National Laboratory
       3              : // (subject to receipt of any required approvals from the U.S. Dept. of Energy), Oak Ridge
       4              : // National Laboratory, managed by UT-Battelle, Alliance for Sustainable Energy, LLC, and other
       5              : // contributors. All rights reserved.
       6              : //
       7              : // NOTICE: This Software was developed under funding from the U.S. Department of Energy and the
       8              : // U.S. Government consequently retains certain rights. As such, the U.S. Government has been
       9              : // granted for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable,
      10              : // worldwide license in the Software to reproduce, distribute copies to the public, prepare
      11              : // derivative works, and perform publicly and display publicly, and to permit others to do so.
      12              : //
      13              : // Redistribution and use in source and binary forms, with or without modification, are permitted
      14              : // provided that the following conditions are met:
      15              : //
      16              : // (1) Redistributions of source code must retain the above copyright notice, this list of
      17              : //     conditions and the following disclaimer.
      18              : //
      19              : // (2) Redistributions in binary form must reproduce the above copyright notice, this list of
      20              : //     conditions and the following disclaimer in the documentation and/or other materials
      21              : //     provided with the distribution.
      22              : //
      23              : // (3) Neither the name of the University of California, Lawrence Berkeley National Laboratory,
      24              : //     the University of Illinois, U.S. Dept. of Energy nor the names of its contributors may be
      25              : //     used to endorse or promote products derived from this software without specific prior
      26              : //     written permission.
      27              : //
      28              : // (4) Use of EnergyPlus(TM) Name. If Licensee (i) distributes the software in stand-alone form
      29              : //     without changes from the version obtained under this License, or (ii) Licensee makes a
      30              : //     reference solely to the software portion of its product, Licensee must refer to the
      31              : //     software as "EnergyPlus version X" software, where "X" is the version number Licensee
      32              : //     obtained under this License and may not use a different name for the software. Except as
      33              : //     specifically required in this Section (4), Licensee shall not use in a company name, a
      34              : //     product name, in advertising, publicity, or other promotional activities any name, trade
      35              : //     name, trademark, logo, or other designation of "EnergyPlus", "E+", "e+" or confusingly
      36              : //     similar designation, without the U.S. Department of Energy's prior written consent.
      37              : //
      38              : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
      39              : // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
      40              : // AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
      41              : // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
      42              : // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
      43              : // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      44              : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
      45              : // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
      46              : // POSSIBILITY OF SUCH DAMAGE.
      47              : 
      48              : // C++ Headers
      49              : #include <cassert>
      50              : #include <cmath>
      51              : 
      52              : // ObjexxFCL Headers
      53              : #include <ObjexxFCL/Fmath.hh>
      54              : 
      55              : // EnergyPlus Headers
      56              : #include <EnergyPlus/Autosizing/Base.hh>
      57              : #include <EnergyPlus/BranchNodeConnections.hh>
      58              : #include <EnergyPlus/Data/EnergyPlusData.hh>
      59              : #include <EnergyPlus/DataBranchAirLoopPlant.hh>
      60              : #include <EnergyPlus/DataEnvironment.hh>
      61              : #include <EnergyPlus/DataHVACGlobals.hh>
      62              : #include <EnergyPlus/DataIPShortCuts.hh>
      63              : #include <EnergyPlus/DataLoopNode.hh>
      64              : #include <EnergyPlus/DataPrecisionGlobals.hh>
      65              : #include <EnergyPlus/DataSizing.hh>
      66              : #include <EnergyPlus/EMSManager.hh>
      67              : #include <EnergyPlus/FluidProperties.hh>
      68              : #include <EnergyPlus/General.hh>
      69              : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
      70              : #include <EnergyPlus/NodeInputManager.hh>
      71              : #include <EnergyPlus/OutputProcessor.hh>
      72              : #include <EnergyPlus/OutputReportPredefined.hh>
      73              : #include <EnergyPlus/Plant/DataPlant.hh>
      74              : #include <EnergyPlus/PlantHeatExchangerFluidToFluid.hh>
      75              : #include <EnergyPlus/PlantUtilities.hh>
      76              : #include <EnergyPlus/ScheduleManager.hh>
      77              : #include <EnergyPlus/UtilityRoutines.hh>
      78              : 
      79              : namespace EnergyPlus::PlantHeatExchangerFluidToFluid {
      80              : 
      81              : // Module containing the routines dealing with the HeatExchanger:FluidToFluid
      82              : 
      83              : // MODULE INFORMATION:
      84              : //       AUTHOR         B. Griffith, derived from legacy code by  Sankaranarayanan K P, and S. Rees
      85              : //       DATE WRITTEN   November 2012
      86              : //       MODIFIED       na
      87              : //       RE-ENGINEERED  na
      88              : 
      89              : // PURPOSE OF THIS MODULE:
      90              : // Simulate a generic plant heat exchanger with a variety of control options
      91              : 
      92              : std::string const ComponentClassName("HeatExchanger:FluidToFluid");
      93              : 
      94              : constexpr std::array<std::string_view, (int)FluidHXType::Num> fluidHXTypeNames = {"CrossFlowBothUnMixed",
      95              :                                                                                   "CrossFlowBothMixed",
      96              :                                                                                   "CrossFlowSupplyMixedDemandUnMixed",
      97              :                                                                                   "CrossFlowSupplyUnMixedDemandMixed",
      98              :                                                                                   "CounterFlow",
      99              :                                                                                   "ParallelFlow",
     100              :                                                                                   "Ideal"};
     101              : constexpr std::array<std::string_view, (int)FluidHXType::Num> fluidHXTypeNamesUC = {"CROSSFLOWBOTHUNMIXED",
     102              :                                                                                     "CROSSFLOWBOTHMIXED",
     103              :                                                                                     "CROSSFLOWSUPPLYMIXEDDEMANDUNMIXED",
     104              :                                                                                     "CROSSFLOWSUPPLYUNMIXEDDEMANDMIXED",
     105              :                                                                                     "COUNTERFLOW",
     106              :                                                                                     "PARALLELFLOW",
     107              :                                                                                     "IDEAL"};
     108              : 
     109              : constexpr std::array<std::string_view, (int)ControlType::Num> controlTypeNames = {"UncontrolledOn",
     110              :                                                                                   "OperationSchemeModulated",
     111              :                                                                                   "OperationSchemeOnOff",
     112              :                                                                                   "HeatingSetpointModulated",
     113              :                                                                                   "HeatingSetpointOnOff",
     114              :                                                                                   "CoolingSetpointModulated",
     115              :                                                                                   "CoolingSetpointOnOff",
     116              :                                                                                   "DualDeadbandSetpointModulated",
     117              :                                                                                   "DualDeadbandSetpointOnOff",
     118              :                                                                                   "CoolingDifferentialOnOff",
     119              :                                                                                   "CoolingSetpointOnOffWithComponentOverride",
     120              :                                                                                   "TrackComponentOnOff"};
     121              : constexpr std::array<std::string_view, (int)ControlType::Num> controlTypeNamesUC = {"UNCONTROLLEDON",
     122              :                                                                                     "OPERATIONSCHEMEMODULATED",
     123              :                                                                                     "OPERATIONSCHEMEONOFF",
     124              :                                                                                     "HEATINGSETPOINTMODULATED",
     125              :                                                                                     "HEATINGSETPOINTONOFF",
     126              :                                                                                     "COOLINGSETPOINTMODULATED",
     127              :                                                                                     "COOLINGSETPOINTONOFF",
     128              :                                                                                     "DUALDEADBANDSETPOINTMODULATED",
     129              :                                                                                     "DUALDEADBANDSETPOINTONOFF",
     130              :                                                                                     "COOLINGDIFFERENTIALONOFF",
     131              :                                                                                     "COOLINGSETPOINTONOFFWITHCOMPONENTOVERRIDE",
     132              :                                                                                     "TRACKCOMPONENTONOFF"};
     133              : 
     134              : constexpr std::array<std::string_view, (int)CtrlTempType::Num> ctrlTempTypeNames = {"WetBulbTemperature", "DryBulbTemperature", "Loop"};
     135              : constexpr std::array<std::string_view, (int)CtrlTempType::Num> ctrlTempTypeNamesUC = {"WETBULBTEMPERATURE", "DRYBULBTEMPERATURE", "LOOP"};
     136              : 
     137           12 : PlantComponent *HeatExchangerStruct::factory(EnergyPlusData &state, std::string const &objectName)
     138              : {
     139              :     // Process the input data for heat exchangers if it hasn't been done already
     140           12 :     if (state.dataPlantHXFluidToFluid->GetInput) {
     141            2 :         GetFluidHeatExchangerInput(state);
     142            2 :         state.dataPlantHXFluidToFluid->GetInput = false;
     143              :     }
     144              :     // Now look for this particular object
     145           24 :     for (auto &obj : state.dataPlantHXFluidToFluid->FluidHX) {
     146           24 :         if (obj.Name == objectName) {
     147           12 :             return &obj;
     148              :         }
     149              :     }
     150              :     // If we didn't find it, fatal
     151              :     ShowFatalError(state, format("LocalPlantFluidHXFactory: Error getting inputs for object named: {}", objectName)); // LCOV_EXCL_LINE
     152              :     // Shut up the compiler
     153              :     return nullptr; // LCOV_EXCL_LINE
     154              : }
     155              : 
     156           60 : void HeatExchangerStruct::onInitLoopEquip(EnergyPlusData &state, [[maybe_unused]] const PlantLocation &calledFromLocation)
     157              : {
     158           60 :     this->initialize(state);
     159           60 : }
     160              : 
     161           60 : void HeatExchangerStruct::getDesignCapacities(
     162              :     EnergyPlusData &state, const PlantLocation &calledFromLocation, Real64 &MaxLoad, Real64 &MinLoad, Real64 &OptLoad)
     163              : {
     164           60 :     if (calledFromLocation.loopNum == this->DemandSideLoop.loopNum) {
     165           30 :         MinLoad = 0.0;
     166           30 :         MaxLoad = this->DemandSideLoop.MaxLoad;
     167           30 :         OptLoad = this->DemandSideLoop.MaxLoad * 0.9;
     168           30 :     } else if (calledFromLocation.loopNum == this->SupplySideLoop.loopNum) {
     169           30 :         this->size(state); // only call sizing from the loop that sizes are based on
     170           30 :         MinLoad = 0.0;
     171           30 :         MaxLoad = this->SupplySideLoop.MaxLoad;
     172           30 :         OptLoad = this->SupplySideLoop.MaxLoad * 0.9;
     173              :     }
     174           60 : }
     175              : 
     176        34940 : void HeatExchangerStruct::simulate(EnergyPlusData &state,
     177              :                                    const PlantLocation &calledFromLocation,
     178              :                                    bool const FirstHVACIteration,
     179              :                                    Real64 &CurLoad,
     180              :                                    [[maybe_unused]] bool const RunFlag)
     181              : {
     182              : 
     183              :     // SUBROUTINE INFORMATION:
     184              :     //       AUTHOR         B. Griffith
     185              :     //       DATE WRITTEN   November 2012
     186              :     //       MODIFIED       na
     187              :     //       RE-ENGINEERED  na
     188              : 
     189              :     // PURPOSE OF THIS SUBROUTINE:
     190              :     // Main entry point and simulation manager for heat exchanger
     191              : 
     192        34940 :     this->initialize(state);
     193              : 
     194              :     // for op scheme led HXs, only call controls if called from Loop Supply Side
     195        34940 :     if ((this->controlMode == ControlType::OperationSchemeModulated) || (this->controlMode == ControlType::OperationSchemeOnOff)) {
     196            0 :         if (calledFromLocation.loopNum == this->SupplySideLoop.loopNum) {
     197            0 :             this->control(state, CurLoad, FirstHVACIteration);
     198              :         }
     199              :     } else {
     200        34940 :         this->control(state, CurLoad, FirstHVACIteration);
     201              :     }
     202              : 
     203        69880 :     this->calculate(state,
     204        34940 :                     state.dataLoopNodes->Node(this->SupplySideLoop.inletNodeNum).MassFlowRate,
     205        34940 :                     state.dataLoopNodes->Node(this->DemandSideLoop.inletNodeNum).MassFlowRate);
     206        34940 : }
     207              : 
     208            2 : void GetFluidHeatExchangerInput(EnergyPlusData &state)
     209              : {
     210              : 
     211              :     // SUBROUTINE INFORMATION:
     212              :     //       AUTHOR         B. Griffith
     213              :     //       DATE WRITTEN   November 2012
     214              :     //       MODIFIED       na
     215              :     //       RE-ENGINEERED  na
     216              : 
     217              :     // PURPOSE OF THIS SUBROUTINE:
     218              :     // get input for heat exchanger model
     219              : 
     220              :     static constexpr std::string_view RoutineName("GetFluidHeatExchangerInput: ");
     221              :     static constexpr std::string_view routineName = "GetFluidHeatExchangerInput";
     222              : 
     223            2 :     bool ErrorsFound(false);
     224              :     int NumAlphas;        // Number of elements in the alpha array
     225              :     int NumNums;          // Number of elements in the numeric array
     226              :     int IOStat;           // IO Status when calling get input subroutine
     227            2 :     int MaxNumAlphas(0);  // argument for call to GetObjectDefMaxArgs
     228            2 :     int MaxNumNumbers(0); // argument for call to GetObjectDefMaxArgs
     229            2 :     int TotalArgs(0);     // argument for call to GetObjectDefMaxArgs
     230            2 :     Array1D_string cAlphaFieldNames;
     231            2 :     Array1D_string cNumericFieldNames;
     232            2 :     Array1D_bool lNumericFieldBlanks;
     233            2 :     Array1D_bool lAlphaFieldBlanks;
     234            2 :     Array1D_string cAlphaArgs;
     235            2 :     Array1D<Real64> rNumericArgs;
     236            2 :     std::string cCurrentModuleObject;
     237              : 
     238            2 :     cCurrentModuleObject = "HeatExchanger:FluidToFluid";
     239              : 
     240            2 :     state.dataPlantHXFluidToFluid->NumberOfPlantFluidHXs = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
     241            2 :     if (state.dataPlantHXFluidToFluid->NumberOfPlantFluidHXs == 0) return;
     242              : 
     243            2 :     state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, cCurrentModuleObject, TotalArgs, NumAlphas, NumNums);
     244            2 :     MaxNumNumbers = NumNums;
     245            2 :     MaxNumAlphas = NumAlphas;
     246              : 
     247            2 :     cAlphaFieldNames.allocate(MaxNumAlphas);
     248            2 :     cAlphaArgs.allocate(MaxNumAlphas);
     249            2 :     lAlphaFieldBlanks.dimension(MaxNumAlphas, false);
     250            2 :     cNumericFieldNames.allocate(MaxNumNumbers);
     251            2 :     rNumericArgs.dimension(MaxNumNumbers, 0.0);
     252            2 :     lNumericFieldBlanks.dimension(MaxNumNumbers, false);
     253              : 
     254            2 :     if (state.dataPlantHXFluidToFluid->NumberOfPlantFluidHXs > 0) {
     255            2 :         state.dataPlantHXFluidToFluid->FluidHX.allocate(state.dataPlantHXFluidToFluid->NumberOfPlantFluidHXs);
     256            8 :         for (int CompLoop = 1; CompLoop <= state.dataPlantHXFluidToFluid->NumberOfPlantFluidHXs; ++CompLoop) {
     257            6 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
     258              :                                                                      cCurrentModuleObject,
     259              :                                                                      CompLoop,
     260              :                                                                      cAlphaArgs,
     261              :                                                                      NumAlphas,
     262              :                                                                      rNumericArgs,
     263              :                                                                      NumNums,
     264              :                                                                      IOStat,
     265              :                                                                      lNumericFieldBlanks,
     266              :                                                                      lAlphaFieldBlanks,
     267              :                                                                      cAlphaFieldNames,
     268              :                                                                      cNumericFieldNames);
     269              : 
     270            6 :             ErrorObjectHeader eoh{routineName, cCurrentModuleObject, cAlphaArgs(1)};
     271              : 
     272            6 :             Util::IsNameEmpty(state, cAlphaArgs(1), cCurrentModuleObject, ErrorsFound);
     273              : 
     274            6 :             state.dataPlantHXFluidToFluid->FluidHX(CompLoop).Name = cAlphaArgs(1);
     275              : 
     276            6 :             if (lAlphaFieldBlanks(2)) {
     277            0 :                 state.dataPlantHXFluidToFluid->FluidHX(CompLoop).availSched = Sched::GetScheduleAlwaysOn(state);
     278            6 :             } else if ((state.dataPlantHXFluidToFluid->FluidHX(CompLoop).availSched = Sched::GetSchedule(state, cAlphaArgs(2))) == nullptr) {
     279            0 :                 ShowSevereItemNotFound(state, eoh, cAlphaFieldNames(2), cAlphaArgs(2));
     280            0 :                 ErrorsFound = true;
     281              :             }
     282              : 
     283            6 :             state.dataPlantHXFluidToFluid->FluidHX(CompLoop).DemandSideLoop.inletNodeNum =
     284           12 :                 NodeInputManager::GetOnlySingleNode(state,
     285            6 :                                                     cAlphaArgs(3),
     286              :                                                     ErrorsFound,
     287              :                                                     DataLoopNode::ConnectionObjectType::HeatExchangerFluidToFluid,
     288            6 :                                                     cAlphaArgs(1),
     289              :                                                     DataLoopNode::NodeFluidType::Water,
     290              :                                                     DataLoopNode::ConnectionType::Inlet,
     291              :                                                     NodeInputManager::CompFluidStream::Primary,
     292              :                                                     DataLoopNode::ObjectIsNotParent);
     293            6 :             state.dataPlantHXFluidToFluid->FluidHX(CompLoop).DemandSideLoop.outletNodeNum =
     294           18 :                 NodeInputManager::GetOnlySingleNode(state,
     295            6 :                                                     cAlphaArgs(4),
     296              :                                                     ErrorsFound,
     297              :                                                     DataLoopNode::ConnectionObjectType::HeatExchangerFluidToFluid,
     298            6 :                                                     cAlphaArgs(1),
     299              :                                                     DataLoopNode::NodeFluidType::Water,
     300              :                                                     DataLoopNode::ConnectionType::Outlet,
     301              :                                                     NodeInputManager::CompFluidStream::Primary,
     302              :                                                     DataLoopNode::ObjectIsNotParent);
     303           12 :             BranchNodeConnections::TestCompSet(
     304            6 :                 state, cCurrentModuleObject, cAlphaArgs(1), cAlphaArgs(3), cAlphaArgs(4), "Loop Demand Side Plant Nodes");
     305            6 :             state.dataPlantHXFluidToFluid->FluidHX(CompLoop).DemandSideLoop.DesignVolumeFlowRate = rNumericArgs(1);
     306            6 :             if (state.dataPlantHXFluidToFluid->FluidHX(CompLoop).DemandSideLoop.DesignVolumeFlowRate == DataSizing::AutoSize) {
     307            0 :                 state.dataPlantHXFluidToFluid->FluidHX(CompLoop).DemandSideLoop.DesignVolumeFlowRateWasAutoSized = true;
     308              :             }
     309              : 
     310            6 :             state.dataPlantHXFluidToFluid->FluidHX(CompLoop).SupplySideLoop.inletNodeNum =
     311           12 :                 NodeInputManager::GetOnlySingleNode(state,
     312            6 :                                                     cAlphaArgs(5),
     313              :                                                     ErrorsFound,
     314              :                                                     DataLoopNode::ConnectionObjectType::HeatExchangerFluidToFluid,
     315            6 :                                                     cAlphaArgs(1),
     316              :                                                     DataLoopNode::NodeFluidType::Water,
     317              :                                                     DataLoopNode::ConnectionType::Inlet,
     318              :                                                     NodeInputManager::CompFluidStream::Secondary,
     319              :                                                     DataLoopNode::ObjectIsNotParent);
     320            6 :             state.dataPlantHXFluidToFluid->FluidHX(CompLoop).SupplySideLoop.outletNodeNum =
     321           18 :                 NodeInputManager::GetOnlySingleNode(state,
     322            6 :                                                     cAlphaArgs(6),
     323              :                                                     ErrorsFound,
     324              :                                                     DataLoopNode::ConnectionObjectType::HeatExchangerFluidToFluid,
     325            6 :                                                     cAlphaArgs(1),
     326              :                                                     DataLoopNode::NodeFluidType::Water,
     327              :                                                     DataLoopNode::ConnectionType::Outlet,
     328              :                                                     NodeInputManager::CompFluidStream::Secondary,
     329              :                                                     DataLoopNode::ObjectIsNotParent);
     330           12 :             BranchNodeConnections::TestCompSet(
     331            6 :                 state, cCurrentModuleObject, cAlphaArgs(1), cAlphaArgs(5), cAlphaArgs(6), "Loop Supply Side Plant Nodes");
     332            6 :             state.dataPlantHXFluidToFluid->FluidHX(CompLoop).SupplySideLoop.DesignVolumeFlowRate = rNumericArgs(2);
     333            6 :             if (state.dataPlantHXFluidToFluid->FluidHX(CompLoop).SupplySideLoop.DesignVolumeFlowRate == DataSizing::AutoSize) {
     334            0 :                 state.dataPlantHXFluidToFluid->FluidHX(CompLoop).SupplySideLoop.DesignVolumeFlowRateWasAutoSized = true;
     335              :             }
     336              : 
     337            6 :             if (lAlphaFieldBlanks(7)) {
     338            0 :                 ShowSevereEmptyField(state, eoh, cAlphaFieldNames(7), cAlphaArgs(7));
     339            0 :                 ErrorsFound = true;
     340            6 :             } else if ((state.dataPlantHXFluidToFluid->FluidHX(CompLoop).HeatExchangeModelType =
     341           12 :                             static_cast<FluidHXType>(getEnumValue(fluidHXTypeNamesUC, cAlphaArgs(7)))) == FluidHXType::Invalid) {
     342            0 :                 ShowSevereInvalidKey(state, eoh, cAlphaFieldNames(7), cAlphaArgs(7));
     343            0 :                 ErrorsFound = true;
     344              :             }
     345              : 
     346            6 :             if (!lNumericFieldBlanks(3)) {
     347            6 :                 state.dataPlantHXFluidToFluid->FluidHX(CompLoop).UA = rNumericArgs(3);
     348            6 :                 if (state.dataPlantHXFluidToFluid->FluidHX(CompLoop).UA == DataSizing::AutoSize) {
     349            0 :                     state.dataPlantHXFluidToFluid->FluidHX(CompLoop).UAWasAutoSized = true;
     350              :                 }
     351              :             } else {
     352            0 :                 if (state.dataPlantHXFluidToFluid->FluidHX(CompLoop).HeatExchangeModelType != FluidHXType::Ideal) {
     353            0 :                     ShowSevereError(state, format("{}{}=\"{}\", invalid entry.", RoutineName, cCurrentModuleObject, cAlphaArgs(1)));
     354            0 :                     ShowContinueError(state, format("Missing entry for {}", cNumericFieldNames(3)));
     355            0 :                     ErrorsFound = true;
     356              :                 }
     357              :             }
     358              : 
     359            6 :             if (lAlphaFieldBlanks(8)) {
     360            0 :                 ShowSevereEmptyField(state, eoh, cAlphaFieldNames(8));
     361            0 :                 ErrorsFound = true;
     362            6 :             } else if ((state.dataPlantHXFluidToFluid->FluidHX(CompLoop).controlMode =
     363           12 :                             static_cast<ControlType>(getEnumValue(controlTypeNamesUC, cAlphaArgs(8)))) == ControlType::Invalid) {
     364            0 :                 ShowSevereInvalidKey(state, eoh, cAlphaFieldNames(8), cAlphaArgs(8));
     365            0 :                 ErrorsFound = true;
     366              :             }
     367              : 
     368            6 :             if (!lAlphaFieldBlanks(9)) {
     369            6 :                 state.dataPlantHXFluidToFluid->FluidHX(CompLoop).SetPointNodeNum =
     370           12 :                     NodeInputManager::GetOnlySingleNode(state,
     371            6 :                                                         cAlphaArgs(9),
     372              :                                                         ErrorsFound,
     373              :                                                         DataLoopNode::ConnectionObjectType::HeatExchangerFluidToFluid,
     374            6 :                                                         cAlphaArgs(1),
     375              :                                                         DataLoopNode::NodeFluidType::Water,
     376              :                                                         DataLoopNode::ConnectionType::Sensor,
     377              :                                                         NodeInputManager::CompFluidStream::Primary,
     378              :                                                         DataLoopNode::ObjectIsNotParent);
     379              :                 // check that node actually has setpoints on it
     380            6 :                 if ((state.dataPlantHXFluidToFluid->FluidHX(CompLoop).controlMode == ControlType::HeatingSetPointModulated) ||
     381            4 :                     (state.dataPlantHXFluidToFluid->FluidHX(CompLoop).controlMode == ControlType::HeatingSetPointOnOff) ||
     382            4 :                     (state.dataPlantHXFluidToFluid->FluidHX(CompLoop).controlMode == ControlType::CoolingSetPointModulated) ||
     383           12 :                     (state.dataPlantHXFluidToFluid->FluidHX(CompLoop).controlMode == ControlType::CoolingSetPointOnOff) ||
     384            2 :                     (state.dataPlantHXFluidToFluid->FluidHX(CompLoop).controlMode == ControlType::CoolingSetPointOnOffWithComponentOverride)) {
     385            4 :                     if (state.dataLoopNodes->Node(state.dataPlantHXFluidToFluid->FluidHX(CompLoop).SetPointNodeNum).TempSetPoint ==
     386              :                         DataLoopNode::SensedNodeFlagValue) {
     387            0 :                         if (!state.dataGlobal->AnyEnergyManagementSystemInModel) {
     388            0 :                             ShowSevereError(state, format("{} Missing temperature setpoint for DataLoopNode::Node = {}", RoutineName, cAlphaArgs(9)));
     389            0 :                             ShowContinueError(state, format("Occurs for {}=\"{}", cCurrentModuleObject, cAlphaArgs(1)));
     390            0 :                             ShowContinueError(state, " Use a setpoint manager to place a single temperature setpoint on the node");
     391            0 :                             ErrorsFound = true;
     392              :                         } else {
     393              :                             // need call to EMS to check node
     394            0 :                             bool NodeEMSSetPointMissing = false;
     395            0 :                             EMSManager::CheckIfNodeSetPointManagedByEMS(state,
     396            0 :                                                                         state.dataPlantHXFluidToFluid->FluidHX(CompLoop).SetPointNodeNum,
     397              :                                                                         HVAC::CtrlVarType::Temp,
     398              :                                                                         NodeEMSSetPointMissing);
     399            0 :                             if (NodeEMSSetPointMissing) {
     400            0 :                                 ShowSevereError(state, format("{} Missing temperature setpoint for node = {}", RoutineName, cAlphaArgs(9)));
     401            0 :                                 ShowContinueError(state, format("Occurs for {}=\"{}", cCurrentModuleObject, cAlphaArgs(1)));
     402            0 :                                 ShowContinueError(state, "Use a setpoint manager or EMS actuator to place a single temperature setpoint on the node");
     403            0 :                                 ErrorsFound = true;
     404              :                             }
     405              :                         }
     406              :                     }
     407            2 :                 } else if ((state.dataPlantHXFluidToFluid->FluidHX(CompLoop).controlMode == ControlType::DualDeadBandSetPointModulated) ||
     408            0 :                            (state.dataPlantHXFluidToFluid->FluidHX(CompLoop).controlMode == ControlType::DualDeadBandSetPointOnOff)) {
     409            2 :                     if ((state.dataLoopNodes->Node(state.dataPlantHXFluidToFluid->FluidHX(CompLoop).SetPointNodeNum).TempSetPointHi ==
     410            4 :                          DataLoopNode::SensedNodeFlagValue) ||
     411            2 :                         (state.dataLoopNodes->Node(state.dataPlantHXFluidToFluid->FluidHX(CompLoop).SetPointNodeNum).TempSetPointLo ==
     412              :                          DataLoopNode::SensedNodeFlagValue)) {
     413            0 :                         if (!state.dataGlobal->AnyEnergyManagementSystemInModel) {
     414            0 :                             ShowSevereError(state, format("{} Missing dual temperature setpoints for node = {}", RoutineName, cAlphaArgs(9)));
     415            0 :                             ShowContinueError(state, format("Occurs for {}=\"{}", cCurrentModuleObject, cAlphaArgs(1)));
     416            0 :                             ShowContinueError(state, " Use a setpoint manager to place a dual temperature setpoint on the node");
     417            0 :                             ErrorsFound = true;
     418              :                         } else {
     419              :                             // need call to EMS to check node
     420            0 :                             bool NodeEMSSetPointMissing = false;
     421            0 :                             EMSManager::CheckIfNodeSetPointManagedByEMS(state,
     422            0 :                                                                         state.dataPlantHXFluidToFluid->FluidHX(CompLoop).SetPointNodeNum,
     423              :                                                                         HVAC::CtrlVarType::Temp,
     424              :                                                                         NodeEMSSetPointMissing);
     425            0 :                             EMSManager::CheckIfNodeSetPointManagedByEMS(state,
     426            0 :                                                                         state.dataPlantHXFluidToFluid->FluidHX(CompLoop).SetPointNodeNum,
     427              :                                                                         HVAC::CtrlVarType::Temp,
     428              :                                                                         NodeEMSSetPointMissing);
     429            0 :                             if (NodeEMSSetPointMissing) {
     430            0 :                                 ShowSevereError(state, format("{} Missing temperature setpoint for node = {}", RoutineName, cAlphaArgs(9)));
     431            0 :                                 ShowContinueError(state, format("Occurs for {}=\"{}", cCurrentModuleObject, cAlphaArgs(1)));
     432            0 :                                 ShowContinueError(state, "Use a setpoint manager or EMS actuators to place a dual temperature setpoints on the node");
     433            0 :                                 ErrorsFound = true;
     434              :                             }
     435              :                         }
     436              :                     }
     437              :                 }
     438              : 
     439              :             } else {
     440              :                 // need to name a setpoint node if using a setpoint type control mode
     441            0 :                 if ((state.dataPlantHXFluidToFluid->FluidHX(CompLoop).controlMode == ControlType::HeatingSetPointModulated) ||
     442            0 :                     (state.dataPlantHXFluidToFluid->FluidHX(CompLoop).controlMode == ControlType::HeatingSetPointOnOff) ||
     443            0 :                     (state.dataPlantHXFluidToFluid->FluidHX(CompLoop).controlMode == ControlType::CoolingSetPointModulated) ||
     444            0 :                     (state.dataPlantHXFluidToFluid->FluidHX(CompLoop).controlMode == ControlType::CoolingSetPointOnOff) ||
     445            0 :                     (state.dataPlantHXFluidToFluid->FluidHX(CompLoop).controlMode == ControlType::DualDeadBandSetPointModulated) ||
     446            0 :                     (state.dataPlantHXFluidToFluid->FluidHX(CompLoop).controlMode == ControlType::DualDeadBandSetPointOnOff) ||
     447            0 :                     (state.dataPlantHXFluidToFluid->FluidHX(CompLoop).controlMode == ControlType::CoolingSetPointOnOffWithComponentOverride)) {
     448            0 :                     ShowSevereError(state, format("{}{}=\"{}\", invalid entry.", RoutineName, cCurrentModuleObject, cAlphaArgs(1)));
     449            0 :                     ShowContinueError(state, format("Missing entry for {}", cAlphaFieldNames(9)));
     450            0 :                     ErrorsFound = true;
     451              :                 }
     452              :             }
     453              : 
     454            6 :             if (!lNumericFieldBlanks(4)) {
     455            6 :                 state.dataPlantHXFluidToFluid->FluidHX(CompLoop).TempControlTol = rNumericArgs(4);
     456              :             } else {
     457            0 :                 state.dataPlantHXFluidToFluid->FluidHX(CompLoop).TempControlTol = 0.01;
     458              :             }
     459              : 
     460            6 :             std::string endUseCat = Util::makeUPPER(cAlphaArgs(10));
     461            6 :             if (endUseCat == "FREECOOLING")
     462            0 :                 state.dataPlantHXFluidToFluid->FluidHX(CompLoop).HeatTransferMeteringEndUse = OutputProcessor::EndUseCat::FreeCooling;
     463            6 :             else if (endUseCat == "HEATREJECTION")
     464            0 :                 state.dataPlantHXFluidToFluid->FluidHX(CompLoop).HeatTransferMeteringEndUse = OutputProcessor::EndUseCat::HeatRejection;
     465            6 :             else if (endUseCat == "HEATRECOVERYFORCOOLING")
     466            0 :                 state.dataPlantHXFluidToFluid->FluidHX(CompLoop).HeatTransferMeteringEndUse = OutputProcessor::EndUseCat::HeatRecoveryForCooling;
     467            6 :             else if (endUseCat == "HEATRECOVERYFORCOOLING")
     468            0 :                 state.dataPlantHXFluidToFluid->FluidHX(CompLoop).HeatTransferMeteringEndUse = OutputProcessor::EndUseCat::HeatRecoveryForHeating;
     469            6 :             else if (endUseCat == "LOOPTOLOOP")
     470            6 :                 state.dataPlantHXFluidToFluid->FluidHX(CompLoop).HeatTransferMeteringEndUse = OutputProcessor::EndUseCat::LoopToLoop;
     471              :             else {
     472            0 :                 ShowWarningError(
     473              :                     state,
     474            0 :                     format("{} = {}, {} is an invalid value for {}", cCurrentModuleObject, cAlphaArgs(1), cAlphaArgs(10), cAlphaFieldNames(10)));
     475            0 :                 ErrorsFound = true;
     476              :             }
     477              : 
     478            6 :             if (!lAlphaFieldBlanks(11)) {
     479            0 :                 state.dataPlantHXFluidToFluid->FluidHX(CompLoop).OtherCompSupplySideLoop.inletNodeNum =
     480            0 :                     NodeInputManager::GetOnlySingleNode(state,
     481            0 :                                                         cAlphaArgs(11),
     482              :                                                         ErrorsFound,
     483              :                                                         DataLoopNode::ConnectionObjectType::HeatExchangerFluidToFluid,
     484            0 :                                                         cAlphaArgs(1),
     485              :                                                         DataLoopNode::NodeFluidType::Water,
     486              :                                                         DataLoopNode::ConnectionType::Actuator,
     487              :                                                         NodeInputManager::CompFluidStream::Primary,
     488              :                                                         DataLoopNode::ObjectIsNotParent);
     489              :             } else {
     490            6 :                 if (state.dataPlantHXFluidToFluid->FluidHX(CompLoop).controlMode == ControlType::CoolingSetPointOnOffWithComponentOverride) {
     491            0 :                     ShowSevereError(state, format("{}{}=\"{}\", invalid entry.", RoutineName, cCurrentModuleObject, cAlphaArgs(1)));
     492            0 :                     ShowContinueError(state, format("Missing entry for {}", cAlphaFieldNames(11)));
     493            0 :                     ErrorsFound = true;
     494              :                 }
     495              :             }
     496              : 
     497            6 :             if (!lAlphaFieldBlanks(12)) {
     498            0 :                 state.dataPlantHXFluidToFluid->FluidHX(CompLoop).OtherCompDemandSideLoop.inletNodeNum =
     499            0 :                     NodeInputManager::GetOnlySingleNode(state,
     500            0 :                                                         cAlphaArgs(12),
     501              :                                                         ErrorsFound,
     502              :                                                         DataLoopNode::ConnectionObjectType::HeatExchangerFluidToFluid,
     503            0 :                                                         cAlphaArgs(1),
     504              :                                                         DataLoopNode::NodeFluidType::Water,
     505              :                                                         DataLoopNode::ConnectionType::Actuator,
     506              :                                                         NodeInputManager::CompFluidStream::Primary,
     507              :                                                         DataLoopNode::ObjectIsNotParent);
     508              :             } else {
     509            6 :                 if (state.dataPlantHXFluidToFluid->FluidHX(CompLoop).controlMode == ControlType::CoolingSetPointOnOffWithComponentOverride) {
     510            0 :                     ShowSevereError(state, format("{}{}=\"{}\", invalid entry.", RoutineName, cCurrentModuleObject, cAlphaArgs(1)));
     511            0 :                     ShowContinueError(state, format("Missing entry for {}", cAlphaFieldNames(12)));
     512            0 :                     ErrorsFound = true;
     513              :                 }
     514              :             }
     515              : 
     516            6 :             if (lAlphaFieldBlanks(13)) {
     517            6 :                 if (state.dataPlantHXFluidToFluid->FluidHX(CompLoop).controlMode == ControlType::CoolingSetPointOnOffWithComponentOverride) {
     518            0 :                     ShowSevereEmptyField(state, eoh, cAlphaFieldNames(13), cAlphaFieldNames(8), cAlphaArgs(8));
     519            0 :                     ErrorsFound = true;
     520              :                 }
     521            0 :             } else if ((state.dataPlantHXFluidToFluid->FluidHX(CompLoop).ControlSignalTemp =
     522            0 :                             static_cast<CtrlTempType>(getEnumValue(ctrlTempTypeNamesUC, cAlphaArgs(13)))) == CtrlTempType::Invalid) {
     523            0 :                 ShowSevereInvalidKey(state, eoh, cAlphaFieldNames(13), cAlphaArgs(13));
     524            0 :                 ErrorsFound = true;
     525              :             }
     526              : 
     527            6 :             if (!lNumericFieldBlanks(5)) {
     528            0 :                 state.dataPlantHXFluidToFluid->FluidHX(CompLoop).SizingFactor = rNumericArgs(5);
     529              :             } else {
     530            6 :                 state.dataPlantHXFluidToFluid->FluidHX(CompLoop).SizingFactor = 1.0;
     531              :             }
     532              : 
     533            6 :             if (!lNumericFieldBlanks(6)) {
     534            0 :                 state.dataPlantHXFluidToFluid->FluidHX(CompLoop).MinOperationTemp = rNumericArgs(6);
     535              :             } else {
     536            6 :                 state.dataPlantHXFluidToFluid->FluidHX(CompLoop).MinOperationTemp = -9999.0;
     537              :             }
     538              : 
     539            6 :             if (!lNumericFieldBlanks(7)) {
     540            0 :                 state.dataPlantHXFluidToFluid->FluidHX(CompLoop).MaxOperationTemp = rNumericArgs(7);
     541              :             } else {
     542            6 :                 state.dataPlantHXFluidToFluid->FluidHX(CompLoop).MaxOperationTemp = 9999.0;
     543              :             }
     544            6 :         }
     545              :     }
     546              : 
     547            2 :     if (ErrorsFound) {
     548            0 :         ShowFatalError(state, format("{}Errors found in processing {} input.", RoutineName, cCurrentModuleObject));
     549              :     }
     550            2 : }
     551              : 
     552            7 : void HeatExchangerStruct::setupOutputVars(EnergyPlusData &state)
     553              : {
     554           14 :     SetupOutputVariable(state,
     555              :                         "Fluid Heat Exchanger Heat Transfer Rate",
     556              :                         Constant::Units::W,
     557            7 :                         this->HeatTransferRate,
     558              :                         OutputProcessor::TimeStepType::System,
     559              :                         OutputProcessor::StoreType::Average,
     560            7 :                         this->Name);
     561              : 
     562           14 :     SetupOutputVariable(state,
     563              :                         "Fluid Heat Exchanger Heat Transfer Energy",
     564              :                         Constant::Units::J,
     565            7 :                         this->HeatTransferEnergy,
     566              :                         OutputProcessor::TimeStepType::System,
     567              :                         OutputProcessor::StoreType::Sum,
     568            7 :                         this->Name,
     569              :                         Constant::eResource::EnergyTransfer,
     570              :                         OutputProcessor::Group::Plant,
     571              :                         this->HeatTransferMeteringEndUse);
     572              : 
     573           14 :     SetupOutputVariable(state,
     574              :                         "Fluid Heat Exchanger Loop Supply Side Mass Flow Rate",
     575              :                         Constant::Units::kg_s,
     576            7 :                         this->SupplySideLoop.InletMassFlowRate,
     577              :                         OutputProcessor::TimeStepType::System,
     578              :                         OutputProcessor::StoreType::Average,
     579            7 :                         this->Name);
     580              : 
     581           14 :     SetupOutputVariable(state,
     582              :                         "Fluid Heat Exchanger Loop Supply Side Inlet Temperature",
     583              :                         Constant::Units::C,
     584            7 :                         this->SupplySideLoop.InletTemp,
     585              :                         OutputProcessor::TimeStepType::System,
     586              :                         OutputProcessor::StoreType::Average,
     587            7 :                         this->Name);
     588              : 
     589           14 :     SetupOutputVariable(state,
     590              :                         "Fluid Heat Exchanger Loop Supply Side Outlet Temperature",
     591              :                         Constant::Units::C,
     592            7 :                         this->SupplySideLoop.OutletTemp,
     593              :                         OutputProcessor::TimeStepType::System,
     594              :                         OutputProcessor::StoreType::Average,
     595            7 :                         this->Name);
     596              : 
     597           14 :     SetupOutputVariable(state,
     598              :                         "Fluid Heat Exchanger Loop Demand Side Mass Flow Rate",
     599              :                         Constant::Units::kg_s,
     600            7 :                         this->DemandSideLoop.InletMassFlowRate,
     601              :                         OutputProcessor::TimeStepType::System,
     602              :                         OutputProcessor::StoreType::Average,
     603            7 :                         this->Name);
     604              : 
     605           14 :     SetupOutputVariable(state,
     606              :                         "Fluid Heat Exchanger Loop Demand Side Inlet Temperature",
     607              :                         Constant::Units::C,
     608            7 :                         this->DemandSideLoop.InletTemp,
     609              :                         OutputProcessor::TimeStepType::System,
     610              :                         OutputProcessor::StoreType::Average,
     611            7 :                         this->Name);
     612              : 
     613           14 :     SetupOutputVariable(state,
     614              :                         "Fluid Heat Exchanger Loop Demand Side Outlet Temperature",
     615              :                         Constant::Units::C,
     616            7 :                         this->DemandSideLoop.OutletTemp,
     617              :                         OutputProcessor::TimeStepType::System,
     618              :                         OutputProcessor::StoreType::Average,
     619            7 :                         this->Name);
     620              : 
     621           14 :     SetupOutputVariable(state,
     622              :                         "Fluid Heat Exchanger Operation Status",
     623              :                         Constant::Units::None,
     624            7 :                         this->OperationStatus,
     625              :                         OutputProcessor::TimeStepType::System,
     626              :                         OutputProcessor::StoreType::Average,
     627            7 :                         this->Name);
     628              : 
     629           14 :     SetupOutputVariable(state,
     630              :                         "Fluid Heat Exchanger Effectiveness",
     631              :                         Constant::Units::None,
     632            7 :                         this->Effectiveness,
     633              :                         OutputProcessor::TimeStepType::System,
     634              :                         OutputProcessor::StoreType::Average,
     635            7 :                         this->Name);
     636            7 : }
     637              : 
     638        35002 : void HeatExchangerStruct::initialize(EnergyPlusData &state)
     639              : {
     640              : 
     641              :     // SUBROUTINE INFORMATION:
     642              :     //       AUTHOR         B. Griffith
     643              :     //       DATE WRITTEN   november, 2012
     644              :     //       MODIFIED       na
     645              :     //       RE-ENGINEERED  na
     646              : 
     647              :     // PURPOSE OF THIS SUBROUTINE:
     648              :     // Initialize heat exchanger model
     649              : 
     650              :     static constexpr std::string_view RoutineNameNoColon("InitFluidHeatExchanger");
     651              : 
     652        35002 :     this->oneTimeInit(state); // plant setup
     653              : 
     654        35002 :     if (state.dataGlobal->BeginEnvrnFlag && this->MyEnvrnFlag && (state.dataPlnt->PlantFirstSizesOkayToFinalize)) {
     655              : 
     656           12 :         Real64 rho = this->DemandSideLoop.loop->glycol->getDensity(state, Constant::InitConvTemp, RoutineNameNoColon);
     657           12 :         this->DemandSideLoop.MassFlowRateMax = rho * this->DemandSideLoop.DesignVolumeFlowRate;
     658           12 :         PlantUtilities::InitComponentNodes(state,
     659              :                                            this->DemandSideLoop.MassFlowRateMin,
     660              :                                            this->DemandSideLoop.MassFlowRateMax,
     661              :                                            this->DemandSideLoop.inletNodeNum,
     662              :                                            this->DemandSideLoop.outletNodeNum);
     663              : 
     664           12 :         rho = this->SupplySideLoop.loop->glycol->getDensity(state, Constant::InitConvTemp, RoutineNameNoColon);
     665           12 :         this->SupplySideLoop.MassFlowRateMax = rho * this->SupplySideLoop.DesignVolumeFlowRate;
     666           12 :         PlantUtilities::InitComponentNodes(state,
     667              :                                            this->SupplySideLoop.MassFlowRateMin,
     668              :                                            this->SupplySideLoop.MassFlowRateMax,
     669              :                                            this->SupplySideLoop.inletNodeNum,
     670              :                                            this->SupplySideLoop.outletNodeNum);
     671           12 :         this->MyEnvrnFlag = false;
     672              :     }
     673        35002 :     if (!state.dataGlobal->BeginEnvrnFlag) {
     674        34642 :         this->MyEnvrnFlag = true;
     675              :     }
     676              : 
     677        35002 :     this->DemandSideLoop.InletTemp = state.dataLoopNodes->Node(this->DemandSideLoop.inletNodeNum).Temp;
     678        35002 :     this->SupplySideLoop.InletTemp = state.dataLoopNodes->Node(this->SupplySideLoop.inletNodeNum).Temp;
     679              : 
     680        35002 :     if (this->controlMode == ControlType::CoolingSetPointOnOffWithComponentOverride) {
     681              :         // store current value for setpoint in central plant loop data structure
     682            2 :         this->OtherCompSupplySideLoop.comp->FreeCoolCntrlMinCntrlTemp =
     683            2 :             state.dataLoopNodes->Node(this->SetPointNodeNum).TempSetPoint - this->TempControlTol; // issue #5626, include control tolerance
     684              :     }
     685        35002 : }
     686              : 
     687           30 : void HeatExchangerStruct::size(EnergyPlusData &state)
     688              : {
     689              : 
     690              :     // SUBROUTINE INFORMATION:
     691              :     //       AUTHOR         B. Griffith
     692              :     //       DATE WRITTEN   December 2012
     693              :     //       MODIFIED       na
     694              :     //       RE-ENGINEERED  na
     695              : 
     696              :     // PURPOSE OF THIS SUBROUTINE:
     697              :     // Size plant heat exchanger flow rates, UA, and max capacity
     698              : 
     699              :     // METHODOLOGY EMPLOYED:
     700              :     // the supply side flow rate is obtained from the plant sizing structure
     701              :     // the demand side is sized to match the supply side
     702              :     // the UA is sized for an effectiveness of 1.0 using sizing temps
     703              :     // the capacity uses the full HX model
     704              : 
     705              :     static constexpr std::string_view RoutineName("SizeFluidHeatExchanger");
     706              : 
     707              :     // first deal with Loop Supply Side
     708           30 :     int PltSizNumSupSide = this->SupplySideLoop.loop->PlantSizNum;
     709           30 :     int PltSizNumDmdSide = this->DemandSideLoop.loop->PlantSizNum;
     710           30 :     Real64 tmpSupSideDesignVolFlowRate = this->SupplySideLoop.DesignVolumeFlowRate;
     711           30 :     if (this->SupplySideLoop.DesignVolumeFlowRateWasAutoSized) {
     712            0 :         if (PltSizNumSupSide > 0) {
     713            0 :             if (state.dataSize->PlantSizData(PltSizNumSupSide).DesVolFlowRate >= HVAC::SmallWaterVolFlow) {
     714            0 :                 tmpSupSideDesignVolFlowRate = state.dataSize->PlantSizData(PltSizNumSupSide).DesVolFlowRate * this->SizingFactor;
     715            0 :                 if (state.dataPlnt->PlantFirstSizesOkayToFinalize) this->SupplySideLoop.DesignVolumeFlowRate = tmpSupSideDesignVolFlowRate;
     716              :             } else {
     717            0 :                 tmpSupSideDesignVolFlowRate = 0.0;
     718            0 :                 if (state.dataPlnt->PlantFirstSizesOkayToFinalize) this->SupplySideLoop.DesignVolumeFlowRate = tmpSupSideDesignVolFlowRate;
     719              :             }
     720            0 :             if (state.dataPlnt->PlantFinalSizesOkayToReport) {
     721            0 :                 BaseSizer::reportSizerOutput(state,
     722              :                                              "HeatExchanger:FluidToFluid",
     723              :                                              this->Name,
     724              :                                              "Loop Supply Side Design Fluid Flow Rate [m3/s]",
     725              :                                              this->SupplySideLoop.DesignVolumeFlowRate);
     726              :             }
     727            0 :             if (state.dataPlnt->PlantFirstSizesOkayToReport) {
     728            0 :                 BaseSizer::reportSizerOutput(state,
     729              :                                              "HeatExchanger:FluidToFluid",
     730              :                                              this->Name,
     731              :                                              "Initial Loop Supply Side Design Fluid Flow Rate [m3/s]",
     732              :                                              this->SupplySideLoop.DesignVolumeFlowRate);
     733              :             }
     734              :         } else {
     735            0 :             if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
     736            0 :                 ShowSevereError(state, "SizeFluidHeatExchanger: Autosizing of requires a loop Sizing:Plant object");
     737            0 :                 ShowContinueError(state, format("Occurs in heat exchanger object={}", this->Name));
     738              :             }
     739              :         }
     740              :     }
     741           30 :     PlantUtilities::RegisterPlantCompDesignFlow(state, this->SupplySideLoop.inletNodeNum, tmpSupSideDesignVolFlowRate);
     742              : 
     743              :     // second deal with Loop Demand Side
     744           30 :     Real64 tmpDmdSideDesignVolFlowRate = this->DemandSideLoop.DesignVolumeFlowRate;
     745           30 :     if (this->DemandSideLoop.DesignVolumeFlowRateWasAutoSized) {
     746            0 :         if (tmpSupSideDesignVolFlowRate > HVAC::SmallWaterVolFlow) {
     747            0 :             tmpDmdSideDesignVolFlowRate = tmpSupSideDesignVolFlowRate;
     748            0 :             if (state.dataPlnt->PlantFirstSizesOkayToFinalize) this->DemandSideLoop.DesignVolumeFlowRate = tmpDmdSideDesignVolFlowRate;
     749              :         } else {
     750            0 :             tmpDmdSideDesignVolFlowRate = 0.0;
     751            0 :             if (state.dataPlnt->PlantFirstSizesOkayToFinalize) this->DemandSideLoop.DesignVolumeFlowRate = tmpDmdSideDesignVolFlowRate;
     752              :         }
     753            0 :         if (state.dataPlnt->PlantFinalSizesOkayToReport) {
     754            0 :             BaseSizer::reportSizerOutput(state,
     755              :                                          "HeatExchanger:FluidToFluid",
     756              :                                          this->Name,
     757              :                                          "Loop Demand Side Design Fluid Flow Rate [m3/s]",
     758              :                                          this->DemandSideLoop.DesignVolumeFlowRate);
     759              :         }
     760            0 :         if (state.dataPlnt->PlantFirstSizesOkayToReport) {
     761            0 :             BaseSizer::reportSizerOutput(state,
     762              :                                          "HeatExchanger:FluidToFluid",
     763              :                                          this->Name,
     764              :                                          "Initial Loop Demand Side Design Fluid Flow Rate [m3/s]",
     765              :                                          this->DemandSideLoop.DesignVolumeFlowRate);
     766              :         }
     767              :     }
     768           30 :     PlantUtilities::RegisterPlantCompDesignFlow(state, this->DemandSideLoop.inletNodeNum, tmpDmdSideDesignVolFlowRate);
     769              : 
     770              :     // size UA if needed
     771           30 :     if (this->UAWasAutoSized) {
     772              :         // get nominal delta T between two loops
     773            0 :         if (PltSizNumSupSide > 0 && PltSizNumDmdSide > 0) {
     774              : 
     775            0 :             Real64 tmpDeltaTloopToLoop(0.0);
     776              : 
     777            0 :             switch (state.dataSize->PlantSizData(PltSizNumSupSide).LoopType) {
     778              : 
     779            0 :             case DataSizing::TypeOfPlantLoop::Heating:
     780              :             case DataSizing::TypeOfPlantLoop::Steam: {
     781              :                 tmpDeltaTloopToLoop =
     782            0 :                     std::abs((state.dataSize->PlantSizData(PltSizNumSupSide).ExitTemp - state.dataSize->PlantSizData(PltSizNumSupSide).DeltaT) -
     783            0 :                              state.dataSize->PlantSizData(PltSizNumDmdSide).ExitTemp);
     784            0 :                 break;
     785              :             }
     786            0 :             case DataSizing::TypeOfPlantLoop::Cooling:
     787              :             case DataSizing::TypeOfPlantLoop::Condenser: {
     788              :                 tmpDeltaTloopToLoop =
     789            0 :                     std::abs((state.dataSize->PlantSizData(PltSizNumSupSide).ExitTemp + state.dataSize->PlantSizData(PltSizNumSupSide).DeltaT) -
     790            0 :                              state.dataSize->PlantSizData(PltSizNumDmdSide).ExitTemp);
     791            0 :                 break;
     792              :             }
     793            0 :             default:
     794            0 :                 assert(false);
     795              :                 break;
     796              :             }
     797              : 
     798            0 :             tmpDeltaTloopToLoop = max(2.0, tmpDeltaTloopToLoop);
     799            0 :             Real64 tmpDeltaTSupLoop = state.dataSize->PlantSizData(PltSizNumSupSide).DeltaT;
     800            0 :             if (tmpSupSideDesignVolFlowRate >= HVAC::SmallWaterVolFlow) {
     801              : 
     802            0 :                 Real64 Cp = this->SupplySideLoop.loop->glycol->getSpecificHeat(state, Constant::InitConvTemp, RoutineName);
     803              : 
     804            0 :                 Real64 rho = this->SupplySideLoop.loop->glycol->getDensity(state, Constant::InitConvTemp, RoutineName);
     805              : 
     806            0 :                 Real64 tmpDesCap = Cp * rho * tmpDeltaTSupLoop * tmpSupSideDesignVolFlowRate;
     807            0 :                 if (state.dataPlnt->PlantFirstSizesOkayToFinalize) this->UA = tmpDesCap / tmpDeltaTloopToLoop;
     808              :             } else {
     809            0 :                 if (state.dataPlnt->PlantFirstSizesOkayToFinalize) this->UA = 0.0;
     810              :             }
     811            0 :             if (state.dataPlnt->PlantFinalSizesOkayToReport) {
     812            0 :                 BaseSizer::reportSizerOutput(
     813              :                     state, "HeatExchanger:FluidToFluid", this->Name, "Heat Exchanger U-Factor Times Area Value [W/C]", this->UA);
     814            0 :                 BaseSizer::reportSizerOutput(state,
     815              :                                              "HeatExchanger:FluidToFluid",
     816              :                                              this->Name,
     817              :                                              "Loop-to-loop Temperature Difference Used to Size Heat Exchanger U-Factor Times Area Value [C]",
     818              :                                              tmpDeltaTloopToLoop);
     819              :             }
     820            0 :             if (state.dataPlnt->PlantFirstSizesOkayToReport) {
     821            0 :                 BaseSizer::reportSizerOutput(
     822              :                     state, "HeatExchanger:FluidToFluid", this->Name, "Initial Heat Exchanger U-Factor Times Area Value [W/C]", this->UA);
     823            0 :                 BaseSizer::reportSizerOutput(state,
     824              :                                              "HeatExchanger:FluidToFluid",
     825              :                                              this->Name,
     826              :                                              "Initial Loop-to-loop Temperature Difference Used to Size Heat Exchanger U-Factor Times Area Value [C]",
     827              :                                              tmpDeltaTloopToLoop);
     828              :             }
     829            0 :         } else {
     830            0 :             if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
     831            0 :                 ShowSevereError(state, "SizeFluidHeatExchanger: Autosizing of heat Exchanger UA requires a loop Sizing:Plant objects for both loops");
     832            0 :                 ShowContinueError(state, format("Occurs in heat exchanger object={}", this->Name));
     833              :             }
     834              :         }
     835              :     }
     836              : 
     837              :     // size capacities for load range based op schemes
     838           30 :     if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
     839              : 
     840            6 :         if (PltSizNumSupSide > 0) {
     841            0 :             switch (state.dataSize->PlantSizData(PltSizNumSupSide).LoopType) {
     842            0 :             case DataSizing::TypeOfPlantLoop::Heating:
     843              :             case DataSizing::TypeOfPlantLoop::Steam: {
     844            0 :                 state.dataLoopNodes->Node(this->SupplySideLoop.inletNodeNum).Temp =
     845            0 :                     (state.dataSize->PlantSizData(PltSizNumSupSide).ExitTemp - state.dataSize->PlantSizData(PltSizNumSupSide).DeltaT);
     846            0 :                 break;
     847              :             }
     848            0 :             case DataSizing::TypeOfPlantLoop::Cooling:
     849              :             case DataSizing::TypeOfPlantLoop::Condenser: {
     850            0 :                 state.dataLoopNodes->Node(this->SupplySideLoop.inletNodeNum).Temp =
     851            0 :                     (state.dataSize->PlantSizData(PltSizNumSupSide).ExitTemp + state.dataSize->PlantSizData(PltSizNumSupSide).DeltaT);
     852            0 :                 break;
     853              :             }
     854            0 :             default:
     855            0 :                 break;
     856              :             }
     857              : 
     858              :         } else { // don't rely on sizing, use loop setpoints
     859              :             // loop supply side
     860            6 :             if (this->SupplySideLoop.loop->LoopDemandCalcScheme == DataPlant::LoopDemandCalcScheme::SingleSetPoint) {
     861            4 :                 state.dataLoopNodes->Node(this->SupplySideLoop.inletNodeNum).Temp =
     862            4 :                     state.dataLoopNodes->Node(this->SupplySideLoop.loop->TempSetPointNodeNum).TempSetPoint;
     863            2 :             } else if (this->SupplySideLoop.loop->LoopDemandCalcScheme == DataPlant::LoopDemandCalcScheme::DualSetPointDeadBand) {
     864            2 :                 state.dataLoopNodes->Node(this->SupplySideLoop.inletNodeNum).Temp =
     865            2 :                     (state.dataLoopNodes->Node(this->SupplySideLoop.loop->TempSetPointNodeNum).TempSetPointHi +
     866            2 :                      state.dataLoopNodes->Node(this->SupplySideLoop.loop->TempSetPointNodeNum).TempSetPointLo) /
     867              :                     2.0;
     868              :             }
     869              :         }
     870              : 
     871            6 :         if (PltSizNumDmdSide > 0) {
     872            0 :             state.dataLoopNodes->Node(this->DemandSideLoop.inletNodeNum).Temp = state.dataSize->PlantSizData(PltSizNumDmdSide).ExitTemp;
     873              :         } else { // don't rely on sizing, use loop setpoints
     874              :             // loop demand side
     875            6 :             if (this->DemandSideLoop.loop->LoopDemandCalcScheme == DataPlant::LoopDemandCalcScheme::SingleSetPoint) {
     876            2 :                 state.dataLoopNodes->Node(this->DemandSideLoop.inletNodeNum).Temp =
     877            2 :                     state.dataLoopNodes->Node(this->DemandSideLoop.loop->TempSetPointNodeNum).TempSetPoint;
     878            4 :             } else if (this->DemandSideLoop.loop->LoopDemandCalcScheme == DataPlant::LoopDemandCalcScheme::DualSetPointDeadBand) {
     879            4 :                 state.dataLoopNodes->Node(this->DemandSideLoop.inletNodeNum).Temp =
     880            4 :                     (state.dataLoopNodes->Node(this->DemandSideLoop.loop->TempSetPointNodeNum).TempSetPointHi +
     881            4 :                      state.dataLoopNodes->Node(this->DemandSideLoop.loop->TempSetPointNodeNum).TempSetPointLo) /
     882              :                     2.0;
     883              :             }
     884              :         }
     885              : 
     886            6 :         Real64 rho = this->SupplySideLoop.loop->glycol->getDensity(state, Constant::InitConvTemp, RoutineName);
     887            6 :         Real64 SupSideMdot = this->SupplySideLoop.DesignVolumeFlowRate * rho;
     888            6 :         rho = this->DemandSideLoop.loop->glycol->getDensity(state, Constant::InitConvTemp, RoutineName);
     889            6 :         Real64 DmdSideMdot = this->DemandSideLoop.DesignVolumeFlowRate * rho;
     890              : 
     891            6 :         this->calculate(state, SupSideMdot, DmdSideMdot);
     892            6 :         this->SupplySideLoop.MaxLoad = std::abs(this->HeatTransferRate);
     893              :     }
     894           30 :     if (state.dataPlnt->PlantFinalSizesOkayToReport) {
     895            6 :         OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchMechType, this->Name, "HeatExchanger:FluidToFluid");
     896            6 :         OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchMechNomCap, this->Name, this->SupplySideLoop.MaxLoad);
     897              :     }
     898           30 : }
     899              : 
     900        34942 : void HeatExchangerStruct::control(EnergyPlusData &state, Real64 MyLoad, bool FirstHVACIteration)
     901              : {
     902              : 
     903              :     // SUBROUTINE INFORMATION:
     904              :     //       AUTHOR         B. Griffith
     905              :     //       DATE WRITTEN   November 2012
     906              :     //       MODIFIED       na
     907              :     //       RE-ENGINEERED  na
     908              : 
     909              :     // PURPOSE OF THIS SUBROUTINE:
     910              :     // determine control state for fluid to fluid heat exchanger
     911              :     // make fluid flow requests accordingly
     912              : 
     913              :     // METHODOLOGY EMPLOYED:
     914              :     // long CASE statement for different control options
     915              : 
     916              :     static constexpr std::string_view RoutineName("ControlFluidHeatExchanger");
     917              : 
     918              :     Real64 mdotSupSide;
     919              :     Real64 mdotDmdSide;
     920              : 
     921              :     // check if available by schedule
     922              :     bool ScheduledOff;
     923        34942 :     Real64 AvailSchedValue = this->availSched->getCurrentVal();
     924        34942 :     if (AvailSchedValue <= 0) {
     925            0 :         ScheduledOff = true;
     926              :     } else {
     927        34942 :         ScheduledOff = false;
     928              :     }
     929              : 
     930              :     // check if operational limits trip off unit
     931        34942 :     bool LimitTrippedOff = false;
     932        69884 :     if ((state.dataLoopNodes->Node(this->SupplySideLoop.inletNodeNum).Temp < this->MinOperationTemp) ||
     933        34942 :         (state.dataLoopNodes->Node(this->DemandSideLoop.inletNodeNum).Temp < this->MinOperationTemp)) {
     934            0 :         LimitTrippedOff = true;
     935              :     }
     936        69884 :     if ((state.dataLoopNodes->Node(this->SupplySideLoop.inletNodeNum).Temp > this->MaxOperationTemp) ||
     937        34942 :         (state.dataLoopNodes->Node(this->DemandSideLoop.inletNodeNum).Temp > this->MaxOperationTemp)) {
     938            0 :         LimitTrippedOff = true;
     939              :     }
     940              : 
     941        34942 :     if (!ScheduledOff && !LimitTrippedOff) {
     942              : 
     943        34942 :         switch (this->controlMode) {
     944              : 
     945            0 :         case ControlType::UncontrolledOn: {
     946              : 
     947              :             // make passive request for supply side loop flow
     948            0 :             mdotSupSide = this->SupplySideLoop.MassFlowRateMax;
     949            0 :             PlantUtilities::SetComponentFlowRate(
     950              :                 state, mdotSupSide, this->SupplySideLoop.inletNodeNum, this->SupplySideLoop.outletNodeNum, this->SupplySideLoop);
     951            0 :             if (mdotSupSide > DataBranchAirLoopPlant::MassFlowTolerance) {
     952              :                 // if supply side loop has massflow, request demand side flow
     953            0 :                 mdotDmdSide = this->DemandSideLoop.MassFlowRateMax;
     954              :             } else {
     955            0 :                 mdotDmdSide = 0.0;
     956              :             }
     957            0 :             PlantUtilities::SetComponentFlowRate(
     958              :                 state, mdotDmdSide, this->DemandSideLoop.inletNodeNum, this->DemandSideLoop.outletNodeNum, this->DemandSideLoop);
     959              : 
     960            0 :             break;
     961              :         }
     962            0 :         case ControlType::OperationSchemeModulated: {
     963              : 
     964            0 :             if (std::abs(MyLoad) > HVAC::SmallLoad) {
     965            0 :                 if (MyLoad < -1.0 * HVAC::SmallLoad) { // requesting cooling
     966            0 :                     Real64 DeltaTCooling = this->SupplySideLoop.InletTemp - this->DemandSideLoop.InletTemp;
     967            0 :                     if (DeltaTCooling > this->TempControlTol) { // can do cooling so turn on
     968            0 :                         mdotSupSide = this->SupplySideLoop.MassFlowRateMax;
     969            0 :                         PlantUtilities::SetComponentFlowRate(
     970              :                             state, mdotSupSide, this->SupplySideLoop.inletNodeNum, this->SupplySideLoop.outletNodeNum, this->SupplySideLoop);
     971            0 :                         if (mdotSupSide > DataBranchAirLoopPlant::MassFlowTolerance) {
     972              :                             // if supply side loop has massflow, request demand side flow
     973            0 :                             Real64 cp = this->SupplySideLoop.loop->glycol->getSpecificHeat(state, this->SupplySideLoop.InletTemp, RoutineName);
     974            0 :                             Real64 TargetLeavingTemp = this->SupplySideLoop.InletTemp - std::abs(MyLoad) / (cp * mdotSupSide);
     975              : 
     976            0 :                             this->findDemandSideLoopFlow(state, TargetLeavingTemp, HXAction::CoolingSupplySideLoop);
     977              :                         } else { // no flow on supply side so do not request flow on demand side
     978            0 :                             mdotDmdSide = 0.0;
     979            0 :                             PlantUtilities::SetComponentFlowRate(
     980              :                                 state, mdotDmdSide, this->DemandSideLoop.inletNodeNum, this->DemandSideLoop.outletNodeNum, this->DemandSideLoop);
     981              :                         }
     982              :                     } else { // not able to cool so turn off
     983            0 :                         mdotSupSide = 0.0;
     984            0 :                         PlantUtilities::SetComponentFlowRate(
     985              :                             state, mdotSupSide, this->SupplySideLoop.inletNodeNum, this->SupplySideLoop.outletNodeNum, this->SupplySideLoop);
     986              :                         // issue 4959, make demand side flow request on first hvac iteration so demand side loop can run as a trial to get a
     987              :                         // fresh demand side inlet temperature value
     988            0 :                         if (FirstHVACIteration) {
     989            0 :                             mdotDmdSide = this->DemandSideLoop.MassFlowRateMax;
     990              :                         } else {
     991            0 :                             mdotDmdSide = 0.0;
     992              :                         }
     993            0 :                         PlantUtilities::SetComponentFlowRate(
     994              :                             state, mdotDmdSide, this->DemandSideLoop.inletNodeNum, this->DemandSideLoop.outletNodeNum, this->DemandSideLoop);
     995              :                     }
     996              : 
     997              :                 } else { // requesting heating
     998            0 :                     Real64 DeltaTHeating = this->DemandSideLoop.InletTemp - this->SupplySideLoop.InletTemp;
     999            0 :                     if (DeltaTHeating > this->TempControlTol) { // can do heating so turn on
    1000            0 :                         mdotSupSide = this->SupplySideLoop.MassFlowRateMax;
    1001            0 :                         PlantUtilities::SetComponentFlowRate(
    1002              :                             state, mdotSupSide, this->SupplySideLoop.inletNodeNum, this->SupplySideLoop.outletNodeNum, this->SupplySideLoop);
    1003            0 :                         if (mdotSupSide > DataBranchAirLoopPlant::MassFlowTolerance) {
    1004            0 :                             Real64 cp = this->SupplySideLoop.loop->glycol->getSpecificHeat(state, this->SupplySideLoop.InletTemp, RoutineName);
    1005            0 :                             Real64 TargetLeavingTemp = this->SupplySideLoop.InletTemp + std::abs(MyLoad) / (cp * mdotSupSide);
    1006              : 
    1007            0 :                             this->findDemandSideLoopFlow(state, TargetLeavingTemp, HXAction::HeatingSupplySideLoop);
    1008              :                         } else { // no flow on supply side so do not request flow on demand side
    1009            0 :                             mdotDmdSide = 0.0;
    1010            0 :                             PlantUtilities::SetComponentFlowRate(
    1011              :                                 state, mdotDmdSide, this->DemandSideLoop.inletNodeNum, this->DemandSideLoop.outletNodeNum, this->DemandSideLoop);
    1012              :                         }
    1013              :                     } else { // not able to heat so turn off
    1014            0 :                         mdotSupSide = 0.0;
    1015            0 :                         PlantUtilities::SetComponentFlowRate(
    1016              :                             state, mdotSupSide, this->SupplySideLoop.inletNodeNum, this->SupplySideLoop.outletNodeNum, this->SupplySideLoop);
    1017              :                         // issue 4959, make demand side flow request on first hvac iteration so demand side loop can run as a trial to get a
    1018              :                         // fresh demand side inlet temperature value
    1019            0 :                         if (FirstHVACIteration) {
    1020            0 :                             mdotDmdSide = this->DemandSideLoop.MassFlowRateMax;
    1021              :                         } else {
    1022            0 :                             mdotDmdSide = 0.0;
    1023              :                         }
    1024            0 :                         PlantUtilities::SetComponentFlowRate(
    1025              :                             state, mdotDmdSide, this->DemandSideLoop.inletNodeNum, this->DemandSideLoop.outletNodeNum, this->DemandSideLoop);
    1026              :                     }
    1027              :                 }
    1028              : 
    1029              :             } else { //  no load
    1030            0 :                 mdotSupSide = 0.0;
    1031            0 :                 PlantUtilities::SetComponentFlowRate(
    1032              :                     state, mdotSupSide, this->SupplySideLoop.inletNodeNum, this->SupplySideLoop.outletNodeNum, this->SupplySideLoop);
    1033            0 :                 mdotDmdSide = 0.0;
    1034            0 :                 PlantUtilities::SetComponentFlowRate(
    1035              :                     state, mdotDmdSide, this->DemandSideLoop.inletNodeNum, this->DemandSideLoop.outletNodeNum, this->DemandSideLoop);
    1036              :             }
    1037              : 
    1038            0 :             break;
    1039              :         }
    1040            0 :         case ControlType::OperationSchemeOnOff: {
    1041            0 :             if (std::abs(MyLoad) > HVAC::SmallLoad) {
    1042            0 :                 if (MyLoad < HVAC::SmallLoad) { // requesting cooling
    1043            0 :                     Real64 DeltaTCooling = this->SupplySideLoop.InletTemp - this->DemandSideLoop.InletTemp;
    1044            0 :                     if (DeltaTCooling > this->TempControlTol) { // can do cooling so turn on
    1045            0 :                         mdotSupSide = this->SupplySideLoop.MassFlowRateMax;
    1046            0 :                         PlantUtilities::SetComponentFlowRate(
    1047              :                             state, mdotSupSide, this->SupplySideLoop.inletNodeNum, this->SupplySideLoop.outletNodeNum, this->SupplySideLoop);
    1048            0 :                         if (mdotSupSide > DataBranchAirLoopPlant::MassFlowTolerance) {
    1049            0 :                             mdotDmdSide = this->DemandSideLoop.MassFlowRateMax;
    1050              :                         } else {
    1051            0 :                             mdotDmdSide = 0.0;
    1052              :                         }
    1053              : 
    1054            0 :                         PlantUtilities::SetComponentFlowRate(
    1055              :                             state, mdotDmdSide, this->DemandSideLoop.inletNodeNum, this->DemandSideLoop.outletNodeNum, this->DemandSideLoop);
    1056              :                     } else { // not able to cool so turn off
    1057            0 :                         mdotSupSide = 0.0;
    1058            0 :                         PlantUtilities::SetComponentFlowRate(
    1059              :                             state, mdotSupSide, this->SupplySideLoop.inletNodeNum, this->SupplySideLoop.outletNodeNum, this->SupplySideLoop);
    1060              :                         // issue 4959, make demand side flow request on first hvac iteration so demand side loop can run as a trial to get a
    1061              :                         // fresh demand side inlet temperature value
    1062            0 :                         if (FirstHVACIteration) {
    1063            0 :                             mdotDmdSide = this->DemandSideLoop.MassFlowRateMax;
    1064              :                         } else {
    1065            0 :                             mdotDmdSide = 0.0;
    1066              :                         }
    1067            0 :                         PlantUtilities::SetComponentFlowRate(
    1068              :                             state, mdotDmdSide, this->DemandSideLoop.inletNodeNum, this->DemandSideLoop.outletNodeNum, this->DemandSideLoop);
    1069              :                     }
    1070              : 
    1071              :                 } else { // requesting heating
    1072            0 :                     Real64 DeltaTHeating = this->DemandSideLoop.InletTemp - this->SupplySideLoop.InletTemp;
    1073            0 :                     if (DeltaTHeating > this->TempControlTol) { // can do heating so turn on
    1074            0 :                         mdotSupSide = this->SupplySideLoop.MassFlowRateMax;
    1075            0 :                         PlantUtilities::SetComponentFlowRate(
    1076              :                             state, mdotSupSide, this->SupplySideLoop.inletNodeNum, this->SupplySideLoop.outletNodeNum, this->SupplySideLoop);
    1077            0 :                         if (mdotSupSide > DataBranchAirLoopPlant::MassFlowTolerance) {
    1078            0 :                             mdotDmdSide = this->DemandSideLoop.MassFlowRateMax;
    1079              :                         } else {
    1080            0 :                             mdotDmdSide = 0.0;
    1081              :                         }
    1082            0 :                         PlantUtilities::SetComponentFlowRate(
    1083              :                             state, mdotDmdSide, this->DemandSideLoop.inletNodeNum, this->DemandSideLoop.outletNodeNum, this->DemandSideLoop);
    1084              :                     } else { // not able to heat so turn off
    1085            0 :                         mdotSupSide = 0.0;
    1086            0 :                         PlantUtilities::SetComponentFlowRate(
    1087              :                             state, mdotSupSide, this->SupplySideLoop.inletNodeNum, this->SupplySideLoop.outletNodeNum, this->SupplySideLoop);
    1088              :                         // issue 4959, make demand side flow request on first hvac iteration so demand side loop can run as a trial to get a
    1089              :                         // fresh demand side inlet temperature value
    1090            0 :                         if (FirstHVACIteration) {
    1091            0 :                             mdotDmdSide = this->DemandSideLoop.MassFlowRateMax;
    1092              :                         } else {
    1093            0 :                             mdotDmdSide = 0.0;
    1094              :                         }
    1095            0 :                         PlantUtilities::SetComponentFlowRate(
    1096              :                             state, mdotDmdSide, this->DemandSideLoop.inletNodeNum, this->DemandSideLoop.outletNodeNum, this->DemandSideLoop);
    1097              :                     }
    1098              :                 }
    1099              : 
    1100              :             } else { // no load
    1101            0 :                 mdotSupSide = 0.0;
    1102            0 :                 PlantUtilities::SetComponentFlowRate(
    1103              :                     state, mdotSupSide, this->SupplySideLoop.inletNodeNum, this->SupplySideLoop.outletNodeNum, this->SupplySideLoop);
    1104            0 :                 mdotDmdSide = 0.0;
    1105            0 :                 PlantUtilities::SetComponentFlowRate(
    1106              :                     state, mdotDmdSide, this->DemandSideLoop.inletNodeNum, this->DemandSideLoop.outletNodeNum, this->DemandSideLoop);
    1107              :             }
    1108              : 
    1109            0 :             break;
    1110              :         }
    1111        11648 :         case ControlType::HeatingSetPointModulated: {
    1112              : 
    1113        11648 :             Real64 SetPointTemp = state.dataLoopNodes->Node(this->SetPointNodeNum).TempSetPoint;
    1114        11648 :             Real64 DeltaTHeating = this->DemandSideLoop.InletTemp - this->SupplySideLoop.InletTemp;
    1115        11648 :             if ((DeltaTHeating > this->TempControlTol) && (SetPointTemp > this->SupplySideLoop.InletTemp)) {
    1116              :                 // can and want to heat
    1117         5750 :                 mdotSupSide = this->SupplySideLoop.MassFlowRateMax;
    1118         5750 :                 PlantUtilities::SetComponentFlowRate(
    1119              :                     state, mdotSupSide, this->SupplySideLoop.inletNodeNum, this->SupplySideLoop.outletNodeNum, this->SupplySideLoop);
    1120         5750 :                 if (mdotSupSide > DataBranchAirLoopPlant::MassFlowTolerance) {
    1121              : 
    1122         5750 :                     Real64 TargetLeavingTemp = SetPointTemp;
    1123         5750 :                     this->findDemandSideLoopFlow(state, TargetLeavingTemp, HXAction::HeatingSupplySideLoop);
    1124              :                 } else {
    1125            0 :                     mdotDmdSide = 0.0;
    1126            0 :                     PlantUtilities::SetComponentFlowRate(
    1127              :                         state, mdotDmdSide, this->DemandSideLoop.inletNodeNum, this->DemandSideLoop.outletNodeNum, this->DemandSideLoop);
    1128              :                 }
    1129         5750 :             } else { // not able are wanting to heat so turn off
    1130         5898 :                 mdotSupSide = 0.0;
    1131         5898 :                 PlantUtilities::SetComponentFlowRate(
    1132              :                     state, mdotSupSide, this->SupplySideLoop.inletNodeNum, this->SupplySideLoop.outletNodeNum, this->SupplySideLoop);
    1133              :                 // issue 4959, make demand side flow request on first hvac iteration so demand side loop can run as a trial to get a fresh
    1134              :                 // demand side inlet temperature value
    1135         5898 :                 if (FirstHVACIteration) {
    1136         2388 :                     mdotDmdSide = this->DemandSideLoop.MassFlowRateMax;
    1137              :                 } else {
    1138         3510 :                     mdotDmdSide = 0.0;
    1139              :                 }
    1140         5898 :                 PlantUtilities::SetComponentFlowRate(
    1141              :                     state, mdotDmdSide, this->DemandSideLoop.inletNodeNum, this->DemandSideLoop.outletNodeNum, this->DemandSideLoop);
    1142              :             }
    1143              : 
    1144        11648 :             break;
    1145              :         }
    1146            0 :         case ControlType::HeatingSetPointOnOff: {
    1147              : 
    1148            0 :             Real64 SetPointTemp = state.dataLoopNodes->Node(this->SetPointNodeNum).TempSetPoint;
    1149            0 :             Real64 DeltaTHeating = this->DemandSideLoop.InletTemp - this->SupplySideLoop.InletTemp;
    1150            0 :             if ((DeltaTHeating > this->TempControlTol) && (SetPointTemp > this->SupplySideLoop.InletTemp)) {
    1151              :                 // can and want to heat
    1152            0 :                 mdotSupSide = this->SupplySideLoop.MassFlowRateMax;
    1153            0 :                 PlantUtilities::SetComponentFlowRate(
    1154              :                     state, mdotSupSide, this->SupplySideLoop.inletNodeNum, this->SupplySideLoop.outletNodeNum, this->SupplySideLoop);
    1155            0 :                 if (mdotSupSide > DataBranchAirLoopPlant::MassFlowTolerance) {
    1156            0 :                     mdotDmdSide = this->DemandSideLoop.MassFlowRateMax;
    1157              :                 } else {
    1158            0 :                     mdotDmdSide = 0.0;
    1159              :                 }
    1160            0 :                 PlantUtilities::SetComponentFlowRate(
    1161              :                     state, mdotDmdSide, this->DemandSideLoop.inletNodeNum, this->DemandSideLoop.outletNodeNum, this->DemandSideLoop);
    1162              :             } else { // not able or are wanting to heat so turn off
    1163            0 :                 mdotSupSide = 0.0;
    1164            0 :                 PlantUtilities::SetComponentFlowRate(
    1165              :                     state, mdotSupSide, this->SupplySideLoop.inletNodeNum, this->SupplySideLoop.outletNodeNum, this->SupplySideLoop);
    1166              :                 // issue 4959, make demand side flow request on first hvac iteration so demand side loop can run as a trial to get a fresh
    1167              :                 // demand side inlet temperature value
    1168            0 :                 if (FirstHVACIteration) {
    1169            0 :                     mdotDmdSide = this->DemandSideLoop.MassFlowRateMax;
    1170              :                 } else {
    1171            0 :                     mdotDmdSide = 0.0;
    1172              :                 }
    1173            0 :                 PlantUtilities::SetComponentFlowRate(
    1174              :                     state, mdotDmdSide, this->DemandSideLoop.inletNodeNum, this->DemandSideLoop.outletNodeNum, this->DemandSideLoop);
    1175              :             }
    1176              : 
    1177            0 :             break;
    1178              :         }
    1179        11648 :         case ControlType::CoolingSetPointModulated: {
    1180              : 
    1181        11648 :             Real64 SetPointTemp = state.dataLoopNodes->Node(this->SetPointNodeNum).TempSetPoint;
    1182        11648 :             Real64 DeltaTCooling = this->SupplySideLoop.InletTemp - this->DemandSideLoop.InletTemp;
    1183        11648 :             if ((DeltaTCooling > this->TempControlTol) && (SetPointTemp < this->SupplySideLoop.InletTemp)) {
    1184              :                 // can and want to cool
    1185         5750 :                 mdotSupSide = this->SupplySideLoop.MassFlowRateMax;
    1186         5750 :                 PlantUtilities::SetComponentFlowRate(
    1187              :                     state, mdotSupSide, this->SupplySideLoop.inletNodeNum, this->SupplySideLoop.outletNodeNum, this->SupplySideLoop);
    1188         5750 :                 if (mdotSupSide > DataBranchAirLoopPlant::MassFlowTolerance) {
    1189         5750 :                     Real64 TargetLeavingTemp = SetPointTemp;
    1190         5750 :                     this->findDemandSideLoopFlow(state, TargetLeavingTemp, HXAction::CoolingSupplySideLoop);
    1191              :                 } else {
    1192            0 :                     mdotDmdSide = 0.0;
    1193            0 :                     PlantUtilities::SetComponentFlowRate(
    1194              :                         state, mdotDmdSide, this->DemandSideLoop.inletNodeNum, this->DemandSideLoop.outletNodeNum, this->DemandSideLoop);
    1195              :                 }
    1196         5750 :             } else { // not able or are wanting to cool so turn off
    1197         5898 :                 mdotSupSide = 0.0;
    1198         5898 :                 PlantUtilities::SetComponentFlowRate(
    1199              :                     state, mdotSupSide, this->SupplySideLoop.inletNodeNum, this->SupplySideLoop.outletNodeNum, this->SupplySideLoop);
    1200              :                 // issue 4959, make demand side flow request on first hvac iteration so demand side loop can run as a trial to get a fresh
    1201              :                 // demand side inlet temperature value
    1202         5898 :                 if (FirstHVACIteration) {
    1203         2388 :                     mdotDmdSide = this->DemandSideLoop.MassFlowRateMax;
    1204              :                 } else {
    1205         3510 :                     mdotDmdSide = 0.0;
    1206              :                 }
    1207         5898 :                 PlantUtilities::SetComponentFlowRate(
    1208              :                     state, mdotDmdSide, this->DemandSideLoop.inletNodeNum, this->DemandSideLoop.outletNodeNum, this->DemandSideLoop);
    1209              :             }
    1210              : 
    1211        11648 :             break;
    1212              :         }
    1213            0 :         case ControlType::CoolingSetPointOnOff: {
    1214              : 
    1215            0 :             Real64 SetPointTemp = state.dataLoopNodes->Node(this->SetPointNodeNum).TempSetPoint;
    1216            0 :             Real64 DeltaTCooling = this->SupplySideLoop.InletTemp - this->DemandSideLoop.InletTemp;
    1217            0 :             if ((DeltaTCooling > this->TempControlTol) && (SetPointTemp < this->SupplySideLoop.InletTemp)) {
    1218              :                 // can and want to cool
    1219            0 :                 mdotSupSide = this->SupplySideLoop.MassFlowRateMax;
    1220            0 :                 PlantUtilities::SetComponentFlowRate(
    1221              :                     state, mdotSupSide, this->SupplySideLoop.inletNodeNum, this->SupplySideLoop.outletNodeNum, this->SupplySideLoop);
    1222            0 :                 if (mdotSupSide > DataBranchAirLoopPlant::MassFlowTolerance) {
    1223            0 :                     mdotDmdSide = this->DemandSideLoop.MassFlowRateMax;
    1224              :                 } else {
    1225            0 :                     mdotDmdSide = 0.0;
    1226              :                 }
    1227            0 :                 PlantUtilities::SetComponentFlowRate(
    1228              :                     state, mdotDmdSide, this->DemandSideLoop.inletNodeNum, this->DemandSideLoop.outletNodeNum, this->DemandSideLoop);
    1229              :             } else { // not able or are wanting to cool so turn off
    1230            0 :                 mdotSupSide = 0.0;
    1231            0 :                 PlantUtilities::SetComponentFlowRate(
    1232              :                     state, mdotSupSide, this->SupplySideLoop.inletNodeNum, this->SupplySideLoop.outletNodeNum, this->SupplySideLoop);
    1233              :                 // issue 4959, make demand side flow request on first hvac iteration so demand side loop can run as a trial to get a fresh
    1234              :                 // demand side inlet temperature value
    1235            0 :                 if (FirstHVACIteration) {
    1236            0 :                     mdotDmdSide = this->DemandSideLoop.MassFlowRateMax;
    1237              :                 } else {
    1238            0 :                     mdotDmdSide = 0.0;
    1239              :                 }
    1240            0 :                 PlantUtilities::SetComponentFlowRate(
    1241              :                     state, mdotDmdSide, this->DemandSideLoop.inletNodeNum, this->DemandSideLoop.outletNodeNum, this->DemandSideLoop);
    1242              :             }
    1243              : 
    1244            0 :             break;
    1245              :         }
    1246        11644 :         case ControlType::DualDeadBandSetPointModulated: {
    1247              : 
    1248        11644 :             Real64 SetPointTempLo = state.dataLoopNodes->Node(this->SetPointNodeNum).TempSetPointLo;
    1249        11644 :             Real64 SetPointTempHi = state.dataLoopNodes->Node(this->SetPointNodeNum).TempSetPointHi;
    1250        11644 :             Real64 DeltaTCooling = this->SupplySideLoop.InletTemp - this->DemandSideLoop.InletTemp;
    1251        11644 :             Real64 DeltaTHeating = this->DemandSideLoop.InletTemp - this->SupplySideLoop.InletTemp;
    1252        11644 :             if ((DeltaTCooling > this->TempControlTol) && (SetPointTempHi < this->SupplySideLoop.InletTemp)) {
    1253              : 
    1254              :                 // can and want to cool
    1255         5736 :                 mdotSupSide = this->SupplySideLoop.MassFlowRateMax;
    1256         5736 :                 PlantUtilities::SetComponentFlowRate(
    1257              :                     state, mdotSupSide, this->SupplySideLoop.inletNodeNum, this->SupplySideLoop.outletNodeNum, this->SupplySideLoop);
    1258         5736 :                 if (mdotSupSide > DataBranchAirLoopPlant::MassFlowTolerance) {
    1259         5736 :                     Real64 TargetLeavingTemp = SetPointTempHi;
    1260         5736 :                     this->findDemandSideLoopFlow(state, TargetLeavingTemp, HXAction::CoolingSupplySideLoop);
    1261              :                 } else {
    1262            0 :                     mdotDmdSide = 0.0;
    1263            0 :                     PlantUtilities::SetComponentFlowRate(
    1264              :                         state, mdotDmdSide, this->DemandSideLoop.inletNodeNum, this->DemandSideLoop.outletNodeNum, this->DemandSideLoop);
    1265              :                 }
    1266        11644 :             } else if ((DeltaTHeating > this->TempControlTol) && (SetPointTempLo > this->SupplySideLoop.InletTemp)) {
    1267              :                 // can and want to heat
    1268         5736 :                 mdotSupSide = this->SupplySideLoop.MassFlowRateMax;
    1269         5736 :                 PlantUtilities::SetComponentFlowRate(
    1270              :                     state, mdotSupSide, this->SupplySideLoop.inletNodeNum, this->SupplySideLoop.outletNodeNum, this->SupplySideLoop);
    1271         5736 :                 if (mdotSupSide > DataBranchAirLoopPlant::MassFlowTolerance) {
    1272         5736 :                     Real64 TargetLeavingTemp = SetPointTempLo;
    1273         5736 :                     this->findDemandSideLoopFlow(state, TargetLeavingTemp, HXAction::HeatingSupplySideLoop);
    1274              :                 } else {
    1275            0 :                     mdotDmdSide = 0.0;
    1276            0 :                     PlantUtilities::SetComponentFlowRate(
    1277              :                         state, mdotDmdSide, this->DemandSideLoop.inletNodeNum, this->DemandSideLoop.outletNodeNum, this->DemandSideLoop);
    1278              :                 }
    1279         5736 :             } else { // not able or don't want conditioning
    1280          172 :                 mdotSupSide = 0.0;
    1281          172 :                 PlantUtilities::SetComponentFlowRate(
    1282              :                     state, mdotSupSide, this->SupplySideLoop.inletNodeNum, this->SupplySideLoop.outletNodeNum, this->SupplySideLoop);
    1283              :                 // issue 4959, make demand side flow request on first hvac iteration so demand side loop can run as a trial to get a fresh
    1284              :                 // demand side inlet temperature value
    1285          172 :                 if (FirstHVACIteration) {
    1286          100 :                     mdotDmdSide = this->DemandSideLoop.MassFlowRateMax;
    1287              :                 } else {
    1288           72 :                     mdotDmdSide = 0.0;
    1289              :                 }
    1290          172 :                 PlantUtilities::SetComponentFlowRate(
    1291              :                     state, mdotDmdSide, this->DemandSideLoop.inletNodeNum, this->DemandSideLoop.outletNodeNum, this->DemandSideLoop);
    1292              :             }
    1293              : 
    1294        11644 :             break;
    1295              :         }
    1296            0 :         case ControlType::DualDeadBandSetPointOnOff: {
    1297              : 
    1298            0 :             Real64 SetPointTempLo = state.dataLoopNodes->Node(this->SetPointNodeNum).TempSetPointLo;
    1299            0 :             Real64 SetPointTempHi = state.dataLoopNodes->Node(this->SetPointNodeNum).TempSetPointHi;
    1300            0 :             Real64 DeltaTCooling = this->SupplySideLoop.InletTemp - this->DemandSideLoop.InletTemp;
    1301            0 :             Real64 DeltaTHeating = this->DemandSideLoop.InletTemp - this->SupplySideLoop.InletTemp;
    1302            0 :             if ((DeltaTCooling > this->TempControlTol) && (SetPointTempHi < this->SupplySideLoop.InletTemp)) {
    1303              :                 // can and want to cool
    1304            0 :                 mdotSupSide = this->SupplySideLoop.MassFlowRateMax;
    1305            0 :                 PlantUtilities::SetComponentFlowRate(
    1306              :                     state, mdotSupSide, this->SupplySideLoop.inletNodeNum, this->SupplySideLoop.outletNodeNum, this->SupplySideLoop);
    1307            0 :                 if (mdotSupSide > DataBranchAirLoopPlant::MassFlowTolerance) {
    1308            0 :                     mdotDmdSide = this->DemandSideLoop.MassFlowRateMax;
    1309              :                 } else {
    1310            0 :                     mdotDmdSide = 0.0;
    1311              :                 }
    1312            0 :                 PlantUtilities::SetComponentFlowRate(
    1313              :                     state, mdotDmdSide, this->DemandSideLoop.inletNodeNum, this->DemandSideLoop.outletNodeNum, this->DemandSideLoop);
    1314            0 :             } else if ((DeltaTHeating > this->TempControlTol) && (SetPointTempLo > this->SupplySideLoop.InletTemp)) {
    1315              :                 // can and want to heat
    1316            0 :                 mdotSupSide = this->SupplySideLoop.MassFlowRateMax;
    1317            0 :                 PlantUtilities::SetComponentFlowRate(
    1318              :                     state, mdotSupSide, this->SupplySideLoop.inletNodeNum, this->SupplySideLoop.outletNodeNum, this->SupplySideLoop);
    1319            0 :                 if (mdotSupSide > DataBranchAirLoopPlant::MassFlowTolerance) {
    1320            0 :                     mdotDmdSide = this->DemandSideLoop.MassFlowRateMax;
    1321              :                 } else {
    1322            0 :                     mdotDmdSide = 0.0;
    1323              :                 }
    1324            0 :                 PlantUtilities::SetComponentFlowRate(
    1325              :                     state, mdotDmdSide, this->DemandSideLoop.inletNodeNum, this->DemandSideLoop.outletNodeNum, this->DemandSideLoop);
    1326              :             } else { // not able or don't want conditioning
    1327            0 :                 mdotSupSide = 0.0;
    1328            0 :                 PlantUtilities::SetComponentFlowRate(
    1329              :                     state, mdotSupSide, this->SupplySideLoop.inletNodeNum, this->SupplySideLoop.outletNodeNum, this->SupplySideLoop);
    1330              :                 // issue 4959, make demand side flow request on first hvac iteration so demand side loop can run as a trial to get a fresh
    1331              :                 // demand side inlet temperature value
    1332            0 :                 if (FirstHVACIteration) {
    1333            0 :                     mdotDmdSide = this->DemandSideLoop.MassFlowRateMax;
    1334              :                 } else {
    1335            0 :                     mdotDmdSide = 0.0;
    1336              :                 }
    1337            0 :                 PlantUtilities::SetComponentFlowRate(
    1338              :                     state, mdotDmdSide, this->DemandSideLoop.inletNodeNum, this->DemandSideLoop.outletNodeNum, this->DemandSideLoop);
    1339              :             }
    1340              : 
    1341            0 :             break;
    1342              :         }
    1343            2 :         case ControlType::CoolingDifferentialOnOff: {
    1344              : 
    1345            2 :             Real64 DeltaTCooling = this->SupplySideLoop.InletTemp - this->DemandSideLoop.InletTemp;
    1346            2 :             if (DeltaTCooling > this->TempControlTol) {
    1347              :                 //  want to cool
    1348            0 :                 mdotSupSide = this->SupplySideLoop.MassFlowRateMax;
    1349            0 :                 PlantUtilities::SetComponentFlowRate(
    1350              :                     state, mdotSupSide, this->SupplySideLoop.inletNodeNum, this->SupplySideLoop.outletNodeNum, this->SupplySideLoop);
    1351            0 :                 if (mdotSupSide > DataBranchAirLoopPlant::MassFlowTolerance) {
    1352            0 :                     mdotDmdSide = this->DemandSideLoop.MassFlowRateMax;
    1353              :                 } else {
    1354            0 :                     mdotDmdSide = 0.0;
    1355              :                 }
    1356            0 :                 PlantUtilities::SetComponentFlowRate(
    1357              :                     state, mdotDmdSide, this->DemandSideLoop.inletNodeNum, this->DemandSideLoop.outletNodeNum, this->DemandSideLoop);
    1358              :             } else { // not wanting to cool so turn off
    1359            2 :                 mdotSupSide = 0.0;
    1360            2 :                 PlantUtilities::SetComponentFlowRate(
    1361              :                     state, mdotSupSide, this->SupplySideLoop.inletNodeNum, this->SupplySideLoop.outletNodeNum, this->SupplySideLoop);
    1362              :                 // issue 4959, make demand side flow request on first hvac iteration so demand side loop can run as a trial to get a fresh
    1363              :                 // demand side inlet temperature value
    1364            2 :                 if (FirstHVACIteration) {
    1365            1 :                     mdotDmdSide = this->DemandSideLoop.MassFlowRateMax;
    1366              :                 } else {
    1367            1 :                     mdotDmdSide = 0.0;
    1368              :                 }
    1369            2 :                 PlantUtilities::SetComponentFlowRate(
    1370              :                     state, mdotDmdSide, this->DemandSideLoop.inletNodeNum, this->DemandSideLoop.outletNodeNum, this->DemandSideLoop);
    1371              :             }
    1372              : 
    1373            2 :             break;
    1374              :         }
    1375            0 :         case ControlType::CoolingSetPointOnOffWithComponentOverride: {
    1376              : 
    1377            0 :             Real64 ControlSignalValue(0.0);
    1378              : 
    1379            0 :             switch (this->ControlSignalTemp) {
    1380            0 :             case CtrlTempType::WetBulbTemperature: {
    1381            0 :                 ControlSignalValue = state.dataEnvrn->OutWetBulbTemp;
    1382            0 :                 break;
    1383              :             }
    1384            0 :             case CtrlTempType::DryBulbTemperature: {
    1385            0 :                 ControlSignalValue = state.dataEnvrn->OutDryBulbTemp;
    1386            0 :                 break;
    1387              :             }
    1388            0 :             case CtrlTempType::LoopTemperature: {
    1389            0 :                 ControlSignalValue = state.dataLoopNodes->Node(this->OtherCompDemandSideLoop.inletNodeNum).TempLastTimestep;
    1390            0 :                 break;
    1391              :             }
    1392            0 :             default:
    1393            0 :                 assert(false);
    1394              :                 break;
    1395              :             }
    1396              : 
    1397            0 :             Real64 SetPointTemp = state.dataLoopNodes->Node(this->SetPointNodeNum).TempSetPoint;
    1398            0 :             Real64 DeltaTCooling = SetPointTemp - ControlSignalValue;
    1399              :             // obtain shut down state
    1400            0 :             bool ChillerShutDown = this->OtherCompSupplySideLoop.comp->FreeCoolCntrlShutDown;
    1401            0 :             if (ChillerShutDown && (DeltaTCooling > this->TempControlTol)) {
    1402              :                 // can and want to cool
    1403            0 :                 mdotSupSide = this->SupplySideLoop.MassFlowRateMax;
    1404            0 :                 PlantUtilities::SetComponentFlowRate(
    1405              :                     state, mdotSupSide, this->SupplySideLoop.inletNodeNum, this->SupplySideLoop.outletNodeNum, this->SupplySideLoop);
    1406            0 :                 if (mdotSupSide > DataBranchAirLoopPlant::MassFlowTolerance) {
    1407            0 :                     mdotDmdSide = this->DemandSideLoop.MassFlowRateMax;
    1408              :                 } else {
    1409            0 :                     mdotDmdSide = 0.0;
    1410              :                 }
    1411            0 :                 PlantUtilities::SetComponentFlowRate(
    1412              :                     state, mdotDmdSide, this->DemandSideLoop.inletNodeNum, this->DemandSideLoop.outletNodeNum, this->DemandSideLoop);
    1413              : 
    1414              :             } else {
    1415            0 :                 mdotSupSide = 0.0;
    1416            0 :                 PlantUtilities::SetComponentFlowRate(
    1417              :                     state, mdotSupSide, this->SupplySideLoop.inletNodeNum, this->SupplySideLoop.outletNodeNum, this->SupplySideLoop);
    1418              :                 // issue 4959, make demand side flow request on first hvac iteration so demand side loop can run as a trial to get a fresh
    1419              :                 // demand side inlet temperature value
    1420            0 :                 if (FirstHVACIteration) {
    1421            0 :                     mdotDmdSide = this->DemandSideLoop.MassFlowRateMax;
    1422              :                 } else {
    1423            0 :                     mdotDmdSide = 0.0;
    1424              :                 }
    1425            0 :                 PlantUtilities::SetComponentFlowRate(
    1426              :                     state, mdotDmdSide, this->DemandSideLoop.inletNodeNum, this->DemandSideLoop.outletNodeNum, this->DemandSideLoop);
    1427              :             }
    1428            0 :             break;
    1429              :         }
    1430            0 :         default:
    1431            0 :             break;
    1432              :         }
    1433              : 
    1434        34942 :     } else { // scheduled off
    1435            0 :         mdotSupSide = 0.0;
    1436            0 :         PlantUtilities::SetComponentFlowRate(
    1437              :             state, mdotSupSide, this->SupplySideLoop.inletNodeNum, this->SupplySideLoop.outletNodeNum, this->SupplySideLoop);
    1438            0 :         mdotDmdSide = 0.0;
    1439            0 :         PlantUtilities::SetComponentFlowRate(
    1440              :             state, mdotDmdSide, this->DemandSideLoop.inletNodeNum, this->DemandSideLoop.outletNodeNum, this->DemandSideLoop);
    1441              :     }
    1442        34942 : }
    1443              : 
    1444       142906 : void HeatExchangerStruct::calculate(EnergyPlusData &state, Real64 const SupSideMdot, Real64 const DmdSideMdot)
    1445              : {
    1446              : 
    1447              :     // SUBROUTINE INFORMATION:
    1448              :     //       AUTHOR         B.Griffith, derived from CalcEconHeatExchanger by Sankaranarayanan K P aug. 2007
    1449              :     //       DATE WRITTEN   November 2012
    1450              :     //       MODIFIED       na
    1451              :     //       RE-ENGINEERED  na
    1452              : 
    1453              :     // PURPOSE OF THIS SUBROUTINE:
    1454              :     // Evalutate heat exchanger model and calculate leaving temperatures
    1455              : 
    1456              :     // METHODOLOGY EMPLOYED:
    1457              :     // apply heat transfer model depending on type of HX used
    1458              : 
    1459              :     static constexpr std::string_view RoutineName("CalcFluidHeatExchanger");
    1460              : 
    1461       142906 :     int constexpr CmaxMixedCminUnmixed(40);
    1462       142906 :     int constexpr CmaxUnMixedCminMixed(41);
    1463              : 
    1464       142906 :     Real64 SupSideLoopInletTemp = state.dataLoopNodes->Node(this->SupplySideLoop.inletNodeNum).Temp;
    1465       142906 :     Real64 DmdSideLoopInletTemp = state.dataLoopNodes->Node(this->DemandSideLoop.inletNodeNum).Temp;
    1466              : 
    1467              :     // specific heat of fluid entering from supply side loop at inlet temp
    1468       142906 :     Real64 SupSideLoopInletCp = this->SupplySideLoop.loop->glycol->getSpecificHeat(state, SupSideLoopInletTemp, RoutineName);
    1469              : 
    1470              :     // specific heat of fluid entering from demand side loop at inlet temp
    1471       142906 :     Real64 DmdSideLoopInletCp = this->DemandSideLoop.loop->glycol->getSpecificHeat(state, DmdSideLoopInletTemp, RoutineName);
    1472              : 
    1473       142906 :     Real64 SupSideCapRate = SupSideMdot * SupSideLoopInletCp;
    1474       142906 :     Real64 DmdSideCapRate = DmdSideMdot * DmdSideLoopInletCp;
    1475       142906 :     Real64 MinCapRate = min(SupSideCapRate, DmdSideCapRate);
    1476       142906 :     Real64 MaxCapRate = max(SupSideCapRate, DmdSideCapRate);
    1477              : 
    1478       142906 :     if (MinCapRate > 0.0) {
    1479              : 
    1480        96504 :         switch (this->HeatExchangeModelType) {
    1481              : 
    1482        96504 :         case FluidHXType::CrossFlowBothUnMixed: {
    1483        96504 :             Real64 NTU = this->UA / MinCapRate;
    1484        96504 :             Real64 CapRatio = MinCapRate / MaxCapRate;
    1485        96504 :             Real64 ExpCheckValue1 = std::pow(NTU, 0.22) / CapRatio;
    1486        96504 :             Real64 ExpCheckValue2 = -CapRatio * std::pow(NTU, 0.78);
    1487        96504 :             if ((ExpCheckValue1 > DataPrecisionGlobals::EXP_UpperLimit) || (ExpCheckValue2 > DataPrecisionGlobals::EXP_UpperLimit)) {
    1488           12 :                 if (-NTU >= DataPrecisionGlobals::EXP_LowerLimit) {
    1489            0 :                     this->Effectiveness = 1.0 - std::exp(-NTU);
    1490            0 :                     this->Effectiveness = min(1.0, this->Effectiveness);
    1491              :                 } else {
    1492           12 :                     this->Effectiveness = 1.0;
    1493              :                 }
    1494              :             } else {
    1495        96492 :                 this->Effectiveness = 1.0 - std::exp((std::pow(NTU, 0.22) / CapRatio) * (std::exp(-CapRatio * std::pow(NTU, 0.78)) - 1.0));
    1496        96492 :                 this->Effectiveness = min(1.0, this->Effectiveness);
    1497              :             }
    1498              : 
    1499        96504 :             break;
    1500              :         }
    1501            0 :         case FluidHXType::CrossFlowBothMixed: {
    1502            0 :             Real64 NTU = this->UA / MinCapRate;
    1503            0 :             Real64 CapRatio = MinCapRate / MaxCapRate;
    1504            0 :             Real64 ExpCheckValue1 = -CapRatio * NTU;
    1505            0 :             Real64 ExpCheckValue2 = -NTU;
    1506            0 :             if (ExpCheckValue1 < DataPrecisionGlobals::EXP_LowerLimit) {
    1507            0 :                 if (ExpCheckValue2 >= DataPrecisionGlobals::EXP_LowerLimit) {
    1508            0 :                     this->Effectiveness = 1.0 - std::exp(-NTU);
    1509            0 :                     this->Effectiveness = min(1.0, this->Effectiveness);
    1510              :                 } else {
    1511            0 :                     this->Effectiveness = 1.0;
    1512              :                 }
    1513            0 :             } else if (ExpCheckValue2 < DataPrecisionGlobals::EXP_LowerLimit) {
    1514            0 :                 this->Effectiveness = 1.0;
    1515            0 :             } else if ((std::exp(-NTU) == 1.0) || (NTU == 0.0) || (std::exp(-CapRatio * NTU) == 1.0)) { // don't div by zero
    1516              : 
    1517            0 :                 this->Effectiveness = 0.0;
    1518              :             } else {
    1519            0 :                 this->Effectiveness = 1.0 / ((1.0 / (1.0 - std::exp(-NTU))) + (CapRatio / (1.0 - std::exp(-CapRatio * NTU))) - (1.0 / NTU));
    1520            0 :                 this->Effectiveness = min(1.0, this->Effectiveness);
    1521              :             }
    1522              : 
    1523            0 :             break;
    1524              :         }
    1525            0 :         case FluidHXType::CrossFlowSupplyLoopMixedDemandLoopUnMixed:
    1526              :         case FluidHXType::CrossFlowSupplyLoopUnMixedDemandLoopMixed: {
    1527              : 
    1528              :             int CrossFlowEquation;
    1529            0 :             if (SupSideCapRate == MaxCapRate && this->HeatExchangeModelType == FluidHXType::CrossFlowSupplyLoopMixedDemandLoopUnMixed) {
    1530            0 :                 CrossFlowEquation = CmaxMixedCminUnmixed;
    1531            0 :             } else if (SupSideCapRate == MinCapRate && this->HeatExchangeModelType == FluidHXType::CrossFlowSupplyLoopMixedDemandLoopUnMixed) {
    1532            0 :                 CrossFlowEquation = CmaxUnMixedCminMixed;
    1533            0 :             } else if (DmdSideCapRate == MaxCapRate && this->HeatExchangeModelType == FluidHXType::CrossFlowSupplyLoopUnMixedDemandLoopMixed) {
    1534            0 :                 CrossFlowEquation = CmaxMixedCminUnmixed;
    1535            0 :             } else if (DmdSideCapRate == MinCapRate && this->HeatExchangeModelType == FluidHXType::CrossFlowSupplyLoopUnMixedDemandLoopMixed) {
    1536            0 :                 CrossFlowEquation = CmaxUnMixedCminMixed;
    1537              :             } else {
    1538            0 :                 CrossFlowEquation = CmaxMixedCminUnmixed;
    1539              :             }
    1540              : 
    1541            0 :             Real64 NTU = this->UA / MinCapRate;
    1542            0 :             Real64 CapRatio = MinCapRate / MaxCapRate;
    1543            0 :             if (CrossFlowEquation == CmaxMixedCminUnmixed) {
    1544            0 :                 Real64 ExpCheckValue1 = -NTU;
    1545            0 :                 if (CapRatio == 0.0) { // protect div by zero
    1546            0 :                     if (ExpCheckValue1 >= DataPrecisionGlobals::EXP_LowerLimit) {
    1547            0 :                         this->Effectiveness = 1.0 - std::exp(-NTU);
    1548            0 :                         this->Effectiveness = min(1.0, this->Effectiveness);
    1549              :                     } else {
    1550            0 :                         this->Effectiveness = 1.0;
    1551              :                     }
    1552            0 :                 } else if (ExpCheckValue1 < DataPrecisionGlobals::EXP_LowerLimit) {
    1553            0 :                     this->Effectiveness = 0.632 / CapRatio;
    1554            0 :                     this->Effectiveness = min(1.0, this->Effectiveness);
    1555              :                 } else {
    1556            0 :                     this->Effectiveness = (1.0 / CapRatio) * (1.0 - std::exp(CapRatio * std::exp(-NTU) - 1.0));
    1557            0 :                     this->Effectiveness = min(1.0, this->Effectiveness);
    1558              :                 }
    1559            0 :             } else if (CrossFlowEquation == CmaxUnMixedCminMixed) {
    1560            0 :                 Real64 ExpCheckValue1 = -CapRatio * NTU;
    1561            0 :                 if (CapRatio == 0.0) {
    1562            0 :                     if (-NTU >= DataPrecisionGlobals::EXP_LowerLimit) {
    1563            0 :                         this->Effectiveness = 1.0 - std::exp(-NTU);
    1564            0 :                         this->Effectiveness = min(1.0, this->Effectiveness);
    1565              :                     } else {
    1566            0 :                         this->Effectiveness = 1.0;
    1567              :                     }
    1568              :                 } else {
    1569            0 :                     if (ExpCheckValue1 >= DataPrecisionGlobals::EXP_LowerLimit) {
    1570            0 :                         Real64 ExpCheckValue2 = -(1.0 / CapRatio) * (1.0 - std::exp(-CapRatio * NTU));
    1571            0 :                         if (ExpCheckValue2 < DataPrecisionGlobals::EXP_LowerLimit) {
    1572            0 :                             this->Effectiveness = 1.0;
    1573              :                         } else {
    1574            0 :                             this->Effectiveness = 1.0 - std::exp(ExpCheckValue2);
    1575            0 :                             this->Effectiveness = min(1.0, this->Effectiveness);
    1576              :                         }
    1577              :                     } else {
    1578            0 :                         this->Effectiveness = 1.0;
    1579              :                     }
    1580              :                 }
    1581              :             } else {
    1582            0 :                 assert(false);
    1583              :             }
    1584              : 
    1585            0 :             break;
    1586              :         }
    1587            0 :         case FluidHXType::CounterFlow: {
    1588            0 :             Real64 NTU = this->UA / MinCapRate;
    1589            0 :             Real64 CapRatio = MinCapRate / MaxCapRate;
    1590            0 :             Real64 ExpCheckValue1 = -NTU * (1.0 - CapRatio);
    1591            0 :             if (ExpCheckValue1 > DataPrecisionGlobals::EXP_UpperLimit) {
    1592            0 :                 if (-NTU >= DataPrecisionGlobals::EXP_LowerLimit) {
    1593            0 :                     this->Effectiveness = 1.0 - std::exp(-NTU);
    1594            0 :                     this->Effectiveness = min(1.0, this->Effectiveness);
    1595              :                 } else {
    1596            0 :                     this->Effectiveness = 1.0;
    1597              :                 }
    1598            0 :             } else if (CapRatio * std::exp(-NTU * (1.0 - CapRatio)) == 1.0) {
    1599            0 :                 if (-NTU >= DataPrecisionGlobals::EXP_LowerLimit) {
    1600            0 :                     this->Effectiveness = 1.0 - std::exp(-NTU);
    1601            0 :                     this->Effectiveness = min(1.0, this->Effectiveness);
    1602              :                 } else {
    1603            0 :                     this->Effectiveness = 1.0;
    1604              :                 }
    1605              :             } else {
    1606            0 :                 this->Effectiveness = (1.0 - std::exp(-NTU * (1.0 - CapRatio))) / (1.0 - CapRatio * std::exp(-NTU * (1.0 - CapRatio)));
    1607            0 :                 this->Effectiveness = min(1.0, this->Effectiveness);
    1608              :             }
    1609              : 
    1610            0 :             break;
    1611              :         }
    1612            0 :         case FluidHXType::ParallelFlow: {
    1613            0 :             Real64 NTU = this->UA / MinCapRate;
    1614            0 :             Real64 CapRatio = MinCapRate / MaxCapRate;
    1615            0 :             Real64 ExpCheckValue1 = -NTU * (1.0 + CapRatio);
    1616            0 :             if (ExpCheckValue1 > DataPrecisionGlobals::EXP_UpperLimit) {
    1617            0 :                 if (-NTU >= DataPrecisionGlobals::EXP_LowerLimit) {
    1618            0 :                     this->Effectiveness = 1.0 - std::exp(-NTU);
    1619            0 :                     this->Effectiveness = min(1.0, this->Effectiveness);
    1620              :                 } else {
    1621            0 :                     this->Effectiveness = 1.0;
    1622              :                 }
    1623              :             } else {
    1624            0 :                 this->Effectiveness = (1.0 - std::exp(-NTU * (1.0 + CapRatio))) / (1.0 + CapRatio);
    1625            0 :                 this->Effectiveness = min(1.0, this->Effectiveness);
    1626              :             }
    1627              : 
    1628            0 :             break;
    1629              :         }
    1630            0 :         case FluidHXType::Ideal: {
    1631            0 :             this->Effectiveness = 1.0;
    1632            0 :             break;
    1633              :         }
    1634            0 :         default:
    1635            0 :             assert(false);
    1636              :             break;
    1637              :         }
    1638              : 
    1639              :     } else { // no capacity
    1640        46402 :         this->Effectiveness = 0.0;
    1641              :     }
    1642              : 
    1643       142906 :     this->HeatTransferRate = this->Effectiveness * MinCapRate * (SupSideLoopInletTemp - DmdSideLoopInletTemp); // + means supply side is cooled
    1644              : 
    1645       142906 :     if (SupSideMdot > 0.0) {
    1646       130998 :         this->SupplySideLoop.OutletTemp = SupSideLoopInletTemp - this->HeatTransferRate / (SupSideLoopInletCp * SupSideMdot);
    1647              :     } else {
    1648        11908 :         this->SupplySideLoop.OutletTemp = SupSideLoopInletTemp;
    1649              :     }
    1650              : 
    1651       142906 :     if (DmdSideMdot > 0.0) {
    1652       103486 :         this->DemandSideLoop.OutletTemp = DmdSideLoopInletTemp + this->HeatTransferRate / (DmdSideLoopInletCp * DmdSideMdot);
    1653              :     } else {
    1654        39420 :         this->DemandSideLoop.OutletTemp = DmdSideLoopInletTemp;
    1655              :     }
    1656              : 
    1657       142906 :     this->SupplySideLoop.InletTemp = SupSideLoopInletTemp;
    1658       142906 :     this->SupplySideLoop.InletMassFlowRate = SupSideMdot;
    1659       142906 :     this->DemandSideLoop.InletTemp = DmdSideLoopInletTemp;
    1660       142906 :     this->DemandSideLoop.InletMassFlowRate = DmdSideMdot;
    1661              : 
    1662       142906 :     state.dataLoopNodes->Node(this->DemandSideLoop.outletNodeNum).Temp = this->DemandSideLoop.OutletTemp;
    1663       142906 :     state.dataLoopNodes->Node(this->SupplySideLoop.outletNodeNum).Temp = this->SupplySideLoop.OutletTemp;
    1664              : 
    1665       142906 :     this->HeatTransferEnergy = this->HeatTransferRate * state.dataHVACGlobal->TimeStepSysSec;
    1666              : 
    1667       239410 :     if ((std::abs(this->HeatTransferRate) > HVAC::SmallLoad) && (this->DemandSideLoop.InletMassFlowRate > 0.0) &&
    1668        96504 :         (this->SupplySideLoop.InletMassFlowRate > 0.0)) {
    1669        96504 :         this->OperationStatus = 1.0;
    1670              :     } else {
    1671        46402 :         this->OperationStatus = 0.0;
    1672              :     }
    1673       142906 : }
    1674              : 
    1675        22972 : void HeatExchangerStruct::findDemandSideLoopFlow(EnergyPlusData &state, Real64 const TargetSupplySideLoopLeavingTemp, HXAction const HXActionMode)
    1676              : {
    1677              : 
    1678              :     // SUBROUTINE INFORMATION:
    1679              :     //       AUTHOR         B. Griffith
    1680              :     //       DATE WRITTEN   November 2012
    1681              :     //       MODIFIED       na
    1682              :     //       RE-ENGINEERED  na
    1683              : 
    1684              :     // PURPOSE OF THIS SUBROUTINE:
    1685              :     // modulate demand side flow rate to hit a target leaving temperature (within tolerance)
    1686              : 
    1687              :     // METHODOLOGY EMPLOYED:
    1688              :     // uses E+'s Regula Falsi numerical method
    1689              : 
    1690        22972 :     int constexpr MaxIte(500);   // Maximum number of iterations for solver
    1691        22972 :     Real64 constexpr Acc(1.e-3); // Accuracy of solver result
    1692              : 
    1693              :     int SolFla; // Flag of solver
    1694              : 
    1695              :     // mass flow rate of fluid entering from supply side loop
    1696        22972 :     Real64 SupSideMdot = state.dataLoopNodes->Node(this->SupplySideLoop.inletNodeNum).MassFlowRate;
    1697              :     // first see if root is bracketed
    1698              :     // min demand flow
    1699              : 
    1700              :     // mass flow rate of fluid entering from demand side loop
    1701        22972 :     Real64 DmdSideMdot = this->DemandSideLoop.MassFlowRateMin;
    1702        22972 :     this->calculate(state, SupSideMdot, DmdSideMdot);
    1703        22972 :     Real64 LeavingTempMinFlow = this->SupplySideLoop.OutletTemp;
    1704              : 
    1705              :     // full demand flow
    1706        22972 :     DmdSideMdot = this->DemandSideLoop.MassFlowRateMax;
    1707        22972 :     this->calculate(state, SupSideMdot, DmdSideMdot);
    1708        22972 :     Real64 LeavingTempFullFlow = this->SupplySideLoop.OutletTemp;
    1709              : 
    1710        22972 :     switch (HXActionMode) {
    1711              : 
    1712        11486 :     case HXAction::HeatingSupplySideLoop: {
    1713        11486 :         if ((LeavingTempFullFlow > TargetSupplySideLoopLeavingTemp) && (TargetSupplySideLoopLeavingTemp > LeavingTempMinFlow)) {
    1714        31008 :             auto f = [&state, this, TargetSupplySideLoopLeavingTemp](Real64 const DmdSideMassFlowRate) {
    1715        31008 :                 Real64 SupSideMdot = state.dataLoopNodes->Node(this->SupplySideLoop.inletNodeNum).MassFlowRate;
    1716        31008 :                 this->calculate(state, SupSideMdot, DmdSideMassFlowRate);
    1717        31008 :                 return TargetSupplySideLoopLeavingTemp - this->SupplySideLoop.OutletTemp;
    1718         5750 :             };
    1719         5750 :             General::SolveRoot(
    1720              :                 state, Acc, MaxIte, SolFla, DmdSideMdot, f, this->DemandSideLoop.MassFlowRateMin, this->DemandSideLoop.MassFlowRateMax);
    1721              : 
    1722         5750 :             if (SolFla == -1) { // no convergence
    1723            0 :                 if (!state.dataGlobal->WarmupFlag) {
    1724            0 :                     if (this->DmdSideModulatSolvNoConvergeErrorCount < 1) {
    1725            0 :                         ++this->DmdSideModulatSolvNoConvergeErrorCount;
    1726            0 :                         ShowWarningError(
    1727              :                             state,
    1728            0 :                             format("{} named {} - Iteration Limit exceeded calculating demand side loop flow rate", ComponentClassName, this->Name));
    1729            0 :                         ShowContinueError(state, format("Simulation continues with calculated demand side mass flow rate = {:.7R}", DmdSideMdot));
    1730              :                     }
    1731            0 :                     ShowRecurringWarningErrorAtEnd(state,
    1732            0 :                                                    ComponentClassName + " named " + this->Name +
    1733              :                                                        " - Iteration Limit exceeded calculating demand side loop flow rate continues.",
    1734            0 :                                                    this->DmdSideModulatSolvNoConvergeErrorIndex,
    1735              :                                                    DmdSideMdot,
    1736              :                                                    DmdSideMdot);
    1737              :                 }
    1738         5750 :             } else if (SolFla == -2) { // f(x0) and f(x1) have the same sign
    1739            0 :                 DmdSideMdot = this->DemandSideLoop.MassFlowRateMax * (LeavingTempFullFlow - TargetSupplySideLoopLeavingTemp) /
    1740            0 :                               (LeavingTempFullFlow - LeavingTempMinFlow);
    1741            0 :                 if (!state.dataGlobal->WarmupFlag) {
    1742            0 :                     if (this->DmdSideModulatSolvFailErrorCount < 1) {
    1743            0 :                         ++this->DmdSideModulatSolvFailErrorCount;
    1744            0 :                         ShowWarningError(
    1745            0 :                             state, format("{} named {} - Solver failed to calculate demand side loop flow rate", ComponentClassName, this->Name));
    1746            0 :                         ShowContinueError(state, format("Simulation continues with estimated demand side mass flow rate = {:.7R}", DmdSideMdot));
    1747              :                     }
    1748            0 :                     ShowRecurringWarningErrorAtEnd(state,
    1749            0 :                                                    ComponentClassName + " named " + this->Name +
    1750              :                                                        " - Solver failed to calculate demand side loop flow rate continues.",
    1751            0 :                                                    this->DmdSideModulatSolvFailErrorIndex,
    1752              :                                                    DmdSideMdot,
    1753              :                                                    DmdSideMdot);
    1754              :                 }
    1755              :             }
    1756         5750 :             PlantUtilities::SetComponentFlowRate(
    1757              :                 state, DmdSideMdot, this->DemandSideLoop.inletNodeNum, this->DemandSideLoop.outletNodeNum, this->DemandSideLoop);
    1758              : 
    1759        11486 :         } else if ((TargetSupplySideLoopLeavingTemp >= LeavingTempFullFlow) && (LeavingTempFullFlow > LeavingTempMinFlow)) {
    1760              :             // run at full flow
    1761         5736 :             DmdSideMdot = this->DemandSideLoop.MassFlowRateMax;
    1762         5736 :             PlantUtilities::SetComponentFlowRate(
    1763              :                 state, DmdSideMdot, this->DemandSideLoop.inletNodeNum, this->DemandSideLoop.outletNodeNum, this->DemandSideLoop);
    1764              : 
    1765            0 :         } else if (LeavingTempMinFlow >= TargetSupplySideLoopLeavingTemp) {
    1766              : 
    1767              :             // run at min flow
    1768            0 :             DmdSideMdot = this->DemandSideLoop.MassFlowRateMin;
    1769            0 :             PlantUtilities::SetComponentFlowRate(
    1770              :                 state, DmdSideMdot, this->DemandSideLoop.inletNodeNum, this->DemandSideLoop.outletNodeNum, this->DemandSideLoop);
    1771              :         }
    1772        11486 :         break;
    1773              :     }
    1774        11486 :     case HXAction::CoolingSupplySideLoop: {
    1775        11486 :         if ((LeavingTempFullFlow < TargetSupplySideLoopLeavingTemp) && (TargetSupplySideLoopLeavingTemp < LeavingTempMinFlow)) {
    1776        31008 :             auto f = [&state, this, TargetSupplySideLoopLeavingTemp](Real64 const DmdSideMassFlowRate) {
    1777        31008 :                 Real64 SupSideMdot = state.dataLoopNodes->Node(this->SupplySideLoop.inletNodeNum).MassFlowRate;
    1778        31008 :                 this->calculate(state, SupSideMdot, DmdSideMassFlowRate);
    1779        31008 :                 return TargetSupplySideLoopLeavingTemp - this->SupplySideLoop.OutletTemp;
    1780         5750 :             };
    1781         5750 :             General::SolveRoot(
    1782              :                 state, Acc, MaxIte, SolFla, DmdSideMdot, f, this->DemandSideLoop.MassFlowRateMin, this->DemandSideLoop.MassFlowRateMax);
    1783              : 
    1784         5750 :             if (SolFla == -1) { // no convergence
    1785            0 :                 if (!state.dataGlobal->WarmupFlag) {
    1786            0 :                     if (this->DmdSideModulatSolvNoConvergeErrorCount < 1) {
    1787            0 :                         ++this->DmdSideModulatSolvNoConvergeErrorCount;
    1788            0 :                         ShowWarningError(
    1789              :                             state,
    1790            0 :                             format("{} named {} - Iteration Limit exceeded calculating demand side loop flow rate", ComponentClassName, this->Name));
    1791            0 :                         ShowContinueError(state, format("Simulation continues with calculated demand side mass flow rate = {:.7R}", DmdSideMdot));
    1792              :                     }
    1793            0 :                     ShowRecurringWarningErrorAtEnd(state,
    1794            0 :                                                    ComponentClassName + " named " + this->Name +
    1795              :                                                        " - Iteration Limit exceeded calculating demand side loop flow rate continues.",
    1796            0 :                                                    this->DmdSideModulatSolvNoConvergeErrorIndex,
    1797              :                                                    DmdSideMdot,
    1798              :                                                    DmdSideMdot);
    1799              :                 }
    1800         5750 :             } else if (SolFla == -2) { // f(x0) and f(x1) have the same sign
    1801            0 :                 DmdSideMdot = this->DemandSideLoop.MassFlowRateMax * (LeavingTempFullFlow - TargetSupplySideLoopLeavingTemp) /
    1802            0 :                               (LeavingTempFullFlow - LeavingTempMinFlow);
    1803            0 :                 if (!state.dataGlobal->WarmupFlag) {
    1804            0 :                     if (this->DmdSideModulatSolvFailErrorCount < 1) {
    1805            0 :                         ++this->DmdSideModulatSolvFailErrorCount;
    1806            0 :                         ShowWarningError(
    1807            0 :                             state, format("{} named {} - Solver failed to calculate demand side loop flow rate", ComponentClassName, this->Name));
    1808            0 :                         ShowContinueError(state, format("Simulation continues with estimated demand side mass flow rate = {:.7R}", DmdSideMdot));
    1809              :                     }
    1810            0 :                     ShowRecurringWarningErrorAtEnd(state,
    1811            0 :                                                    ComponentClassName + " named " + this->Name +
    1812              :                                                        " - Solver failed to calculate demand side loop flow rate continues.",
    1813            0 :                                                    this->DmdSideModulatSolvFailErrorIndex,
    1814              :                                                    DmdSideMdot,
    1815              :                                                    DmdSideMdot);
    1816              :                 }
    1817              :             }
    1818         5750 :             PlantUtilities::SetComponentFlowRate(
    1819              :                 state, DmdSideMdot, this->DemandSideLoop.inletNodeNum, this->DemandSideLoop.outletNodeNum, this->DemandSideLoop);
    1820        11486 :         } else if ((TargetSupplySideLoopLeavingTemp <= LeavingTempFullFlow) && (LeavingTempFullFlow < LeavingTempMinFlow)) {
    1821              :             // run at full flow
    1822         5736 :             DmdSideMdot = this->DemandSideLoop.MassFlowRateMax;
    1823         5736 :             PlantUtilities::SetComponentFlowRate(
    1824              :                 state, DmdSideMdot, this->DemandSideLoop.inletNodeNum, this->DemandSideLoop.outletNodeNum, this->DemandSideLoop);
    1825            0 :         } else if (LeavingTempMinFlow <= TargetSupplySideLoopLeavingTemp) {
    1826              : 
    1827              :             // run at min flow
    1828            0 :             DmdSideMdot = this->DemandSideLoop.MassFlowRateMin;
    1829            0 :             PlantUtilities::SetComponentFlowRate(
    1830              :                 state, DmdSideMdot, this->DemandSideLoop.inletNodeNum, this->DemandSideLoop.outletNodeNum, this->DemandSideLoop);
    1831              :         }
    1832        11486 :         break;
    1833              :     }
    1834            0 :     default:
    1835            0 :         break;
    1836              :     }
    1837        22972 : }
    1838              : 
    1839        35002 : void HeatExchangerStruct::oneTimeInit(EnergyPlusData &state)
    1840              : {
    1841              : 
    1842              :     static constexpr std::string_view RoutineName("InitFluidHeatExchanger: ");
    1843              : 
    1844        35002 :     if (this->MyOneTimeFlag) {
    1845            7 :         this->setupOutputVars(state);
    1846            7 :         this->MyFlag = true;
    1847            7 :         this->MyEnvrnFlag = true;
    1848            7 :         this->MyOneTimeFlag = false;
    1849              :     }
    1850              : 
    1851        35002 :     if (this->MyFlag) {
    1852              :         // locate the main two connections to the plant loops
    1853            7 :         bool errFlag = false;
    1854           14 :         PlantUtilities::ScanPlantLoopsForObject(state,
    1855              :                                                 this->Name,
    1856              :                                                 DataPlant::PlantEquipmentType::FluidToFluidPlantHtExchg,
    1857              :                                                 this->DemandSideLoop,
    1858              :                                                 errFlag,
    1859              :                                                 _,
    1860              :                                                 _,
    1861              :                                                 _,
    1862            7 :                                                 this->DemandSideLoop.inletNodeNum,
    1863              :                                                 _);
    1864              : 
    1865            7 :         if (this->DemandSideLoop.loopSideNum != DataPlant::LoopSideLocation::Demand) { // throw error
    1866            0 :             ShowSevereError(state,
    1867            0 :                             format("{} Invalid connections for {} name = \"{}\"",
    1868              :                                    RoutineName,
    1869            0 :                                    DataPlant::PlantEquipTypeNames[static_cast<int>(DataPlant::PlantEquipmentType::FluidToFluidPlantHtExchg)],
    1870            0 :                                    this->Name));
    1871            0 :             ShowContinueError(state, "The \"Loop Demand Side\" connections are not on the Demand Side of a plant loop");
    1872            0 :             errFlag = true;
    1873              :         }
    1874              : 
    1875           14 :         PlantUtilities::ScanPlantLoopsForObject(state,
    1876              :                                                 this->Name,
    1877              :                                                 DataPlant::PlantEquipmentType::FluidToFluidPlantHtExchg,
    1878              :                                                 this->SupplySideLoop,
    1879              :                                                 errFlag,
    1880              :                                                 _,
    1881              :                                                 _,
    1882              :                                                 _,
    1883            7 :                                                 this->SupplySideLoop.inletNodeNum,
    1884              :                                                 _);
    1885              : 
    1886            7 :         if (this->SupplySideLoop.loopSideNum != DataPlant::LoopSideLocation::Supply) { // throw error
    1887            0 :             ShowSevereError(state,
    1888            0 :                             format("{} Invalid connections for {} name = \"{}\"",
    1889              :                                    RoutineName,
    1890            0 :                                    DataPlant::PlantEquipTypeNames[static_cast<int>(DataPlant::PlantEquipmentType::FluidToFluidPlantHtExchg)],
    1891            0 :                                    this->Name));
    1892            0 :             ShowContinueError(state, "The \"Loop Supply Side\" connections are not on the Supply Side of a plant loop");
    1893            0 :             errFlag = true;
    1894              :         }
    1895              : 
    1896              :         // make sure it is not the same loop on both sides.
    1897            7 :         if (this->SupplySideLoop.loopNum == this->DemandSideLoop.loopNum) { // user is being too tricky, don't allow
    1898            0 :             ShowSevereError(state,
    1899            0 :                             format("{} Invalid connections for {} name = \"{}\"",
    1900              :                                    RoutineName,
    1901            0 :                                    DataPlant::PlantEquipTypeNames[static_cast<int>(DataPlant::PlantEquipmentType::FluidToFluidPlantHtExchg)],
    1902            0 :                                    this->Name));
    1903            0 :             ShowContinueError(state, R"(The "Loop Supply Side" and "Loop Demand Side" need to be on different loops.)");
    1904            0 :             errFlag = true;
    1905              :         } else {
    1906              : 
    1907            7 :             PlantUtilities::InterConnectTwoPlantLoopSides(
    1908              :                 state, this->SupplySideLoop, this->DemandSideLoop, DataPlant::PlantEquipmentType::FluidToFluidPlantHtExchg, true);
    1909              :         }
    1910              : 
    1911              :         // find remote component if control mode is of that type.
    1912            7 :         if (this->controlMode == ControlType::CoolingSetPointOnOffWithComponentOverride) {
    1913              : 
    1914            1 :             PlantUtilities::ScanPlantLoopsForNodeNum(
    1915            1 :                 state, RoutineName, this->OtherCompSupplySideLoop.inletNodeNum, this->OtherCompSupplySideLoop, this->OtherCompSupplySideLoop.compNum);
    1916              : 
    1917            1 :             PlantUtilities::ScanPlantLoopsForNodeNum(
    1918            1 :                 state, RoutineName, this->OtherCompDemandSideLoop.inletNodeNum, this->OtherCompDemandSideLoop, this->OtherCompDemandSideLoop.compNum);
    1919              : 
    1920              :             // revise how loads served category for other controlled equipment
    1921            1 :             switch (this->OtherCompSupplySideLoop.comp->HowLoadServed) {
    1922              : 
    1923            1 :             case DataPlant::HowMet::ByNominalCap: {
    1924            1 :                 this->OtherCompSupplySideLoop.comp->HowLoadServed = DataPlant::HowMet::ByNominalCapFreeCoolCntrl;
    1925            1 :                 break;
    1926              :             }
    1927            0 :             case DataPlant::HowMet::ByNominalCapLowOutLimit: {
    1928            0 :                 this->OtherCompSupplySideLoop.comp->HowLoadServed = DataPlant::HowMet::ByNominalCapLowOutLimitFreeCoolCntrl;
    1929            0 :                 break;
    1930              :             }
    1931            0 :             default:
    1932            0 :                 break;
    1933              :             }
    1934              : 
    1935            1 :             switch (this->ControlSignalTemp) {
    1936            0 :             case CtrlTempType::WetBulbTemperature: {
    1937            0 :                 this->OtherCompSupplySideLoop.comp->FreeCoolCntrlMode = DataPlant::FreeCoolControlMode::WetBulb;
    1938            0 :                 break;
    1939              :             }
    1940            1 :             case CtrlTempType::DryBulbTemperature: {
    1941            1 :                 this->OtherCompSupplySideLoop.comp->FreeCoolCntrlMode = DataPlant::FreeCoolControlMode::DryBulb;
    1942            1 :                 break;
    1943              :             }
    1944            0 :             case CtrlTempType::LoopTemperature: {
    1945            0 :                 this->OtherCompSupplySideLoop.comp->FreeCoolCntrlMode = DataPlant::FreeCoolControlMode::Loop;
    1946            0 :                 this->OtherCompSupplySideLoop.comp->FreeCoolCntrlNodeNum = this->OtherCompDemandSideLoop.inletNodeNum;
    1947            0 :                 break;
    1948              :             }
    1949            0 :             default:
    1950            0 :                 break;
    1951              :             }
    1952              :         }
    1953            7 :         if (this->controlMode == ControlType::TrackComponentOnOff) {
    1954            0 :             if (this->OtherCompSupplySideLoop.inletNodeNum > 0) {
    1955            0 :                 PlantUtilities::ScanPlantLoopsForObject(state,
    1956              :                                                         this->ComponentUserName,
    1957              :                                                         this->ComponentType,
    1958              :                                                         this->OtherCompSupplySideLoop,
    1959              :                                                         errFlag,
    1960              :                                                         _,
    1961              :                                                         _,
    1962              :                                                         _,
    1963            0 :                                                         this->OtherCompSupplySideLoop.inletNodeNum,
    1964              :                                                         _);
    1965              :             }
    1966            0 :             if (this->OtherCompDemandSideLoop.inletNodeNum > 0) {
    1967            0 :                 PlantUtilities::ScanPlantLoopsForObject(state,
    1968              :                                                         this->ComponentUserName,
    1969              :                                                         this->ComponentType,
    1970              :                                                         this->OtherCompDemandSideLoop,
    1971              :                                                         errFlag,
    1972              :                                                         _,
    1973              :                                                         _,
    1974              :                                                         _,
    1975            0 :                                                         this->OtherCompDemandSideLoop.inletNodeNum,
    1976              :                                                         _);
    1977              :             }
    1978              :         }
    1979              : 
    1980            7 :         if (errFlag) {
    1981            0 :             ShowFatalError(state, format("{} Program terminated due to previous condition(s).", RoutineName));
    1982              :         }
    1983            7 :         this->MyFlag = false;
    1984              :     }
    1985        35002 : }
    1986              : 
    1987              : } // namespace EnergyPlus::PlantHeatExchangerFluidToFluid
        

Generated by: LCOV version 2.0-1