LCOV - code coverage report
Current view: top level - EnergyPlus - PlantHeatExchangerFluidToFluid.cc (source / functions) Hit Total Coverage
Test: lcov.output.filtered Lines: 724 1025 70.6 %
Date: 2024-08-23 23:50:59 Functions: 14 14 100.0 %

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

Generated by: LCOV version 1.14