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

Generated by: LCOV version 2.0-1