LCOV - code coverage report
Current view: top level - EnergyPlus - PlantHeatExchangerFluidToFluid.cc (source / functions) Coverage Total Hit
Test: lcov.output.filtered Lines: 43.9 % 964 423
Test Date: 2025-06-02 12:03:30 Functions: 100.0 % 14 14

            Line data    Source code
       1              : // EnergyPlus, Copyright (c) 1996-2025, The Board of Trustees of the University of Illinois,
       2              : // The Regents of the University of California, through Lawrence Berkeley National Laboratory
       3              : // (subject to receipt of any required approvals from the U.S. Dept. of Energy), Oak Ridge
       4              : // National Laboratory, managed by UT-Battelle, Alliance for Sustainable Energy, LLC, and other
       5              : // contributors. All rights reserved.
       6              : //
       7              : // NOTICE: This Software was developed under funding from the U.S. Department of Energy and the
       8              : // U.S. Government consequently retains certain rights. As such, the U.S. Government has been
       9              : // granted for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable,
      10              : // worldwide license in the Software to reproduce, distribute copies to the public, prepare
      11              : // derivative works, and perform publicly and display publicly, and to permit others to do so.
      12              : //
      13              : // Redistribution and use in source and binary forms, with or without modification, are permitted
      14              : // provided that the following conditions are met:
      15              : //
      16              : // (1) Redistributions of source code must retain the above copyright notice, this list of
      17              : //     conditions and the following disclaimer.
      18              : //
      19              : // (2) Redistributions in binary form must reproduce the above copyright notice, this list of
      20              : //     conditions and the following disclaimer in the documentation and/or other materials
      21              : //     provided with the distribution.
      22              : //
      23              : // (3) Neither the name of the University of California, Lawrence Berkeley National Laboratory,
      24              : //     the University of Illinois, U.S. Dept. of Energy nor the names of its contributors may be
      25              : //     used to endorse or promote products derived from this software without specific prior
      26              : //     written permission.
      27              : //
      28              : // (4) Use of EnergyPlus(TM) Name. If Licensee (i) distributes the software in stand-alone form
      29              : //     without changes from the version obtained under this License, or (ii) Licensee makes a
      30              : //     reference solely to the software portion of its product, Licensee must refer to the
      31              : //     software as "EnergyPlus version X" software, where "X" is the version number Licensee
      32              : //     obtained under this License and may not use a different name for the software. Except as
      33              : //     specifically required in this Section (4), Licensee shall not use in a company name, a
      34              : //     product name, in advertising, publicity, or other promotional activities any name, trade
      35              : //     name, trademark, logo, or other designation of "EnergyPlus", "E+", "e+" or confusingly
      36              : //     similar designation, without the U.S. Department of Energy's prior written consent.
      37              : //
      38              : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
      39              : // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
      40              : // AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
      41              : // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
      42              : // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
      43              : // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      44              : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
      45              : // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
      46              : // POSSIBILITY OF SUCH DAMAGE.
      47              : 
      48              : // C++ Headers
      49              : #include <cassert>
      50              : #include <cmath>
      51              : 
      52              : // ObjexxFCL Headers
      53              : #include <ObjexxFCL/Fmath.hh>
      54              : 
      55              : // EnergyPlus Headers
      56              : #include <EnergyPlus/Autosizing/Base.hh>
      57              : #include <EnergyPlus/BranchNodeConnections.hh>
      58              : #include <EnergyPlus/Data/EnergyPlusData.hh>
      59              : #include <EnergyPlus/DataBranchAirLoopPlant.hh>
      60              : #include <EnergyPlus/DataEnvironment.hh>
      61              : #include <EnergyPlus/DataHVACGlobals.hh>
      62              : #include <EnergyPlus/DataIPShortCuts.hh>
      63              : #include <EnergyPlus/DataLoopNode.hh>
      64              : #include <EnergyPlus/DataPrecisionGlobals.hh>
      65              : #include <EnergyPlus/DataSizing.hh>
      66              : #include <EnergyPlus/EMSManager.hh>
      67              : #include <EnergyPlus/FluidProperties.hh>
      68              : #include <EnergyPlus/General.hh>
      69              : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
      70              : #include <EnergyPlus/NodeInputManager.hh>
      71              : #include <EnergyPlus/OutputProcessor.hh>
      72              : #include <EnergyPlus/OutputReportPredefined.hh>
      73              : #include <EnergyPlus/Plant/DataPlant.hh>
      74              : #include <EnergyPlus/PlantHeatExchangerFluidToFluid.hh>
      75              : #include <EnergyPlus/PlantUtilities.hh>
      76              : #include <EnergyPlus/ScheduleManager.hh>
      77              : #include <EnergyPlus/UtilityRoutines.hh>
      78              : 
      79              : namespace EnergyPlus::PlantHeatExchangerFluidToFluid {
      80              : 
      81              : // Module containing the routines dealing with the HeatExchanger:FluidToFluid
      82              : 
      83              : // MODULE INFORMATION:
      84              : //       AUTHOR         B. Griffith, derived from legacy code by  Sankaranarayanan K P, and S. Rees
      85              : //       DATE WRITTEN   November 2012
      86              : //       MODIFIED       na
      87              : //       RE-ENGINEERED  na
      88              : 
      89              : // PURPOSE OF THIS MODULE:
      90              : // Simulate a generic plant heat exchanger with a variety of control options
      91              : 
      92              : std::string const ComponentClassName("HeatExchanger:FluidToFluid");
      93              : 
      94              : constexpr std::array<std::string_view, (int)FluidHXType::Num> fluidHXTypeNames = {"CrossFlowBothUnMixed",
      95              :                                                                                   "CrossFlowBothMixed",
      96              :                                                                                   "CrossFlowSupplyMixedDemandUnMixed",
      97              :                                                                                   "CrossFlowSupplyUnMixedDemandMixed",
      98              :                                                                                   "CounterFlow",
      99              :                                                                                   "ParallelFlow",
     100              :                                                                                   "Ideal"};
     101              : constexpr std::array<std::string_view, (int)FluidHXType::Num> fluidHXTypeNamesUC = {"CROSSFLOWBOTHUNMIXED",
     102              :                                                                                     "CROSSFLOWBOTHMIXED",
     103              :                                                                                     "CROSSFLOWSUPPLYMIXEDDEMANDUNMIXED",
     104              :                                                                                     "CROSSFLOWSUPPLYUNMIXEDDEMANDMIXED",
     105              :                                                                                     "COUNTERFLOW",
     106              :                                                                                     "PARALLELFLOW",
     107              :                                                                                     "IDEAL"};
     108              : 
     109              : constexpr std::array<std::string_view, (int)ControlType::Num> controlTypeNames = {"UncontrolledOn",
     110              :                                                                                   "OperationSchemeModulated",
     111              :                                                                                   "OperationSchemeOnOff",
     112              :                                                                                   "HeatingSetpointModulated",
     113              :                                                                                   "HeatingSetpointOnOff",
     114              :                                                                                   "CoolingSetpointModulated",
     115              :                                                                                   "CoolingSetpointOnOff",
     116              :                                                                                   "DualDeadbandSetpointModulated",
     117              :                                                                                   "DualDeadbandSetpointOnOff",
     118              :                                                                                   "CoolingDifferentialOnOff",
     119              :                                                                                   "CoolingSetpointOnOffWithComponentOverride",
     120              :                                                                                   "TrackComponentOnOff"};
     121              : constexpr std::array<std::string_view, (int)ControlType::Num> controlTypeNamesUC = {"UNCONTROLLEDON",
     122              :                                                                                     "OPERATIONSCHEMEMODULATED",
     123              :                                                                                     "OPERATIONSCHEMEONOFF",
     124              :                                                                                     "HEATINGSETPOINTMODULATED",
     125              :                                                                                     "HEATINGSETPOINTONOFF",
     126              :                                                                                     "COOLINGSETPOINTMODULATED",
     127              :                                                                                     "COOLINGSETPOINTONOFF",
     128              :                                                                                     "DUALDEADBANDSETPOINTMODULATED",
     129              :                                                                                     "DUALDEADBANDSETPOINTONOFF",
     130              :                                                                                     "COOLINGDIFFERENTIALONOFF",
     131              :                                                                                     "COOLINGSETPOINTONOFFWITHCOMPONENTOVERRIDE",
     132              :                                                                                     "TRACKCOMPONENTONOFF"};
     133              : 
     134              : constexpr std::array<std::string_view, (int)CtrlTempType::Num> ctrlTempTypeNames = {"WetBulbTemperature", "DryBulbTemperature", "Loop"};
     135              : constexpr std::array<std::string_view, (int)CtrlTempType::Num> ctrlTempTypeNamesUC = {"WETBULBTEMPERATURE", "DRYBULBTEMPERATURE", "LOOP"};
     136              : 
     137           12 : PlantComponent *HeatExchangerStruct::factory(EnergyPlusData &state, std::string const &objectName)
     138              : {
     139              :     // Process the input data for heat exchangers if it hasn't been done already
     140           12 :     if (state.dataPlantHXFluidToFluid->GetInput) {
     141            2 :         GetFluidHeatExchangerInput(state);
     142            2 :         state.dataPlantHXFluidToFluid->GetInput = false;
     143              :     }
     144              :     // Now look for this particular object
     145           24 :     for (auto &obj : state.dataPlantHXFluidToFluid->FluidHX) {
     146           24 :         if (obj.Name == objectName) {
     147           12 :             return &obj;
     148              :         }
     149           24 :     }
     150              :     // If we didn't find it, fatal
     151              :     ShowFatalError(state, format("LocalPlantFluidHXFactory: Error getting inputs for object named: {}", objectName)); // LCOV_EXCL_LINE
     152              :     // Shut up the compiler
     153              :     return nullptr; // LCOV_EXCL_LINE
     154              : }
     155              : 
     156           60 : void HeatExchangerStruct::onInitLoopEquip(EnergyPlusData &state, [[maybe_unused]] const PlantLocation &calledFromLocation)
     157              : {
     158           60 :     this->initialize(state);
     159           60 : }
     160              : 
     161           60 : void HeatExchangerStruct::getDesignCapacities(
     162              :     EnergyPlusData &state, const PlantLocation &calledFromLocation, Real64 &MaxLoad, Real64 &MinLoad, Real64 &OptLoad)
     163              : {
     164           60 :     if (calledFromLocation.loopNum == this->DemandSideLoop.loopNum) {
     165           30 :         MinLoad = 0.0;
     166           30 :         MaxLoad = this->DemandSideLoop.MaxLoad;
     167           30 :         OptLoad = this->DemandSideLoop.MaxLoad * 0.9;
     168           30 :     } else if (calledFromLocation.loopNum == this->SupplySideLoop.loopNum) {
     169           30 :         this->size(state); // only call sizing from the loop that sizes are based on
     170           30 :         MinLoad = 0.0;
     171           30 :         MaxLoad = this->SupplySideLoop.MaxLoad;
     172           30 :         OptLoad = this->SupplySideLoop.MaxLoad * 0.9;
     173              :     }
     174           60 : }
     175              : 
     176        34940 : void HeatExchangerStruct::simulate(EnergyPlusData &state,
     177              :                                    const PlantLocation &calledFromLocation,
     178              :                                    bool const FirstHVACIteration,
     179              :                                    Real64 &CurLoad,
     180              :                                    [[maybe_unused]] bool const RunFlag)
     181              : {
     182              : 
     183              :     // SUBROUTINE INFORMATION:
     184              :     //       AUTHOR         B. Griffith
     185              :     //       DATE WRITTEN   November 2012
     186              :     //       MODIFIED       na
     187              :     //       RE-ENGINEERED  na
     188              : 
     189              :     // PURPOSE OF THIS SUBROUTINE:
     190              :     // Main entry point and simulation manager for heat exchanger
     191              : 
     192        34940 :     this->initialize(state);
     193              : 
     194              :     // for op scheme led HXs, only call controls if called from Loop Supply Side
     195        34940 :     if ((this->controlMode == ControlType::OperationSchemeModulated) || (this->controlMode == ControlType::OperationSchemeOnOff)) {
     196            0 :         if (calledFromLocation.loopNum == this->SupplySideLoop.loopNum) {
     197            0 :             this->control(state, CurLoad, FirstHVACIteration);
     198              :         }
     199              :     } else {
     200        34940 :         this->control(state, CurLoad, FirstHVACIteration);
     201              :     }
     202              : 
     203        69880 :     this->calculate(state,
     204        34940 :                     state.dataLoopNodes->Node(this->SupplySideLoop.inletNodeNum).MassFlowRate,
     205        34940 :                     state.dataLoopNodes->Node(this->DemandSideLoop.inletNodeNum).MassFlowRate);
     206        34940 : }
     207              : 
     208            2 : void GetFluidHeatExchangerInput(EnergyPlusData &state)
     209              : {
     210              : 
     211              :     // SUBROUTINE INFORMATION:
     212              :     //       AUTHOR         B. Griffith
     213              :     //       DATE WRITTEN   November 2012
     214              :     //       MODIFIED       na
     215              :     //       RE-ENGINEERED  na
     216              : 
     217              :     // PURPOSE OF THIS SUBROUTINE:
     218              :     // get input for heat exchanger model
     219              : 
     220              :     static constexpr std::string_view RoutineName("GetFluidHeatExchangerInput: ");
     221              :     static constexpr std::string_view routineName = "GetFluidHeatExchangerInput";
     222              : 
     223            2 :     bool ErrorsFound(false);
     224              :     int NumAlphas;        // Number of elements in the alpha array
     225              :     int NumNums;          // Number of elements in the numeric array
     226              :     int IOStat;           // IO Status when calling get input subroutine
     227            2 :     int MaxNumAlphas(0);  // argument for call to GetObjectDefMaxArgs
     228            2 :     int MaxNumNumbers(0); // argument for call to GetObjectDefMaxArgs
     229            2 :     int TotalArgs(0);     // argument for call to GetObjectDefMaxArgs
     230            2 :     Array1D_string cAlphaFieldNames;
     231            2 :     Array1D_string cNumericFieldNames;
     232            2 :     Array1D_bool lNumericFieldBlanks;
     233            2 :     Array1D_bool lAlphaFieldBlanks;
     234            2 :     Array1D_string cAlphaArgs;
     235            2 :     Array1D<Real64> rNumericArgs;
     236            2 :     std::string cCurrentModuleObject;
     237              : 
     238            2 :     cCurrentModuleObject = "HeatExchanger:FluidToFluid";
     239              : 
     240            2 :     state.dataPlantHXFluidToFluid->NumberOfPlantFluidHXs = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
     241            2 :     if (state.dataPlantHXFluidToFluid->NumberOfPlantFluidHXs == 0) {
     242            0 :         return;
     243              :     }
     244              : 
     245            2 :     state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, cCurrentModuleObject, TotalArgs, NumAlphas, NumNums);
     246            2 :     MaxNumNumbers = NumNums;
     247            2 :     MaxNumAlphas = NumAlphas;
     248              : 
     249            2 :     cAlphaFieldNames.allocate(MaxNumAlphas);
     250            2 :     cAlphaArgs.allocate(MaxNumAlphas);
     251            2 :     lAlphaFieldBlanks.dimension(MaxNumAlphas, false);
     252            2 :     cNumericFieldNames.allocate(MaxNumNumbers);
     253            2 :     rNumericArgs.dimension(MaxNumNumbers, 0.0);
     254            2 :     lNumericFieldBlanks.dimension(MaxNumNumbers, false);
     255              : 
     256            2 :     if (state.dataPlantHXFluidToFluid->NumberOfPlantFluidHXs > 0) {
     257            2 :         state.dataPlantHXFluidToFluid->FluidHX.allocate(state.dataPlantHXFluidToFluid->NumberOfPlantFluidHXs);
     258            8 :         for (int CompLoop = 1; CompLoop <= state.dataPlantHXFluidToFluid->NumberOfPlantFluidHXs; ++CompLoop) {
     259            6 :             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            6 :             ErrorObjectHeader eoh{routineName, cCurrentModuleObject, cAlphaArgs(1)};
     273              : 
     274            6 :             Util::IsNameEmpty(state, cAlphaArgs(1), cCurrentModuleObject, ErrorsFound);
     275              : 
     276            6 :             state.dataPlantHXFluidToFluid->FluidHX(CompLoop).Name = cAlphaArgs(1);
     277              : 
     278            6 :             if (lAlphaFieldBlanks(2)) {
     279            0 :                 state.dataPlantHXFluidToFluid->FluidHX(CompLoop).availSched = Sched::GetScheduleAlwaysOn(state);
     280            6 :             } 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            6 :             state.dataPlantHXFluidToFluid->FluidHX(CompLoop).DemandSideLoop.inletNodeNum =
     286           12 :                 NodeInputManager::GetOnlySingleNode(state,
     287            6 :                                                     cAlphaArgs(3),
     288              :                                                     ErrorsFound,
     289              :                                                     DataLoopNode::ConnectionObjectType::HeatExchangerFluidToFluid,
     290            6 :                                                     cAlphaArgs(1),
     291              :                                                     DataLoopNode::NodeFluidType::Water,
     292              :                                                     DataLoopNode::ConnectionType::Inlet,
     293              :                                                     NodeInputManager::CompFluidStream::Primary,
     294              :                                                     DataLoopNode::ObjectIsNotParent);
     295            6 :             state.dataPlantHXFluidToFluid->FluidHX(CompLoop).DemandSideLoop.outletNodeNum =
     296           18 :                 NodeInputManager::GetOnlySingleNode(state,
     297            6 :                                                     cAlphaArgs(4),
     298              :                                                     ErrorsFound,
     299              :                                                     DataLoopNode::ConnectionObjectType::HeatExchangerFluidToFluid,
     300            6 :                                                     cAlphaArgs(1),
     301              :                                                     DataLoopNode::NodeFluidType::Water,
     302              :                                                     DataLoopNode::ConnectionType::Outlet,
     303              :                                                     NodeInputManager::CompFluidStream::Primary,
     304              :                                                     DataLoopNode::ObjectIsNotParent);
     305           12 :             BranchNodeConnections::TestCompSet(
     306            6 :                 state, cCurrentModuleObject, cAlphaArgs(1), cAlphaArgs(3), cAlphaArgs(4), "Loop Demand Side Plant Nodes");
     307            6 :             state.dataPlantHXFluidToFluid->FluidHX(CompLoop).DemandSideLoop.DesignVolumeFlowRate = rNumericArgs(1);
     308            6 :             if (state.dataPlantHXFluidToFluid->FluidHX(CompLoop).DemandSideLoop.DesignVolumeFlowRate == DataSizing::AutoSize) {
     309            0 :                 state.dataPlantHXFluidToFluid->FluidHX(CompLoop).DemandSideLoop.DesignVolumeFlowRateWasAutoSized = true;
     310              :             }
     311              : 
     312            6 :             state.dataPlantHXFluidToFluid->FluidHX(CompLoop).SupplySideLoop.inletNodeNum =
     313           12 :                 NodeInputManager::GetOnlySingleNode(state,
     314            6 :                                                     cAlphaArgs(5),
     315              :                                                     ErrorsFound,
     316              :                                                     DataLoopNode::ConnectionObjectType::HeatExchangerFluidToFluid,
     317            6 :                                                     cAlphaArgs(1),
     318              :                                                     DataLoopNode::NodeFluidType::Water,
     319              :                                                     DataLoopNode::ConnectionType::Inlet,
     320              :                                                     NodeInputManager::CompFluidStream::Secondary,
     321              :                                                     DataLoopNode::ObjectIsNotParent);
     322            6 :             state.dataPlantHXFluidToFluid->FluidHX(CompLoop).SupplySideLoop.outletNodeNum =
     323           18 :                 NodeInputManager::GetOnlySingleNode(state,
     324            6 :                                                     cAlphaArgs(6),
     325              :                                                     ErrorsFound,
     326              :                                                     DataLoopNode::ConnectionObjectType::HeatExchangerFluidToFluid,
     327            6 :                                                     cAlphaArgs(1),
     328              :                                                     DataLoopNode::NodeFluidType::Water,
     329              :                                                     DataLoopNode::ConnectionType::Outlet,
     330              :                                                     NodeInputManager::CompFluidStream::Secondary,
     331              :                                                     DataLoopNode::ObjectIsNotParent);
     332           12 :             BranchNodeConnections::TestCompSet(
     333            6 :                 state, cCurrentModuleObject, cAlphaArgs(1), cAlphaArgs(5), cAlphaArgs(6), "Loop Supply Side Plant Nodes");
     334            6 :             state.dataPlantHXFluidToFluid->FluidHX(CompLoop).SupplySideLoop.DesignVolumeFlowRate = rNumericArgs(2);
     335            6 :             if (state.dataPlantHXFluidToFluid->FluidHX(CompLoop).SupplySideLoop.DesignVolumeFlowRate == DataSizing::AutoSize) {
     336            0 :                 state.dataPlantHXFluidToFluid->FluidHX(CompLoop).SupplySideLoop.DesignVolumeFlowRateWasAutoSized = true;
     337              :             }
     338              : 
     339            6 :             if (lAlphaFieldBlanks(7)) {
     340            0 :                 ShowSevereEmptyField(state, eoh, cAlphaFieldNames(7), cAlphaArgs(7));
     341            0 :                 ErrorsFound = true;
     342            6 :             } else if ((state.dataPlantHXFluidToFluid->FluidHX(CompLoop).HeatExchangeModelType =
     343           12 :                             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            6 :             if (!lNumericFieldBlanks(3)) {
     349            6 :                 state.dataPlantHXFluidToFluid->FluidHX(CompLoop).UA = rNumericArgs(3);
     350            6 :                 if (state.dataPlantHXFluidToFluid->FluidHX(CompLoop).UA == DataSizing::AutoSize) {
     351            0 :                     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            6 :             if (lAlphaFieldBlanks(8)) {
     362            0 :                 ShowSevereEmptyField(state, eoh, cAlphaFieldNames(8));
     363            0 :                 ErrorsFound = true;
     364            6 :             } else if ((state.dataPlantHXFluidToFluid->FluidHX(CompLoop).controlMode =
     365           12 :                             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            6 :             if (!lAlphaFieldBlanks(9)) {
     371            6 :                 state.dataPlantHXFluidToFluid->FluidHX(CompLoop).SetPointNodeNum =
     372           12 :                     NodeInputManager::GetOnlySingleNode(state,
     373            6 :                                                         cAlphaArgs(9),
     374              :                                                         ErrorsFound,
     375              :                                                         DataLoopNode::ConnectionObjectType::HeatExchangerFluidToFluid,
     376            6 :                                                         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            6 :                 if ((state.dataPlantHXFluidToFluid->FluidHX(CompLoop).controlMode == ControlType::HeatingSetPointModulated) ||
     383            4 :                     (state.dataPlantHXFluidToFluid->FluidHX(CompLoop).controlMode == ControlType::HeatingSetPointOnOff) ||
     384            4 :                     (state.dataPlantHXFluidToFluid->FluidHX(CompLoop).controlMode == ControlType::CoolingSetPointModulated) ||
     385           12 :                     (state.dataPlantHXFluidToFluid->FluidHX(CompLoop).controlMode == ControlType::CoolingSetPointOnOff) ||
     386            2 :                     (state.dataPlantHXFluidToFluid->FluidHX(CompLoop).controlMode == ControlType::CoolingSetPointOnOffWithComponentOverride)) {
     387            4 :                     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            2 :                 } else if ((state.dataPlantHXFluidToFluid->FluidHX(CompLoop).controlMode == ControlType::DualDeadBandSetPointModulated) ||
     410            0 :                            (state.dataPlantHXFluidToFluid->FluidHX(CompLoop).controlMode == ControlType::DualDeadBandSetPointOnOff)) {
     411            2 :                     if ((state.dataLoopNodes->Node(state.dataPlantHXFluidToFluid->FluidHX(CompLoop).SetPointNodeNum).TempSetPointHi ==
     412            4 :                          DataLoopNode::SensedNodeFlagValue) ||
     413            2 :                         (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            0 :                 if ((state.dataPlantHXFluidToFluid->FluidHX(CompLoop).controlMode == ControlType::HeatingSetPointModulated) ||
     444            0 :                     (state.dataPlantHXFluidToFluid->FluidHX(CompLoop).controlMode == ControlType::HeatingSetPointOnOff) ||
     445            0 :                     (state.dataPlantHXFluidToFluid->FluidHX(CompLoop).controlMode == ControlType::CoolingSetPointModulated) ||
     446            0 :                     (state.dataPlantHXFluidToFluid->FluidHX(CompLoop).controlMode == ControlType::CoolingSetPointOnOff) ||
     447            0 :                     (state.dataPlantHXFluidToFluid->FluidHX(CompLoop).controlMode == ControlType::DualDeadBandSetPointModulated) ||
     448            0 :                     (state.dataPlantHXFluidToFluid->FluidHX(CompLoop).controlMode == ControlType::DualDeadBandSetPointOnOff) ||
     449            0 :                     (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            6 :             if (!lNumericFieldBlanks(4)) {
     457            6 :                 state.dataPlantHXFluidToFluid->FluidHX(CompLoop).TempControlTol = rNumericArgs(4);
     458              :             } else {
     459            0 :                 state.dataPlantHXFluidToFluid->FluidHX(CompLoop).TempControlTol = 0.01;
     460              :             }
     461              : 
     462            6 :             std::string endUseCat = Util::makeUPPER(cAlphaArgs(10));
     463            6 :             if (endUseCat == "FREECOOLING") {
     464            0 :                 state.dataPlantHXFluidToFluid->FluidHX(CompLoop).HeatTransferMeteringEndUse = OutputProcessor::EndUseCat::FreeCooling;
     465            6 :             } else if (endUseCat == "HEATREJECTION") {
     466            0 :                 state.dataPlantHXFluidToFluid->FluidHX(CompLoop).HeatTransferMeteringEndUse = OutputProcessor::EndUseCat::HeatRejection;
     467            6 :             } else if (endUseCat == "HEATRECOVERYFORCOOLING") {
     468            0 :                 state.dataPlantHXFluidToFluid->FluidHX(CompLoop).HeatTransferMeteringEndUse = OutputProcessor::EndUseCat::HeatRecoveryForCooling;
     469            6 :             } else if (endUseCat == "HEATRECOVERYFORCOOLING") {
     470            0 :                 state.dataPlantHXFluidToFluid->FluidHX(CompLoop).HeatTransferMeteringEndUse = OutputProcessor::EndUseCat::HeatRecoveryForHeating;
     471            6 :             } else if (endUseCat == "LOOPTOLOOP") {
     472            6 :                 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            6 :             if (!lAlphaFieldBlanks(11)) {
     481            0 :                 state.dataPlantHXFluidToFluid->FluidHX(CompLoop).OtherCompSupplySideLoop.inletNodeNum =
     482            0 :                     NodeInputManager::GetOnlySingleNode(state,
     483            0 :                                                         cAlphaArgs(11),
     484              :                                                         ErrorsFound,
     485              :                                                         DataLoopNode::ConnectionObjectType::HeatExchangerFluidToFluid,
     486            0 :                                                         cAlphaArgs(1),
     487              :                                                         DataLoopNode::NodeFluidType::Water,
     488              :                                                         DataLoopNode::ConnectionType::Actuator,
     489              :                                                         NodeInputManager::CompFluidStream::Primary,
     490              :                                                         DataLoopNode::ObjectIsNotParent);
     491              :             } else {
     492            6 :                 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            6 :             if (!lAlphaFieldBlanks(12)) {
     500            0 :                 state.dataPlantHXFluidToFluid->FluidHX(CompLoop).OtherCompDemandSideLoop.inletNodeNum =
     501            0 :                     NodeInputManager::GetOnlySingleNode(state,
     502            0 :                                                         cAlphaArgs(12),
     503              :                                                         ErrorsFound,
     504              :                                                         DataLoopNode::ConnectionObjectType::HeatExchangerFluidToFluid,
     505            0 :                                                         cAlphaArgs(1),
     506              :                                                         DataLoopNode::NodeFluidType::Water,
     507              :                                                         DataLoopNode::ConnectionType::Actuator,
     508              :                                                         NodeInputManager::CompFluidStream::Primary,
     509              :                                                         DataLoopNode::ObjectIsNotParent);
     510              :             } else {
     511            6 :                 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            6 :             if (lAlphaFieldBlanks(13)) {
     519            6 :                 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            0 :             } else if ((state.dataPlantHXFluidToFluid->FluidHX(CompLoop).ControlSignalTemp =
     524            0 :                             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            6 :             if (!lNumericFieldBlanks(5)) {
     530            0 :                 state.dataPlantHXFluidToFluid->FluidHX(CompLoop).SizingFactor = rNumericArgs(5);
     531              :             } else {
     532            6 :                 state.dataPlantHXFluidToFluid->FluidHX(CompLoop).SizingFactor = 1.0;
     533              :             }
     534              : 
     535            6 :             if (!lNumericFieldBlanks(6)) {
     536            0 :                 state.dataPlantHXFluidToFluid->FluidHX(CompLoop).MinOperationTemp = rNumericArgs(6);
     537              :             } else {
     538            6 :                 state.dataPlantHXFluidToFluid->FluidHX(CompLoop).MinOperationTemp = -9999.0;
     539              :             }
     540              : 
     541            6 :             if (!lNumericFieldBlanks(7)) {
     542            0 :                 state.dataPlantHXFluidToFluid->FluidHX(CompLoop).MaxOperationTemp = rNumericArgs(7);
     543              :             } else {
     544            6 :                 state.dataPlantHXFluidToFluid->FluidHX(CompLoop).MaxOperationTemp = 9999.0;
     545              :             }
     546            6 :         }
     547              :     }
     548              : 
     549            2 :     if (ErrorsFound) {
     550            0 :         ShowFatalError(state, format("{}Errors found in processing {} input.", RoutineName, cCurrentModuleObject));
     551              :     }
     552            2 : }
     553              : 
     554            7 : void HeatExchangerStruct::setupOutputVars(EnergyPlusData &state)
     555              : {
     556           14 :     SetupOutputVariable(state,
     557              :                         "Fluid Heat Exchanger Heat Transfer Rate",
     558              :                         Constant::Units::W,
     559            7 :                         this->HeatTransferRate,
     560              :                         OutputProcessor::TimeStepType::System,
     561              :                         OutputProcessor::StoreType::Average,
     562            7 :                         this->Name);
     563              : 
     564           14 :     SetupOutputVariable(state,
     565              :                         "Fluid Heat Exchanger Heat Transfer Energy",
     566              :                         Constant::Units::J,
     567            7 :                         this->HeatTransferEnergy,
     568              :                         OutputProcessor::TimeStepType::System,
     569              :                         OutputProcessor::StoreType::Sum,
     570            7 :                         this->Name,
     571              :                         Constant::eResource::EnergyTransfer,
     572              :                         OutputProcessor::Group::Plant,
     573              :                         this->HeatTransferMeteringEndUse);
     574              : 
     575           14 :     SetupOutputVariable(state,
     576              :                         "Fluid Heat Exchanger Loop Supply Side Mass Flow Rate",
     577              :                         Constant::Units::kg_s,
     578            7 :                         this->SupplySideLoop.InletMassFlowRate,
     579              :                         OutputProcessor::TimeStepType::System,
     580              :                         OutputProcessor::StoreType::Average,
     581            7 :                         this->Name);
     582              : 
     583           14 :     SetupOutputVariable(state,
     584              :                         "Fluid Heat Exchanger Loop Supply Side Inlet Temperature",
     585              :                         Constant::Units::C,
     586            7 :                         this->SupplySideLoop.InletTemp,
     587              :                         OutputProcessor::TimeStepType::System,
     588              :                         OutputProcessor::StoreType::Average,
     589            7 :                         this->Name);
     590              : 
     591           14 :     SetupOutputVariable(state,
     592              :                         "Fluid Heat Exchanger Loop Supply Side Outlet Temperature",
     593              :                         Constant::Units::C,
     594            7 :                         this->SupplySideLoop.OutletTemp,
     595              :                         OutputProcessor::TimeStepType::System,
     596              :                         OutputProcessor::StoreType::Average,
     597            7 :                         this->Name);
     598              : 
     599           14 :     SetupOutputVariable(state,
     600              :                         "Fluid Heat Exchanger Loop Demand Side Mass Flow Rate",
     601              :                         Constant::Units::kg_s,
     602            7 :                         this->DemandSideLoop.InletMassFlowRate,
     603              :                         OutputProcessor::TimeStepType::System,
     604              :                         OutputProcessor::StoreType::Average,
     605            7 :                         this->Name);
     606              : 
     607           14 :     SetupOutputVariable(state,
     608              :                         "Fluid Heat Exchanger Loop Demand Side Inlet Temperature",
     609              :                         Constant::Units::C,
     610            7 :                         this->DemandSideLoop.InletTemp,
     611              :                         OutputProcessor::TimeStepType::System,
     612              :                         OutputProcessor::StoreType::Average,
     613            7 :                         this->Name);
     614              : 
     615           14 :     SetupOutputVariable(state,
     616              :                         "Fluid Heat Exchanger Loop Demand Side Outlet Temperature",
     617              :                         Constant::Units::C,
     618            7 :                         this->DemandSideLoop.OutletTemp,
     619              :                         OutputProcessor::TimeStepType::System,
     620              :                         OutputProcessor::StoreType::Average,
     621            7 :                         this->Name);
     622              : 
     623           14 :     SetupOutputVariable(state,
     624              :                         "Fluid Heat Exchanger Operation Status",
     625              :                         Constant::Units::None,
     626            7 :                         this->OperationStatus,
     627              :                         OutputProcessor::TimeStepType::System,
     628              :                         OutputProcessor::StoreType::Average,
     629            7 :                         this->Name);
     630              : 
     631           14 :     SetupOutputVariable(state,
     632              :                         "Fluid Heat Exchanger Effectiveness",
     633              :                         Constant::Units::None,
     634            7 :                         this->Effectiveness,
     635              :                         OutputProcessor::TimeStepType::System,
     636              :                         OutputProcessor::StoreType::Average,
     637            7 :                         this->Name);
     638            7 : }
     639              : 
     640        35002 : 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        35002 :     this->oneTimeInit(state); // plant setup
     655              : 
     656        35002 :     if (state.dataGlobal->BeginEnvrnFlag && this->MyEnvrnFlag && (state.dataPlnt->PlantFirstSizesOkayToFinalize)) {
     657              : 
     658           12 :         Real64 rho = this->DemandSideLoop.loop->glycol->getDensity(state, Constant::InitConvTemp, RoutineNameNoColon);
     659           12 :         this->DemandSideLoop.MassFlowRateMax = rho * this->DemandSideLoop.DesignVolumeFlowRate;
     660           12 :         PlantUtilities::InitComponentNodes(state,
     661              :                                            this->DemandSideLoop.MassFlowRateMin,
     662              :                                            this->DemandSideLoop.MassFlowRateMax,
     663              :                                            this->DemandSideLoop.inletNodeNum,
     664              :                                            this->DemandSideLoop.outletNodeNum);
     665              : 
     666           12 :         rho = this->SupplySideLoop.loop->glycol->getDensity(state, Constant::InitConvTemp, RoutineNameNoColon);
     667           12 :         this->SupplySideLoop.MassFlowRateMax = rho * this->SupplySideLoop.DesignVolumeFlowRate;
     668           12 :         PlantUtilities::InitComponentNodes(state,
     669              :                                            this->SupplySideLoop.MassFlowRateMin,
     670              :                                            this->SupplySideLoop.MassFlowRateMax,
     671              :                                            this->SupplySideLoop.inletNodeNum,
     672              :                                            this->SupplySideLoop.outletNodeNum);
     673           12 :         this->MyEnvrnFlag = false;
     674              :     }
     675        35002 :     if (!state.dataGlobal->BeginEnvrnFlag) {
     676        34642 :         this->MyEnvrnFlag = true;
     677              :     }
     678              : 
     679        35002 :     this->DemandSideLoop.InletTemp = state.dataLoopNodes->Node(this->DemandSideLoop.inletNodeNum).Temp;
     680        35002 :     this->SupplySideLoop.InletTemp = state.dataLoopNodes->Node(this->SupplySideLoop.inletNodeNum).Temp;
     681              : 
     682        35002 :     if (this->controlMode == ControlType::CoolingSetPointOnOffWithComponentOverride) {
     683              :         // store current value for setpoint in central plant loop data structure
     684            2 :         this->OtherCompSupplySideLoop.comp->FreeCoolCntrlMinCntrlTemp =
     685            2 :             state.dataLoopNodes->Node(this->SetPointNodeNum).TempSetPoint - this->TempControlTol; // issue #5626, include control tolerance
     686              :     }
     687        35002 : }
     688              : 
     689           30 : 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           30 :     int PltSizNumSupSide = this->SupplySideLoop.loop->PlantSizNum;
     711           30 :     int PltSizNumDmdSide = this->DemandSideLoop.loop->PlantSizNum;
     712           30 :     Real64 tmpSupSideDesignVolFlowRate = this->SupplySideLoop.DesignVolumeFlowRate;
     713           30 :     if (this->SupplySideLoop.DesignVolumeFlowRateWasAutoSized) {
     714            0 :         if (PltSizNumSupSide > 0) {
     715            0 :             if (state.dataSize->PlantSizData(PltSizNumSupSide).DesVolFlowRate >= HVAC::SmallWaterVolFlow) {
     716            0 :                 tmpSupSideDesignVolFlowRate = state.dataSize->PlantSizData(PltSizNumSupSide).DesVolFlowRate * this->SizingFactor;
     717            0 :                 if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
     718            0 :                     this->SupplySideLoop.DesignVolumeFlowRate = tmpSupSideDesignVolFlowRate;
     719              :                 }
     720              :             } else {
     721            0 :                 tmpSupSideDesignVolFlowRate = 0.0;
     722            0 :                 if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
     723            0 :                     this->SupplySideLoop.DesignVolumeFlowRate = tmpSupSideDesignVolFlowRate;
     724              :                 }
     725              :             }
     726            0 :             if (state.dataPlnt->PlantFinalSizesOkayToReport) {
     727            0 :                 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            0 :             if (state.dataPlnt->PlantFirstSizesOkayToReport) {
     734            0 :                 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           30 :     PlantUtilities::RegisterPlantCompDesignFlow(state, this->SupplySideLoop.inletNodeNum, tmpSupSideDesignVolFlowRate);
     748              : 
     749              :     // second deal with Loop Demand Side
     750           30 :     Real64 tmpDmdSideDesignVolFlowRate = this->DemandSideLoop.DesignVolumeFlowRate;
     751           30 :     if (this->DemandSideLoop.DesignVolumeFlowRateWasAutoSized) {
     752            0 :         if (tmpSupSideDesignVolFlowRate > HVAC::SmallWaterVolFlow) {
     753            0 :             tmpDmdSideDesignVolFlowRate = tmpSupSideDesignVolFlowRate;
     754            0 :             if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
     755            0 :                 this->DemandSideLoop.DesignVolumeFlowRate = tmpDmdSideDesignVolFlowRate;
     756              :             }
     757              :         } else {
     758            0 :             tmpDmdSideDesignVolFlowRate = 0.0;
     759            0 :             if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
     760            0 :                 this->DemandSideLoop.DesignVolumeFlowRate = tmpDmdSideDesignVolFlowRate;
     761              :             }
     762              :         }
     763            0 :         if (state.dataPlnt->PlantFinalSizesOkayToReport) {
     764            0 :             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            0 :         if (state.dataPlnt->PlantFirstSizesOkayToReport) {
     771            0 :             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           30 :     PlantUtilities::RegisterPlantCompDesignFlow(state, this->DemandSideLoop.inletNodeNum, tmpDmdSideDesignVolFlowRate);
     779              : 
     780              :     // size UA if needed
     781           30 :     if (this->UAWasAutoSized) {
     782              :         // get nominal delta T between two loops
     783            0 :         if (PltSizNumSupSide > 0 && PltSizNumDmdSide > 0) {
     784              : 
     785            0 :             Real64 tmpDeltaTloopToLoop(0.0);
     786              : 
     787            0 :             switch (state.dataSize->PlantSizData(PltSizNumSupSide).LoopType) {
     788              : 
     789            0 :             case DataSizing::TypeOfPlantLoop::Heating:
     790              :             case DataSizing::TypeOfPlantLoop::Steam: {
     791              :                 tmpDeltaTloopToLoop =
     792            0 :                     std::abs((state.dataSize->PlantSizData(PltSizNumSupSide).ExitTemp - state.dataSize->PlantSizData(PltSizNumSupSide).DeltaT) -
     793            0 :                              state.dataSize->PlantSizData(PltSizNumDmdSide).ExitTemp);
     794            0 :                 break;
     795              :             }
     796            0 :             case DataSizing::TypeOfPlantLoop::Cooling:
     797              :             case DataSizing::TypeOfPlantLoop::Condenser: {
     798              :                 tmpDeltaTloopToLoop =
     799            0 :                     std::abs((state.dataSize->PlantSizData(PltSizNumSupSide).ExitTemp + state.dataSize->PlantSizData(PltSizNumSupSide).DeltaT) -
     800            0 :                              state.dataSize->PlantSizData(PltSizNumDmdSide).ExitTemp);
     801            0 :                 break;
     802              :             }
     803            0 :             default:
     804            0 :                 assert(false);
     805              :                 break;
     806              :             }
     807              : 
     808            0 :             tmpDeltaTloopToLoop = max(2.0, tmpDeltaTloopToLoop);
     809            0 :             Real64 tmpDeltaTSupLoop = state.dataSize->PlantSizData(PltSizNumSupSide).DeltaT;
     810            0 :             if (tmpSupSideDesignVolFlowRate >= HVAC::SmallWaterVolFlow) {
     811              : 
     812            0 :                 Real64 Cp = this->SupplySideLoop.loop->glycol->getSpecificHeat(state, Constant::InitConvTemp, RoutineName);
     813              : 
     814            0 :                 Real64 rho = this->SupplySideLoop.loop->glycol->getDensity(state, Constant::InitConvTemp, RoutineName);
     815              : 
     816            0 :                 Real64 tmpDesCap = Cp * rho * tmpDeltaTSupLoop * tmpSupSideDesignVolFlowRate;
     817            0 :                 if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
     818            0 :                     this->UA = tmpDesCap / tmpDeltaTloopToLoop;
     819              :                 }
     820              :             } else {
     821            0 :                 if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
     822            0 :                     this->UA = 0.0;
     823              :                 }
     824              :             }
     825            0 :             if (state.dataPlnt->PlantFinalSizesOkayToReport) {
     826            0 :                 BaseSizer::reportSizerOutput(
     827              :                     state, "HeatExchanger:FluidToFluid", this->Name, "Heat Exchanger U-Factor Times Area Value [W/C]", this->UA);
     828            0 :                 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            0 :             if (state.dataPlnt->PlantFirstSizesOkayToReport) {
     835            0 :                 BaseSizer::reportSizerOutput(
     836              :                     state, "HeatExchanger:FluidToFluid", this->Name, "Initial Heat Exchanger U-Factor Times Area Value [W/C]", this->UA);
     837            0 :                 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            0 :         } 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           30 :     if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
     853              : 
     854            6 :         if (PltSizNumSupSide > 0) {
     855            0 :             switch (state.dataSize->PlantSizData(PltSizNumSupSide).LoopType) {
     856            0 :             case DataSizing::TypeOfPlantLoop::Heating:
     857              :             case DataSizing::TypeOfPlantLoop::Steam: {
     858            0 :                 state.dataLoopNodes->Node(this->SupplySideLoop.inletNodeNum).Temp =
     859            0 :                     (state.dataSize->PlantSizData(PltSizNumSupSide).ExitTemp - state.dataSize->PlantSizData(PltSizNumSupSide).DeltaT);
     860            0 :                 break;
     861              :             }
     862            0 :             case DataSizing::TypeOfPlantLoop::Cooling:
     863              :             case DataSizing::TypeOfPlantLoop::Condenser: {
     864            0 :                 state.dataLoopNodes->Node(this->SupplySideLoop.inletNodeNum).Temp =
     865            0 :                     (state.dataSize->PlantSizData(PltSizNumSupSide).ExitTemp + state.dataSize->PlantSizData(PltSizNumSupSide).DeltaT);
     866            0 :                 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            6 :             if (this->SupplySideLoop.loop->LoopDemandCalcScheme == DataPlant::LoopDemandCalcScheme::SingleSetPoint) {
     875            4 :                 state.dataLoopNodes->Node(this->SupplySideLoop.inletNodeNum).Temp =
     876            4 :                     state.dataLoopNodes->Node(this->SupplySideLoop.loop->TempSetPointNodeNum).TempSetPoint;
     877            2 :             } else if (this->SupplySideLoop.loop->LoopDemandCalcScheme == DataPlant::LoopDemandCalcScheme::DualSetPointDeadBand) {
     878            2 :                 state.dataLoopNodes->Node(this->SupplySideLoop.inletNodeNum).Temp =
     879            2 :                     (state.dataLoopNodes->Node(this->SupplySideLoop.loop->TempSetPointNodeNum).TempSetPointHi +
     880            2 :                      state.dataLoopNodes->Node(this->SupplySideLoop.loop->TempSetPointNodeNum).TempSetPointLo) /
     881              :                     2.0;
     882              :             }
     883              :         }
     884              : 
     885            6 :         if (PltSizNumDmdSide > 0) {
     886            0 :             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            6 :             if (this->DemandSideLoop.loop->LoopDemandCalcScheme == DataPlant::LoopDemandCalcScheme::SingleSetPoint) {
     890            2 :                 state.dataLoopNodes->Node(this->DemandSideLoop.inletNodeNum).Temp =
     891            2 :                     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            6 :         Real64 rho = this->SupplySideLoop.loop->glycol->getDensity(state, Constant::InitConvTemp, RoutineName);
     901            6 :         Real64 SupSideMdot = this->SupplySideLoop.DesignVolumeFlowRate * rho;
     902            6 :         rho = this->DemandSideLoop.loop->glycol->getDensity(state, Constant::InitConvTemp, RoutineName);
     903            6 :         Real64 DmdSideMdot = this->DemandSideLoop.DesignVolumeFlowRate * rho;
     904              : 
     905            6 :         this->calculate(state, SupSideMdot, DmdSideMdot);
     906            6 :         this->SupplySideLoop.MaxLoad = std::abs(this->HeatTransferRate);
     907              :     }
     908           30 :     if (state.dataPlnt->PlantFinalSizesOkayToReport) {
     909            6 :         OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchMechType, this->Name, "HeatExchanger:FluidToFluid");
     910            6 :         OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchMechNomCap, this->Name, this->SupplySideLoop.MaxLoad);
     911              :     }
     912           30 : }
     913              : 
     914        34942 : 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        34942 :     Real64 AvailSchedValue = this->availSched->getCurrentVal();
     938        34942 :     if (AvailSchedValue <= 0) {
     939            0 :         ScheduledOff = true;
     940              :     } else {
     941        34942 :         ScheduledOff = false;
     942              :     }
     943              : 
     944              :     // check if operational limits trip off unit
     945        34942 :     bool LimitTrippedOff = false;
     946        69884 :     if ((state.dataLoopNodes->Node(this->SupplySideLoop.inletNodeNum).Temp < this->MinOperationTemp) ||
     947        34942 :         (state.dataLoopNodes->Node(this->DemandSideLoop.inletNodeNum).Temp < this->MinOperationTemp)) {
     948            0 :         LimitTrippedOff = true;
     949              :     }
     950        69884 :     if ((state.dataLoopNodes->Node(this->SupplySideLoop.inletNodeNum).Temp > this->MaxOperationTemp) ||
     951        34942 :         (state.dataLoopNodes->Node(this->DemandSideLoop.inletNodeNum).Temp > this->MaxOperationTemp)) {
     952            0 :         LimitTrippedOff = true;
     953              :     }
     954              : 
     955        34942 :     if (!ScheduledOff && !LimitTrippedOff) {
     956              : 
     957        34942 :         switch (this->controlMode) {
     958              : 
     959            0 :         case ControlType::UncontrolledOn: {
     960              : 
     961              :             // make passive request for supply side loop flow
     962            0 :             mdotSupSide = this->SupplySideLoop.MassFlowRateMax;
     963            0 :             PlantUtilities::SetComponentFlowRate(
     964              :                 state, mdotSupSide, this->SupplySideLoop.inletNodeNum, this->SupplySideLoop.outletNodeNum, this->SupplySideLoop);
     965            0 :             if (mdotSupSide > DataBranchAirLoopPlant::MassFlowTolerance) {
     966              :                 // if supply side loop has massflow, request demand side flow
     967            0 :                 mdotDmdSide = this->DemandSideLoop.MassFlowRateMax;
     968              :             } else {
     969            0 :                 mdotDmdSide = 0.0;
     970              :             }
     971            0 :             PlantUtilities::SetComponentFlowRate(
     972              :                 state, mdotDmdSide, this->DemandSideLoop.inletNodeNum, this->DemandSideLoop.outletNodeNum, this->DemandSideLoop);
     973              : 
     974            0 :             break;
     975              :         }
     976            0 :         case ControlType::OperationSchemeModulated: {
     977              : 
     978            0 :             if (std::abs(MyLoad) > HVAC::SmallLoad) {
     979            0 :                 if (MyLoad < -1.0 * HVAC::SmallLoad) { // requesting cooling
     980            0 :                     Real64 DeltaTCooling = this->SupplySideLoop.InletTemp - this->DemandSideLoop.InletTemp;
     981            0 :                     if (DeltaTCooling > this->TempControlTol) { // can do cooling so turn on
     982            0 :                         mdotSupSide = this->SupplySideLoop.MassFlowRateMax;
     983            0 :                         PlantUtilities::SetComponentFlowRate(
     984              :                             state, mdotSupSide, this->SupplySideLoop.inletNodeNum, this->SupplySideLoop.outletNodeNum, this->SupplySideLoop);
     985            0 :                         if (mdotSupSide > DataBranchAirLoopPlant::MassFlowTolerance) {
     986              :                             // if supply side loop has massflow, request demand side flow
     987            0 :                             Real64 cp = this->SupplySideLoop.loop->glycol->getSpecificHeat(state, this->SupplySideLoop.InletTemp, RoutineName);
     988            0 :                             Real64 TargetLeavingTemp = this->SupplySideLoop.InletTemp - std::abs(MyLoad) / (cp * mdotSupSide);
     989              : 
     990            0 :                             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            0 :                     Real64 DeltaTHeating = this->DemandSideLoop.InletTemp - this->SupplySideLoop.InletTemp;
    1013            0 :                     if (DeltaTHeating > this->TempControlTol) { // can do heating so turn on
    1014            0 :                         mdotSupSide = this->SupplySideLoop.MassFlowRateMax;
    1015            0 :                         PlantUtilities::SetComponentFlowRate(
    1016              :                             state, mdotSupSide, this->SupplySideLoop.inletNodeNum, this->SupplySideLoop.outletNodeNum, this->SupplySideLoop);
    1017            0 :                         if (mdotSupSide > DataBranchAirLoopPlant::MassFlowTolerance) {
    1018            0 :                             Real64 cp = this->SupplySideLoop.loop->glycol->getSpecificHeat(state, this->SupplySideLoop.InletTemp, RoutineName);
    1019            0 :                             Real64 TargetLeavingTemp = this->SupplySideLoop.InletTemp + std::abs(MyLoad) / (cp * mdotSupSide);
    1020              : 
    1021            0 :                             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            0 :                 mdotSupSide = 0.0;
    1045            0 :                 PlantUtilities::SetComponentFlowRate(
    1046              :                     state, mdotSupSide, this->SupplySideLoop.inletNodeNum, this->SupplySideLoop.outletNodeNum, this->SupplySideLoop);
    1047            0 :                 mdotDmdSide = 0.0;
    1048            0 :                 PlantUtilities::SetComponentFlowRate(
    1049              :                     state, mdotDmdSide, this->DemandSideLoop.inletNodeNum, this->DemandSideLoop.outletNodeNum, this->DemandSideLoop);
    1050              :             }
    1051              : 
    1052            0 :             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        11648 :         case ControlType::HeatingSetPointModulated: {
    1126              : 
    1127        11648 :             Real64 SetPointTemp = state.dataLoopNodes->Node(this->SetPointNodeNum).TempSetPoint;
    1128        11648 :             Real64 DeltaTHeating = this->DemandSideLoop.InletTemp - this->SupplySideLoop.InletTemp;
    1129        11648 :             if ((DeltaTHeating > this->TempControlTol) && (SetPointTemp > this->SupplySideLoop.InletTemp)) {
    1130              :                 // can and want to heat
    1131         5750 :                 mdotSupSide = this->SupplySideLoop.MassFlowRateMax;
    1132         5750 :                 PlantUtilities::SetComponentFlowRate(
    1133              :                     state, mdotSupSide, this->SupplySideLoop.inletNodeNum, this->SupplySideLoop.outletNodeNum, this->SupplySideLoop);
    1134         5750 :                 if (mdotSupSide > DataBranchAirLoopPlant::MassFlowTolerance) {
    1135              : 
    1136         5750 :                     Real64 TargetLeavingTemp = SetPointTemp;
    1137         5750 :                     this->findDemandSideLoopFlow(state, TargetLeavingTemp, HXAction::HeatingSupplySideLoop);
    1138              :                 } else {
    1139            0 :                     mdotDmdSide = 0.0;
    1140            0 :                     PlantUtilities::SetComponentFlowRate(
    1141              :                         state, mdotDmdSide, this->DemandSideLoop.inletNodeNum, this->DemandSideLoop.outletNodeNum, this->DemandSideLoop);
    1142              :                 }
    1143         5750 :             } else { // not able are wanting to heat so turn off
    1144         5898 :                 mdotSupSide = 0.0;
    1145         5898 :                 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         5898 :                 if (FirstHVACIteration) {
    1150         2388 :                     mdotDmdSide = this->DemandSideLoop.MassFlowRateMax;
    1151              :                 } else {
    1152         3510 :                     mdotDmdSide = 0.0;
    1153              :                 }
    1154         5898 :                 PlantUtilities::SetComponentFlowRate(
    1155              :                     state, mdotDmdSide, this->DemandSideLoop.inletNodeNum, this->DemandSideLoop.outletNodeNum, this->DemandSideLoop);
    1156              :             }
    1157              : 
    1158        11648 :             break;
    1159              :         }
    1160            0 :         case ControlType::HeatingSetPointOnOff: {
    1161              : 
    1162            0 :             Real64 SetPointTemp = state.dataLoopNodes->Node(this->SetPointNodeNum).TempSetPoint;
    1163            0 :             Real64 DeltaTHeating = this->DemandSideLoop.InletTemp - this->SupplySideLoop.InletTemp;
    1164            0 :             if ((DeltaTHeating > this->TempControlTol) && (SetPointTemp > this->SupplySideLoop.InletTemp)) {
    1165              :                 // can and want to heat
    1166            0 :                 mdotSupSide = this->SupplySideLoop.MassFlowRateMax;
    1167            0 :                 PlantUtilities::SetComponentFlowRate(
    1168              :                     state, mdotSupSide, this->SupplySideLoop.inletNodeNum, this->SupplySideLoop.outletNodeNum, this->SupplySideLoop);
    1169            0 :                 if (mdotSupSide > DataBranchAirLoopPlant::MassFlowTolerance) {
    1170            0 :                     mdotDmdSide = this->DemandSideLoop.MassFlowRateMax;
    1171              :                 } else {
    1172            0 :                     mdotDmdSide = 0.0;
    1173              :                 }
    1174            0 :                 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            0 :                 mdotSupSide = 0.0;
    1178            0 :                 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            0 :                 if (FirstHVACIteration) {
    1183            0 :                     mdotDmdSide = this->DemandSideLoop.MassFlowRateMax;
    1184              :                 } else {
    1185            0 :                     mdotDmdSide = 0.0;
    1186              :                 }
    1187            0 :                 PlantUtilities::SetComponentFlowRate(
    1188              :                     state, mdotDmdSide, this->DemandSideLoop.inletNodeNum, this->DemandSideLoop.outletNodeNum, this->DemandSideLoop);
    1189              :             }
    1190              : 
    1191            0 :             break;
    1192              :         }
    1193        11648 :         case ControlType::CoolingSetPointModulated: {
    1194              : 
    1195        11648 :             Real64 SetPointTemp = state.dataLoopNodes->Node(this->SetPointNodeNum).TempSetPoint;
    1196        11648 :             Real64 DeltaTCooling = this->SupplySideLoop.InletTemp - this->DemandSideLoop.InletTemp;
    1197        11648 :             if ((DeltaTCooling > this->TempControlTol) && (SetPointTemp < this->SupplySideLoop.InletTemp)) {
    1198              :                 // can and want to cool
    1199         5750 :                 mdotSupSide = this->SupplySideLoop.MassFlowRateMax;
    1200         5750 :                 PlantUtilities::SetComponentFlowRate(
    1201              :                     state, mdotSupSide, this->SupplySideLoop.inletNodeNum, this->SupplySideLoop.outletNodeNum, this->SupplySideLoop);
    1202         5750 :                 if (mdotSupSide > DataBranchAirLoopPlant::MassFlowTolerance) {
    1203         5750 :                     Real64 TargetLeavingTemp = SetPointTemp;
    1204         5750 :                     this->findDemandSideLoopFlow(state, TargetLeavingTemp, HXAction::CoolingSupplySideLoop);
    1205              :                 } else {
    1206            0 :                     mdotDmdSide = 0.0;
    1207            0 :                     PlantUtilities::SetComponentFlowRate(
    1208              :                         state, mdotDmdSide, this->DemandSideLoop.inletNodeNum, this->DemandSideLoop.outletNodeNum, this->DemandSideLoop);
    1209              :                 }
    1210         5750 :             } else { // not able or are wanting to cool so turn off
    1211         5898 :                 mdotSupSide = 0.0;
    1212         5898 :                 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         5898 :                 if (FirstHVACIteration) {
    1217         2388 :                     mdotDmdSide = this->DemandSideLoop.MassFlowRateMax;
    1218              :                 } else {
    1219         3510 :                     mdotDmdSide = 0.0;
    1220              :                 }
    1221         5898 :                 PlantUtilities::SetComponentFlowRate(
    1222              :                     state, mdotDmdSide, this->DemandSideLoop.inletNodeNum, this->DemandSideLoop.outletNodeNum, this->DemandSideLoop);
    1223              :             }
    1224              : 
    1225        11648 :             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        11644 :         case ControlType::DualDeadBandSetPointModulated: {
    1261              : 
    1262        11644 :             Real64 SetPointTempLo = state.dataLoopNodes->Node(this->SetPointNodeNum).TempSetPointLo;
    1263        11644 :             Real64 SetPointTempHi = state.dataLoopNodes->Node(this->SetPointNodeNum).TempSetPointHi;
    1264        11644 :             Real64 DeltaTCooling = this->SupplySideLoop.InletTemp - this->DemandSideLoop.InletTemp;
    1265        11644 :             Real64 DeltaTHeating = this->DemandSideLoop.InletTemp - this->SupplySideLoop.InletTemp;
    1266        11644 :             if ((DeltaTCooling > this->TempControlTol) && (SetPointTempHi < this->SupplySideLoop.InletTemp)) {
    1267              : 
    1268              :                 // can and want to cool
    1269         5736 :                 mdotSupSide = this->SupplySideLoop.MassFlowRateMax;
    1270         5736 :                 PlantUtilities::SetComponentFlowRate(
    1271              :                     state, mdotSupSide, this->SupplySideLoop.inletNodeNum, this->SupplySideLoop.outletNodeNum, this->SupplySideLoop);
    1272         5736 :                 if (mdotSupSide > DataBranchAirLoopPlant::MassFlowTolerance) {
    1273         5736 :                     Real64 TargetLeavingTemp = SetPointTempHi;
    1274         5736 :                     this->findDemandSideLoopFlow(state, TargetLeavingTemp, HXAction::CoolingSupplySideLoop);
    1275              :                 } else {
    1276            0 :                     mdotDmdSide = 0.0;
    1277            0 :                     PlantUtilities::SetComponentFlowRate(
    1278              :                         state, mdotDmdSide, this->DemandSideLoop.inletNodeNum, this->DemandSideLoop.outletNodeNum, this->DemandSideLoop);
    1279              :                 }
    1280        11644 :             } else if ((DeltaTHeating > this->TempControlTol) && (SetPointTempLo > this->SupplySideLoop.InletTemp)) {
    1281              :                 // can and want to heat
    1282         5736 :                 mdotSupSide = this->SupplySideLoop.MassFlowRateMax;
    1283         5736 :                 PlantUtilities::SetComponentFlowRate(
    1284              :                     state, mdotSupSide, this->SupplySideLoop.inletNodeNum, this->SupplySideLoop.outletNodeNum, this->SupplySideLoop);
    1285         5736 :                 if (mdotSupSide > DataBranchAirLoopPlant::MassFlowTolerance) {
    1286         5736 :                     Real64 TargetLeavingTemp = SetPointTempLo;
    1287         5736 :                     this->findDemandSideLoopFlow(state, TargetLeavingTemp, HXAction::HeatingSupplySideLoop);
    1288              :                 } else {
    1289            0 :                     mdotDmdSide = 0.0;
    1290            0 :                     PlantUtilities::SetComponentFlowRate(
    1291              :                         state, mdotDmdSide, this->DemandSideLoop.inletNodeNum, this->DemandSideLoop.outletNodeNum, this->DemandSideLoop);
    1292              :                 }
    1293         5736 :             } else { // not able or don't want conditioning
    1294          172 :                 mdotSupSide = 0.0;
    1295          172 :                 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          172 :                 if (FirstHVACIteration) {
    1300          100 :                     mdotDmdSide = this->DemandSideLoop.MassFlowRateMax;
    1301              :                 } else {
    1302           72 :                     mdotDmdSide = 0.0;
    1303              :                 }
    1304          172 :                 PlantUtilities::SetComponentFlowRate(
    1305              :                     state, mdotDmdSide, this->DemandSideLoop.inletNodeNum, this->DemandSideLoop.outletNodeNum, this->DemandSideLoop);
    1306              :             }
    1307              : 
    1308        11644 :             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            2 :         case ControlType::CoolingDifferentialOnOff: {
    1358              : 
    1359            2 :             Real64 DeltaTCooling = this->SupplySideLoop.InletTemp - this->DemandSideLoop.InletTemp;
    1360            2 :             if (DeltaTCooling > this->TempControlTol) {
    1361              :                 //  want to cool
    1362            0 :                 mdotSupSide = this->SupplySideLoop.MassFlowRateMax;
    1363            0 :                 PlantUtilities::SetComponentFlowRate(
    1364              :                     state, mdotSupSide, this->SupplySideLoop.inletNodeNum, this->SupplySideLoop.outletNodeNum, this->SupplySideLoop);
    1365            0 :                 if (mdotSupSide > DataBranchAirLoopPlant::MassFlowTolerance) {
    1366            0 :                     mdotDmdSide = this->DemandSideLoop.MassFlowRateMax;
    1367              :                 } else {
    1368            0 :                     mdotDmdSide = 0.0;
    1369              :                 }
    1370            0 :                 PlantUtilities::SetComponentFlowRate(
    1371              :                     state, mdotDmdSide, this->DemandSideLoop.inletNodeNum, this->DemandSideLoop.outletNodeNum, this->DemandSideLoop);
    1372              :             } else { // not wanting to cool so turn off
    1373            2 :                 mdotSupSide = 0.0;
    1374            2 :                 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            2 :                 if (FirstHVACIteration) {
    1379            1 :                     mdotDmdSide = this->DemandSideLoop.MassFlowRateMax;
    1380              :                 } else {
    1381            1 :                     mdotDmdSide = 0.0;
    1382              :                 }
    1383            2 :                 PlantUtilities::SetComponentFlowRate(
    1384              :                     state, mdotDmdSide, this->DemandSideLoop.inletNodeNum, this->DemandSideLoop.outletNodeNum, this->DemandSideLoop);
    1385              :             }
    1386              : 
    1387            2 :             break;
    1388              :         }
    1389            0 :         case ControlType::CoolingSetPointOnOffWithComponentOverride: {
    1390              : 
    1391            0 :             Real64 ControlSignalValue(0.0);
    1392              : 
    1393            0 :             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            0 :             case CtrlTempType::LoopTemperature: {
    1403            0 :                 ControlSignalValue = state.dataLoopNodes->Node(this->OtherCompDemandSideLoop.inletNodeNum).TempLastTimestep;
    1404            0 :                 break;
    1405              :             }
    1406            0 :             default:
    1407            0 :                 assert(false);
    1408              :                 break;
    1409              :             }
    1410              : 
    1411            0 :             Real64 SetPointTemp = state.dataLoopNodes->Node(this->SetPointNodeNum).TempSetPoint;
    1412            0 :             Real64 DeltaTCooling = SetPointTemp - ControlSignalValue;
    1413              :             // obtain shut down state
    1414            0 :             bool ChillerShutDown = this->OtherCompSupplySideLoop.comp->FreeCoolCntrlShutDown;
    1415            0 :             if (ChillerShutDown && (DeltaTCooling > this->TempControlTol)) {
    1416              :                 // can and want to cool
    1417            0 :                 mdotSupSide = this->SupplySideLoop.MassFlowRateMax;
    1418            0 :                 PlantUtilities::SetComponentFlowRate(
    1419              :                     state, mdotSupSide, this->SupplySideLoop.inletNodeNum, this->SupplySideLoop.outletNodeNum, this->SupplySideLoop);
    1420            0 :                 if (mdotSupSide > DataBranchAirLoopPlant::MassFlowTolerance) {
    1421            0 :                     mdotDmdSide = this->DemandSideLoop.MassFlowRateMax;
    1422              :                 } else {
    1423            0 :                     mdotDmdSide = 0.0;
    1424              :                 }
    1425            0 :                 PlantUtilities::SetComponentFlowRate(
    1426              :                     state, mdotDmdSide, this->DemandSideLoop.inletNodeNum, this->DemandSideLoop.outletNodeNum, this->DemandSideLoop);
    1427              : 
    1428              :             } else {
    1429            0 :                 mdotSupSide = 0.0;
    1430            0 :                 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            0 :                 if (FirstHVACIteration) {
    1435            0 :                     mdotDmdSide = this->DemandSideLoop.MassFlowRateMax;
    1436              :                 } else {
    1437            0 :                     mdotDmdSide = 0.0;
    1438              :                 }
    1439            0 :                 PlantUtilities::SetComponentFlowRate(
    1440              :                     state, mdotDmdSide, this->DemandSideLoop.inletNodeNum, this->DemandSideLoop.outletNodeNum, this->DemandSideLoop);
    1441              :             }
    1442            0 :             break;
    1443              :         }
    1444            0 :         default:
    1445            0 :             break;
    1446              :         }
    1447              : 
    1448        34942 :     } 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        34942 : }
    1457              : 
    1458       142906 : 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       142906 :     int constexpr CmaxMixedCminUnmixed(40);
    1476       142906 :     int constexpr CmaxUnMixedCminMixed(41);
    1477              : 
    1478       142906 :     Real64 SupSideLoopInletTemp = state.dataLoopNodes->Node(this->SupplySideLoop.inletNodeNum).Temp;
    1479       142906 :     Real64 DmdSideLoopInletTemp = state.dataLoopNodes->Node(this->DemandSideLoop.inletNodeNum).Temp;
    1480              : 
    1481              :     // specific heat of fluid entering from supply side loop at inlet temp
    1482       142906 :     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       142906 :     Real64 DmdSideLoopInletCp = this->DemandSideLoop.loop->glycol->getSpecificHeat(state, DmdSideLoopInletTemp, RoutineName);
    1486              : 
    1487       142906 :     Real64 SupSideCapRate = SupSideMdot * SupSideLoopInletCp;
    1488       142906 :     Real64 DmdSideCapRate = DmdSideMdot * DmdSideLoopInletCp;
    1489       142906 :     Real64 MinCapRate = min(SupSideCapRate, DmdSideCapRate);
    1490       142906 :     Real64 MaxCapRate = max(SupSideCapRate, DmdSideCapRate);
    1491              : 
    1492       142906 :     if (MinCapRate > 0.0) {
    1493              : 
    1494        96504 :         switch (this->HeatExchangeModelType) {
    1495              : 
    1496        96504 :         case FluidHXType::CrossFlowBothUnMixed: {
    1497        96504 :             Real64 NTU = this->UA / MinCapRate;
    1498        96504 :             Real64 CapRatio = MinCapRate / MaxCapRate;
    1499        96504 :             Real64 ExpCheckValue1 = std::pow(NTU, 0.22) / CapRatio;
    1500        96504 :             Real64 ExpCheckValue2 = -CapRatio * std::pow(NTU, 0.78);
    1501        96504 :             if ((ExpCheckValue1 > DataPrecisionGlobals::EXP_UpperLimit) || (ExpCheckValue2 > DataPrecisionGlobals::EXP_UpperLimit)) {
    1502           12 :                 if (-NTU >= DataPrecisionGlobals::EXP_LowerLimit) {
    1503            0 :                     this->Effectiveness = 1.0 - std::exp(-NTU);
    1504            0 :                     this->Effectiveness = min(1.0, this->Effectiveness);
    1505              :                 } else {
    1506           12 :                     this->Effectiveness = 1.0;
    1507              :                 }
    1508              :             } else {
    1509        96492 :                 this->Effectiveness = 1.0 - std::exp((std::pow(NTU, 0.22) / CapRatio) * (std::exp(-CapRatio * std::pow(NTU, 0.78)) - 1.0));
    1510        96492 :                 this->Effectiveness = min(1.0, this->Effectiveness);
    1511              :             }
    1512              : 
    1513        96504 :             break;
    1514              :         }
    1515            0 :         case FluidHXType::CrossFlowBothMixed: {
    1516            0 :             Real64 NTU = this->UA / MinCapRate;
    1517            0 :             Real64 CapRatio = MinCapRate / MaxCapRate;
    1518            0 :             Real64 ExpCheckValue1 = -CapRatio * NTU;
    1519            0 :             Real64 ExpCheckValue2 = -NTU;
    1520            0 :             if (ExpCheckValue1 < DataPrecisionGlobals::EXP_LowerLimit) {
    1521            0 :                 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            0 :                     this->Effectiveness = 1.0;
    1526              :                 }
    1527            0 :             } else if (ExpCheckValue2 < DataPrecisionGlobals::EXP_LowerLimit) {
    1528            0 :                 this->Effectiveness = 1.0;
    1529            0 :             } 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            0 :                 this->Effectiveness = 1.0 / ((1.0 / (1.0 - std::exp(-NTU))) + (CapRatio / (1.0 - std::exp(-CapRatio * NTU))) - (1.0 / NTU));
    1534            0 :                 this->Effectiveness = min(1.0, this->Effectiveness);
    1535              :             }
    1536              : 
    1537            0 :             break;
    1538              :         }
    1539            0 :         case FluidHXType::CrossFlowSupplyLoopMixedDemandLoopUnMixed:
    1540              :         case FluidHXType::CrossFlowSupplyLoopUnMixedDemandLoopMixed: {
    1541              : 
    1542              :             int CrossFlowEquation;
    1543            0 :             if (SupSideCapRate == MaxCapRate && this->HeatExchangeModelType == FluidHXType::CrossFlowSupplyLoopMixedDemandLoopUnMixed) {
    1544            0 :                 CrossFlowEquation = CmaxMixedCminUnmixed;
    1545            0 :             } else if (SupSideCapRate == MinCapRate && this->HeatExchangeModelType == FluidHXType::CrossFlowSupplyLoopMixedDemandLoopUnMixed) {
    1546            0 :                 CrossFlowEquation = CmaxUnMixedCminMixed;
    1547            0 :             } else if (DmdSideCapRate == MaxCapRate && this->HeatExchangeModelType == FluidHXType::CrossFlowSupplyLoopUnMixedDemandLoopMixed) {
    1548            0 :                 CrossFlowEquation = CmaxMixedCminUnmixed;
    1549            0 :             } else if (DmdSideCapRate == MinCapRate && this->HeatExchangeModelType == FluidHXType::CrossFlowSupplyLoopUnMixedDemandLoopMixed) {
    1550            0 :                 CrossFlowEquation = CmaxUnMixedCminMixed;
    1551              :             } else {
    1552            0 :                 CrossFlowEquation = CmaxMixedCminUnmixed;
    1553              :             }
    1554              : 
    1555            0 :             Real64 NTU = this->UA / MinCapRate;
    1556            0 :             Real64 CapRatio = MinCapRate / MaxCapRate;
    1557            0 :             if (CrossFlowEquation == CmaxMixedCminUnmixed) {
    1558            0 :                 Real64 ExpCheckValue1 = -NTU;
    1559            0 :                 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            0 :                 } else if (ExpCheckValue1 < DataPrecisionGlobals::EXP_LowerLimit) {
    1567            0 :                     this->Effectiveness = 0.632 / CapRatio;
    1568            0 :                     this->Effectiveness = min(1.0, this->Effectiveness);
    1569              :                 } else {
    1570            0 :                     this->Effectiveness = (1.0 / CapRatio) * (1.0 - std::exp(CapRatio * std::exp(-NTU) - 1.0));
    1571            0 :                     this->Effectiveness = min(1.0, this->Effectiveness);
    1572              :                 }
    1573            0 :             } else if (CrossFlowEquation == CmaxUnMixedCminMixed) {
    1574            0 :                 Real64 ExpCheckValue1 = -CapRatio * NTU;
    1575            0 :                 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            0 :                     if (ExpCheckValue1 >= DataPrecisionGlobals::EXP_LowerLimit) {
    1584            0 :                         Real64 ExpCheckValue2 = -(1.0 / CapRatio) * (1.0 - std::exp(-CapRatio * NTU));
    1585            0 :                         if (ExpCheckValue2 < DataPrecisionGlobals::EXP_LowerLimit) {
    1586            0 :                             this->Effectiveness = 1.0;
    1587              :                         } else {
    1588            0 :                             this->Effectiveness = 1.0 - std::exp(ExpCheckValue2);
    1589            0 :                             this->Effectiveness = min(1.0, this->Effectiveness);
    1590              :                         }
    1591              :                     } else {
    1592            0 :                         this->Effectiveness = 1.0;
    1593              :                     }
    1594              :                 }
    1595              :             } else {
    1596            0 :                 assert(false);
    1597              :             }
    1598              : 
    1599            0 :             break;
    1600              :         }
    1601            0 :         case FluidHXType::CounterFlow: {
    1602            0 :             Real64 NTU = this->UA / MinCapRate;
    1603            0 :             Real64 CapRatio = MinCapRate / MaxCapRate;
    1604            0 :             Real64 ExpCheckValue1 = -NTU * (1.0 - CapRatio);
    1605            0 :             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            0 :             } else if (CapRatio * std::exp(-NTU * (1.0 - CapRatio)) == 1.0) {
    1613            0 :                 if (-NTU >= DataPrecisionGlobals::EXP_LowerLimit) {
    1614            0 :                     this->Effectiveness = 1.0 - std::exp(-NTU);
    1615            0 :                     this->Effectiveness = min(1.0, this->Effectiveness);
    1616              :                 } else {
    1617            0 :                     this->Effectiveness = 1.0;
    1618              :                 }
    1619              :             } else {
    1620            0 :                 this->Effectiveness = (1.0 - std::exp(-NTU * (1.0 - CapRatio))) / (1.0 - CapRatio * std::exp(-NTU * (1.0 - CapRatio)));
    1621            0 :                 this->Effectiveness = min(1.0, this->Effectiveness);
    1622              :             }
    1623              : 
    1624            0 :             break;
    1625              :         }
    1626            0 :         case FluidHXType::ParallelFlow: {
    1627            0 :             Real64 NTU = this->UA / MinCapRate;
    1628            0 :             Real64 CapRatio = MinCapRate / MaxCapRate;
    1629            0 :             Real64 ExpCheckValue1 = -NTU * (1.0 + CapRatio);
    1630            0 :             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            0 :                 this->Effectiveness = (1.0 - std::exp(-NTU * (1.0 + CapRatio))) / (1.0 + CapRatio);
    1639            0 :                 this->Effectiveness = min(1.0, this->Effectiveness);
    1640              :             }
    1641              : 
    1642            0 :             break;
    1643              :         }
    1644            0 :         case FluidHXType::Ideal: {
    1645            0 :             this->Effectiveness = 1.0;
    1646            0 :             break;
    1647              :         }
    1648            0 :         default:
    1649            0 :             assert(false);
    1650              :             break;
    1651              :         }
    1652              : 
    1653              :     } else { // no capacity
    1654        46402 :         this->Effectiveness = 0.0;
    1655              :     }
    1656              : 
    1657       142906 :     this->HeatTransferRate = this->Effectiveness * MinCapRate * (SupSideLoopInletTemp - DmdSideLoopInletTemp); // + means supply side is cooled
    1658              : 
    1659       142906 :     if (SupSideMdot > 0.0) {
    1660       130998 :         this->SupplySideLoop.OutletTemp = SupSideLoopInletTemp - this->HeatTransferRate / (SupSideLoopInletCp * SupSideMdot);
    1661              :     } else {
    1662        11908 :         this->SupplySideLoop.OutletTemp = SupSideLoopInletTemp;
    1663              :     }
    1664              : 
    1665       142906 :     if (DmdSideMdot > 0.0) {
    1666       103486 :         this->DemandSideLoop.OutletTemp = DmdSideLoopInletTemp + this->HeatTransferRate / (DmdSideLoopInletCp * DmdSideMdot);
    1667              :     } else {
    1668        39420 :         this->DemandSideLoop.OutletTemp = DmdSideLoopInletTemp;
    1669              :     }
    1670              : 
    1671       142906 :     this->SupplySideLoop.InletTemp = SupSideLoopInletTemp;
    1672       142906 :     this->SupplySideLoop.InletMassFlowRate = SupSideMdot;
    1673       142906 :     this->DemandSideLoop.InletTemp = DmdSideLoopInletTemp;
    1674       142906 :     this->DemandSideLoop.InletMassFlowRate = DmdSideMdot;
    1675              : 
    1676       142906 :     state.dataLoopNodes->Node(this->DemandSideLoop.outletNodeNum).Temp = this->DemandSideLoop.OutletTemp;
    1677       142906 :     state.dataLoopNodes->Node(this->SupplySideLoop.outletNodeNum).Temp = this->SupplySideLoop.OutletTemp;
    1678              : 
    1679       142906 :     this->HeatTransferEnergy = this->HeatTransferRate * state.dataHVACGlobal->TimeStepSysSec;
    1680              : 
    1681       239410 :     if ((std::abs(this->HeatTransferRate) > HVAC::SmallLoad) && (this->DemandSideLoop.InletMassFlowRate > 0.0) &&
    1682        96504 :         (this->SupplySideLoop.InletMassFlowRate > 0.0)) {
    1683        96504 :         this->OperationStatus = 1.0;
    1684              :     } else {
    1685        46402 :         this->OperationStatus = 0.0;
    1686              :     }
    1687       142906 : }
    1688              : 
    1689        22972 : 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        22972 :     int constexpr MaxIte(500);   // Maximum number of iterations for solver
    1705        22972 :     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        22972 :     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        22972 :     Real64 DmdSideMdot = this->DemandSideLoop.MassFlowRateMin;
    1716        22972 :     this->calculate(state, SupSideMdot, DmdSideMdot);
    1717        22972 :     Real64 LeavingTempMinFlow = this->SupplySideLoop.OutletTemp;
    1718              : 
    1719              :     // full demand flow
    1720        22972 :     DmdSideMdot = this->DemandSideLoop.MassFlowRateMax;
    1721        22972 :     this->calculate(state, SupSideMdot, DmdSideMdot);
    1722        22972 :     Real64 LeavingTempFullFlow = this->SupplySideLoop.OutletTemp;
    1723              : 
    1724        22972 :     switch (HXActionMode) {
    1725              : 
    1726        11486 :     case HXAction::HeatingSupplySideLoop: {
    1727        11486 :         if ((LeavingTempFullFlow > TargetSupplySideLoopLeavingTemp) && (TargetSupplySideLoopLeavingTemp > LeavingTempMinFlow)) {
    1728        31008 :             auto f = [&state, this, TargetSupplySideLoopLeavingTemp](Real64 const DmdSideMassFlowRate) {
    1729        31008 :                 Real64 SupSideMdot = state.dataLoopNodes->Node(this->SupplySideLoop.inletNodeNum).MassFlowRate;
    1730        31008 :                 this->calculate(state, SupSideMdot, DmdSideMassFlowRate);
    1731        31008 :                 return TargetSupplySideLoopLeavingTemp - this->SupplySideLoop.OutletTemp;
    1732         5750 :             };
    1733         5750 :             General::SolveRoot(
    1734              :                 state, Acc, MaxIte, SolFla, DmdSideMdot, f, this->DemandSideLoop.MassFlowRateMin, this->DemandSideLoop.MassFlowRateMax);
    1735              : 
    1736         5750 :             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         5750 :             } 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         5750 :             PlantUtilities::SetComponentFlowRate(
    1771              :                 state, DmdSideMdot, this->DemandSideLoop.inletNodeNum, this->DemandSideLoop.outletNodeNum, this->DemandSideLoop);
    1772              : 
    1773        11486 :         } else if ((TargetSupplySideLoopLeavingTemp >= LeavingTempFullFlow) && (LeavingTempFullFlow > LeavingTempMinFlow)) {
    1774              :             // run at full flow
    1775         5736 :             DmdSideMdot = this->DemandSideLoop.MassFlowRateMax;
    1776         5736 :             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        11486 :         break;
    1787              :     }
    1788        11486 :     case HXAction::CoolingSupplySideLoop: {
    1789        11486 :         if ((LeavingTempFullFlow < TargetSupplySideLoopLeavingTemp) && (TargetSupplySideLoopLeavingTemp < LeavingTempMinFlow)) {
    1790        31008 :             auto f = [&state, this, TargetSupplySideLoopLeavingTemp](Real64 const DmdSideMassFlowRate) {
    1791        31008 :                 Real64 SupSideMdot = state.dataLoopNodes->Node(this->SupplySideLoop.inletNodeNum).MassFlowRate;
    1792        31008 :                 this->calculate(state, SupSideMdot, DmdSideMassFlowRate);
    1793        31008 :                 return TargetSupplySideLoopLeavingTemp - this->SupplySideLoop.OutletTemp;
    1794         5750 :             };
    1795         5750 :             General::SolveRoot(
    1796              :                 state, Acc, MaxIte, SolFla, DmdSideMdot, f, this->DemandSideLoop.MassFlowRateMin, this->DemandSideLoop.MassFlowRateMax);
    1797              : 
    1798         5750 :             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         5750 :             } 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         5750 :             PlantUtilities::SetComponentFlowRate(
    1833              :                 state, DmdSideMdot, this->DemandSideLoop.inletNodeNum, this->DemandSideLoop.outletNodeNum, this->DemandSideLoop);
    1834        11486 :         } else if ((TargetSupplySideLoopLeavingTemp <= LeavingTempFullFlow) && (LeavingTempFullFlow < LeavingTempMinFlow)) {
    1835              :             // run at full flow
    1836         5736 :             DmdSideMdot = this->DemandSideLoop.MassFlowRateMax;
    1837         5736 :             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        11486 :         break;
    1847              :     }
    1848            0 :     default:
    1849            0 :         break;
    1850              :     }
    1851        22972 : }
    1852              : 
    1853        35002 : void HeatExchangerStruct::oneTimeInit(EnergyPlusData &state)
    1854              : {
    1855              : 
    1856              :     static constexpr std::string_view RoutineName("InitFluidHeatExchanger: ");
    1857              : 
    1858        35002 :     if (this->MyOneTimeFlag) {
    1859            7 :         this->setupOutputVars(state);
    1860            7 :         this->MyFlag = true;
    1861            7 :         this->MyEnvrnFlag = true;
    1862            7 :         this->MyOneTimeFlag = false;
    1863              :     }
    1864              : 
    1865        35002 :     if (this->MyFlag) {
    1866              :         // locate the main two connections to the plant loops
    1867            7 :         bool errFlag = false;
    1868           14 :         PlantUtilities::ScanPlantLoopsForObject(state,
    1869              :                                                 this->Name,
    1870              :                                                 DataPlant::PlantEquipmentType::FluidToFluidPlantHtExchg,
    1871              :                                                 this->DemandSideLoop,
    1872              :                                                 errFlag,
    1873              :                                                 _,
    1874              :                                                 _,
    1875              :                                                 _,
    1876            7 :                                                 this->DemandSideLoop.inletNodeNum,
    1877              :                                                 _);
    1878              : 
    1879            7 :         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           14 :         PlantUtilities::ScanPlantLoopsForObject(state,
    1890              :                                                 this->Name,
    1891              :                                                 DataPlant::PlantEquipmentType::FluidToFluidPlantHtExchg,
    1892              :                                                 this->SupplySideLoop,
    1893              :                                                 errFlag,
    1894              :                                                 _,
    1895              :                                                 _,
    1896              :                                                 _,
    1897            7 :                                                 this->SupplySideLoop.inletNodeNum,
    1898              :                                                 _);
    1899              : 
    1900            7 :         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            7 :         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            7 :             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            7 :         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            1 :             case CtrlTempType::DryBulbTemperature: {
    1955            1 :                 this->OtherCompSupplySideLoop.comp->FreeCoolCntrlMode = DataPlant::FreeCoolControlMode::DryBulb;
    1956            1 :                 break;
    1957              :             }
    1958            0 :             case CtrlTempType::LoopTemperature: {
    1959            0 :                 this->OtherCompSupplySideLoop.comp->FreeCoolCntrlMode = DataPlant::FreeCoolControlMode::Loop;
    1960            0 :                 this->OtherCompSupplySideLoop.comp->FreeCoolCntrlNodeNum = this->OtherCompDemandSideLoop.inletNodeNum;
    1961            0 :                 break;
    1962              :             }
    1963            0 :             default:
    1964            0 :                 break;
    1965              :             }
    1966              :         }
    1967            7 :         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            7 :         if (errFlag) {
    1995            0 :             ShowFatalError(state, format("{} Program terminated due to previous condition(s).", RoutineName));
    1996              :         }
    1997            7 :         this->MyFlag = false;
    1998              :     }
    1999        35002 : }
    2000              : 
    2001              : } // namespace EnergyPlus::PlantHeatExchangerFluidToFluid
        

Generated by: LCOV version 2.0-1