LCOV - code coverage report
Current view: top level - EnergyPlus - PlantHeatExchangerFluidToFluid.cc (source / functions) Hit Total Coverage
Test: lcov.output.filtered Lines: 701 1020 68.7 %
Date: 2023-01-17 19:17:23 Functions: 16 16 100.0 %

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

Generated by: LCOV version 1.13